From 9656f1476cbcba7898f16062e3b6e5be92eecb78 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Thu, 4 Aug 2016 20:54:13 +0000 Subject: [PATCH] GlobalISel: implement narrowing for G_ADD. llvm-svn: 277769 --- .../llvm/CodeGen/GlobalISel/MachineIRBuilder.h | 22 +++++++++++++++ llvm/include/llvm/Target/GenericOpcodes.td | 15 ++++++++++ llvm/include/llvm/Target/TargetOpcodes.def | 11 ++++++-- llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 17 +++++++++++ .../CodeGen/GlobalISel/MachineLegalizeHelper.cpp | 33 +++++++++++++++++++++- .../lib/Target/AArch64/AArch64MachineLegalizer.cpp | 9 +++++- .../CodeGen/AArch64/GlobalISel/legalize-add.mir | 28 ++++++++++++++++++ 7 files changed, 131 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 1178503..2d84c3e 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -131,6 +131,19 @@ public: MachineInstrBuilder buildAdd(LLT Ty, unsigned Res, unsigned Op0, unsigned Op1); + /// Build and insert \p Res, \p CarryOut = G_ADDE \p Ty \p Op0, \p Op1, + /// \p CarryIn + /// + /// G_ADDE sets \p Res to \p Op0 + \p Op1 + \p CarryIn (truncated to the bit + /// width) and sets \p CarryOut to 1 if the result overflowed in 2s-complement + /// arithmetic. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildAdde(LLT Ty, unsigned Res, unsigned CarryOut, + unsigned Op0, unsigned Op1, unsigned CarryIn); + /// Build and insert \p Res = G_ANYEXTEND \p Ty \p Op0 /// /// G_ANYEXTEND produces a register of the specified width, with bits 0 to @@ -163,6 +176,15 @@ public: /// \return The newly created instruction. MachineInstrBuilder buildBrCond(LLT Ty, unsigned Tst, MachineBasicBlock &BB); + /// Build and insert \p Res = G_CONSTANT \p Ty \p Val + /// + /// G_CONSTANT is an integer constant with the specified size and value. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildConstant(LLT Ty, unsigned Res, int64_t Val); + /// Build and insert \p Res = COPY Op /// /// Register-to-register COPY sets \p Res to \p Op. diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index aa7639c..716968d 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -59,6 +59,12 @@ def G_BITCAST : Instruction { let hasSideEffects = 0; } +def G_CONSTANT : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins unknown:$imm); + let hasSideEffects = 0; +} + //------------------------------------------------------------------------------ // Binary ops. //------------------------------------------------------------------------------ @@ -79,6 +85,14 @@ def G_SUB : Instruction { let isCommutable = 0; } +// Generic addition consuming and producing a carry flag. +def G_ADDE : Instruction { + let OutOperandList = (outs unknown:$dst, unknown:$carry_out); + let InOperandList = (ins unknown:$src1, unknown:$src2, unknown:$carry_in); + let hasSideEffects = 0; + let isCommutable = 1; +} + // Generic bitwise and. def G_AND : Instruction { let OutOperandList = (outs unknown:$dst); @@ -163,6 +177,7 @@ def G_INTRINSIC_W_SIDE_EFFECTS : Instruction { //------------------------------------------------------------------------------ // Branches. //------------------------------------------------------------------------------ + // Generic unconditional branch. def G_BR : Instruction { let OutOperandList = (outs); diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def index 01a589b..ec1dd96 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.def +++ b/llvm/include/llvm/Target/TargetOpcodes.def @@ -159,16 +159,20 @@ HANDLE_TARGET_OPCODE(PATCHABLE_RET) HANDLE_TARGET_OPCODE(G_ADD) HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_START, G_ADD) +/// Generic ADD instruction, consuming the normal operands plus a carry flag, +/// and similarly producing the result and a carry flag. +HANDLE_TARGET_OPCODE(G_ADDE) + /// Generic SUB instruction. This is an integer sub. HANDLE_TARGET_OPCODE(G_SUB) /// Generic Bitwise-AND instruction. HANDLE_TARGET_OPCODE(G_AND) -/// Generic Bitwise-OR instruction. +/// Generic bitwise or instruction. HANDLE_TARGET_OPCODE(G_OR) -/// Generic Bitwise-OR instruction. +/// Generic bitwise exclusive-or instruction. HANDLE_TARGET_OPCODE(G_XOR) /// Generic instruction to materialize the address of an alloca or other @@ -214,6 +218,9 @@ HANDLE_TARGET_OPCODE(G_ANYEXTEND) /// Generic truncation. HANDLE_TARGET_OPCODE(G_TRUNC) +/// Generic integer constant. +HANDLE_TARGET_OPCODE(G_CONSTANT) + /// Generic BRANCH instruction. This is an unconditional branch. HANDLE_TARGET_OPCODE(G_BR) diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 09a8fa6..5abc652 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -95,6 +95,11 @@ MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) { return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op); } +MachineInstrBuilder MachineIRBuilder::buildConstant(LLT Ty, unsigned Res, + int64_t Val) { + return buildInstr(TargetOpcode::G_CONSTANT, Ty).addDef(Res).addImm(Val); +} + MachineInstrBuilder MachineIRBuilder::buildBrCond(LLT Ty, unsigned Tst, MachineBasicBlock &Dest) { return buildInstr(TargetOpcode::G_BRCOND, Ty).addUse(Tst).addMBB(&Dest); @@ -119,6 +124,18 @@ MachineInstrBuilder MachineIRBuilder::buildStore(LLT VTy, LLT PTy, .addMemOperand(&MMO); } +MachineInstrBuilder MachineIRBuilder::buildAdde(LLT Ty, unsigned Res, + unsigned CarryOut, unsigned Op0, + unsigned Op1, + unsigned CarryIn) { + return buildInstr(TargetOpcode::G_ADDE, Ty) + .addDef(Res) + .addDef(CarryOut) + .addUse(Op0) + .addUse(Op1) + .addUse(CarryIn); +} + MachineInstrBuilder MachineIRBuilder::buildAnyExtend(LLT Ty, unsigned Res, unsigned Op) { return buildInstr(TargetOpcode::G_ANYEXTEND, Ty).addDef(Res).addUse(Op); diff --git a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp index 71d3206..31092a5 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp @@ -61,7 +61,38 @@ void MachineLegalizeHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, MachineLegalizeHelper::LegalizeResult MachineLegalizeHelper::narrowScalar(MachineInstr &MI, LLT NarrowTy) { - return UnableToLegalize; + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_ADD: { + // Expand in terms of carry-setting/consuming G_ADDE instructions. + unsigned NarrowSize = NarrowTy.getSizeInBits(); + int NumParts = MI.getType().getSizeInBits() / NarrowSize; + + MIRBuilder.setInstr(MI); + + SmallVector Src1Regs, Src2Regs, DstRegs; + extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); + extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); + + unsigned CarryIn = MRI.createGenericVirtualRegister(1); + MIRBuilder.buildConstant(LLT::scalar(1), CarryIn, 0); + + for (int i = 0; i < NumParts; ++i) { + unsigned DstReg = MRI.createGenericVirtualRegister(NarrowSize); + unsigned CarryOut = MRI.createGenericVirtualRegister(1); + + MIRBuilder.buildAdde(NarrowTy, DstReg, CarryOut, Src1Regs[i], Src2Regs[i], + CarryIn); + + DstRegs.push_back(DstReg); + CarryIn = CarryOut; + } + MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs); + MI.eraseFromParent(); + return Legalized; + } + } } MachineLegalizeHelper::LegalizeResult diff --git a/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp b/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp index 9414742..c547f7b 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp +++ b/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp @@ -26,20 +26,27 @@ using namespace llvm; AArch64MachineLegalizer::AArch64MachineLegalizer() { using namespace TargetOpcode; + const LLT s8 = LLT::scalar(8); + const LLT s16 = LLT::scalar(16); const LLT s32 = LLT::scalar(32); const LLT s64 = LLT::scalar(64); const LLT v2s32 = LLT::vector(2, 32); const LLT v4s32 = LLT::vector(4, 32); const LLT v2s64 = LLT::vector(2, 64); - for (auto BinOp : {G_ADD, G_SUB, G_AND, G_OR, G_XOR}) + for (auto BinOp : {G_ADD, G_SUB, G_AND, G_OR, G_XOR}) { for (auto Ty : {s32, s64, v2s32, v4s32, v2s64}) setAction(BinOp, Ty, Legal); + for (auto Ty : {s8, s16}) + setAction(BinOp, Ty, WidenScalar); + } + for (auto MemOp : {G_LOAD, G_STORE}) for (auto Ty : {s32, s64}) setAction(MemOp, Ty, Legal); + setAction(G_BR, LLT::unsized(), Legal); computeTables(); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir index 9078db5..77eb479 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir @@ -3,6 +3,10 @@ --- | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "aarch64-apple-ios" + define void @test_scalar_add_big() { + entry: + ret void + } define void @test_scalar_add_small() { entry: ret void @@ -14,6 +18,30 @@ ... --- +name: test_scalar_add_big +isSSA: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0.entry: + liveins: %x0, %x1, %x2, %x3 + ; CHECK-LABEL: name: test_scalar_add_big + ; CHECK-DAG: [[LHS_LO:%.*]](64), [[LHS_HI:%.*]](64) = G_EXTRACT s64 %0, 0, 64 + ; CHECK-DAG: [[RHS_LO:%.*]](64), [[RHS_HI:%.*]](64) = G_EXTRACT s64 %1, 0, 64 + ; CHECK-DAG: [[CARRY0:%.*]](1) = G_CONSTANT s1 0 + ; CHECK: [[RES_LO:%.*]](64), [[CARRY:%.*]](1) = G_ADDE s64 [[LHS_LO]], [[RHS_LO]], [[CARRY0]] + ; CHECK: [[RES_HI:%.*]](64), {{%.*}}(1) = G_ADDE s64 [[LHS_HI]], [[RHS_HI]], [[CARRY]] + ; CHECK: %2(128) = G_SEQUENCE s128 [[RES_LO]], [[RES_HI]] + + %0(128) = G_SEQUENCE s128 %x0, %x1 + %1(128) = G_SEQUENCE s128 %x2, %x3 + %2(128) = G_ADD s128 %0, %1 + %x0, %x1 = G_EXTRACT s64 %2, 0, 64 +... + +--- name: test_scalar_add_small isSSA: true registers: -- 2.7.4