diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h | 3 | ||||
-rw-r--r-- | llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h | 25 | ||||
-rw-r--r-- | llvm/include/llvm/Target/GenericOpcodes.td | 15 | ||||
-rw-r--r-- | llvm/include/llvm/Target/TargetOpcodes.def | 4 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Legalizer.cpp | 31 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 24 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 40 | ||||
-rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir | 20 | ||||
-rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir | 4 |
10 files changed, 139 insertions, 31 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h b/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h index 8284ab6dac6..bed7230cc01 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h @@ -58,6 +58,9 @@ public: bool combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII); + bool combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, + const TargetInstrInfo &TII); + bool runOnMachineFunction(MachineFunction &MF) override; }; } // End namespace llvm. diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index a3fa6c263b1..d7fe1c4f63e 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -468,6 +468,31 @@ public: ArrayRef<unsigned> Ops, ArrayRef<uint64_t> Indices); + /// Build and insert \p Res<def> = G_MERGE_VALUES \p Op0, ... + /// + /// G_MERGE_VALUES combines the input elements contiguously into a larger + /// register. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre The entire register \p Res (and no more) must be covered by the input + /// registers. + /// \pre The type of all \p Ops registers must be identical. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildMerge(unsigned Res, ArrayRef<unsigned> Ops); + + /// Build and insert \p Res0<def>, ... = G_UNMERGE_VALUES \p Op + /// + /// G_UNMERGE_VALUES splits contiguous bits of the input into multiple + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre The entire register \p Res (and no more) must be covered by the input + /// registers. + /// \pre The type of all \p Res registers must be identical. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildUnmerge(ArrayRef<unsigned> Res, unsigned Op); + void addUsesWithIndices(MachineInstrBuilder MIB) {} template <typename... ArgTys> diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 880fbc46374..fecdd72d6a5 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -434,6 +434,15 @@ def G_EXTRACT : Instruction { let hasSideEffects = 0; } +// Extract multiple registers specified size, starting from blocks given by +// indexes. This will almost certainly be mapped to sub-register COPYs after +// register banks have been selected. +def G_UNMERGE_VALUES : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins variable_ops); + let hasSideEffects = 0; +} + // Insert a sequence of smaller registers into a larger one at the specified // indices (interleaved with the values in the operand list "op0, bit0, op1, // bit1, ...")). @@ -452,6 +461,12 @@ def G_SEQUENCE : Instruction { let hasSideEffects = 0; } +def G_MERGE_VALUES : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins variable_ops); + let hasSideEffects = 0; +} + // Intrinsic without side effects. def G_INTRINSIC : Instruction { let OutOperandList = (outs); diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def index 2d1ff50ca10..58e6157778c 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.def +++ b/llvm/include/llvm/Target/TargetOpcodes.def @@ -229,6 +229,8 @@ HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE) /// (typically a sub-register COPY after instruction selection). HANDLE_TARGET_OPCODE(G_EXTRACT) +HANDLE_TARGET_OPCODE(G_UNMERGE_VALUES) + /// Generic instruction to insert blocks of bits from the registers given into /// the source. HANDLE_TARGET_OPCODE(G_INSERT) @@ -237,6 +239,8 @@ HANDLE_TARGET_OPCODE(G_INSERT) /// larger register. HANDLE_TARGET_OPCODE(G_SEQUENCE) +HANDLE_TARGET_OPCODE(G_MERGE_VALUES) + /// Generic pointer to int conversion. HANDLE_TARGET_OPCODE(G_PTRTOINT) diff --git a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp index 8f3d341720b..a849346ce99 100644 --- a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -113,6 +113,36 @@ bool Legalizer::combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI, return Changed; } +bool Legalizer::combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, + const TargetInstrInfo &TII) { + if (MI.getOpcode() != TargetOpcode::G_UNMERGE_VALUES) + return false; + + unsigned NumDefs = MI.getNumOperands() - 1; + unsigned SrcReg = MI.getOperand(NumDefs).getReg(); + MachineInstr &MergeI = *MRI.def_instr_begin(SrcReg); + if (MergeI.getOpcode() != TargetOpcode::G_MERGE_VALUES) + return false; + + if (MergeI.getNumOperands() - 1 != NumDefs) + return false; + + // FIXME: is a COPY appropriate if the types mismatch? We know both registers + // are allocatable by now. + if (MRI.getType(MI.getOperand(0).getReg()) != + MRI.getType(MergeI.getOperand(1).getReg())) + return false; + + for (unsigned Idx = 0; Idx < NumDefs; ++Idx) + MRI.replaceRegWith(MI.getOperand(Idx).getReg(), + MergeI.getOperand(Idx + 1).getReg()); + + MI.eraseFromParent(); + if (MRI.use_empty(MergeI.getOperand(0).getReg())) + MergeI.eraseFromParent(); + return true; +} + bool Legalizer::runOnMachineFunction(MachineFunction &MF) { // If the ISel pipeline failed, do not bother running that pass. if (MF.getProperties().hasProperty( @@ -166,6 +196,7 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) { NextMI = std::next(MI); Changed |= combineExtracts(*MI, MRI, TII); + Changed |= combineMerges(*MI, MRI, TII); } } diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 6bb64e068ec..2d28a42c797 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -86,13 +86,9 @@ LegalizerHelper::legalizeInstr(MachineInstr &MI, void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, SmallVectorImpl<unsigned> &VRegs) { - unsigned Size = Ty.getSizeInBits(); - SmallVector<uint64_t, 4> Indexes; - for (int i = 0; i < NumParts; ++i) { + for (int i = 0; i < NumParts; ++i) VRegs.push_back(MRI.createGenericVirtualRegister(Ty)); - Indexes.push_back(i * Size); - } - MIRBuilder.buildExtract(VRegs, Indexes, Reg); + MIRBuilder.buildUnmerge(VRegs, Reg); } static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { @@ -156,12 +152,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return UnableToLegalize; case TargetOpcode::G_ADD: { // Expand in terms of carry-setting/consuming G_ADDE instructions. - unsigned NarrowSize = NarrowTy.getSizeInBits(); int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowTy.getSizeInBits(); SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; - SmallVector<uint64_t, 2> Indexes; extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); @@ -176,11 +170,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, Src2Regs[i], CarryIn); DstRegs.push_back(DstReg); - Indexes.push_back(i * NarrowSize); CarryIn = CarryOut; } unsigned DstReg = MI.getOperand(0).getReg(); - MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); + MIRBuilder.buildMerge(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; } @@ -200,7 +193,6 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, for (int i = 0; i < NumParts; ++i) { unsigned DstStart = i * NarrowSize; unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); - Indexes.push_back(DstStart); findInsertionsForRange(DstStart, DstStart + NarrowSize, CurOp, EndOp, MI); @@ -239,7 +231,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, } assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered"); - MIRBuilder.buildSequence(MI.getOperand(0).getReg(), DstRegs, Indexes); + MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs); MI.eraseFromParent(); return Legalized; } @@ -251,7 +243,6 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize); SmallVector<unsigned, 2> DstRegs; - SmallVector<uint64_t, 2> Indexes; for (int i = 0; i < NumParts; ++i) { unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); unsigned SrcReg = MRI.createGenericVirtualRegister(NarrowPtrTy); @@ -264,10 +255,9 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin()); DstRegs.push_back(DstReg); - Indexes.push_back(i * NarrowSize); } unsigned DstReg = MI.getOperand(0).getReg(); - MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); + MIRBuilder.buildMerge(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; } @@ -578,7 +568,6 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, MIRBuilder.setInstr(MI); SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; - SmallVector<uint64_t, 2> Indexes; extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); @@ -586,10 +575,9 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]); DstRegs.push_back(DstReg); - Indexes.push_back(i * NarrowSize); } - MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); + MIRBuilder.buildMerge(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; } diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp index 75c54c23872..d9e4f848a74 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -80,7 +80,9 @@ LegalizerInfo::getAction(const InstrAspect &Aspect) const { // FIXME: the long-term plan calls for expansion in terms of load/store (if // they're not legal). if (Aspect.Opcode == TargetOpcode::G_SEQUENCE || - Aspect.Opcode == TargetOpcode::G_EXTRACT) + Aspect.Opcode == TargetOpcode::G_EXTRACT || + Aspect.Opcode == TargetOpcode::G_MERGE_VALUES || + Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES) return std::make_pair(Legal, Aspect.Type); LegalizeAction Action = findInActions(Aspect); diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index d92bbc1c246..41985e3a328 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -416,6 +416,46 @@ MachineIRBuilder::buildSequence(unsigned Res, return MIB; } +MachineInstrBuilder MachineIRBuilder::buildMerge(unsigned Res, + ArrayRef<unsigned> Ops) { + +#ifndef NDEBUG + assert(!Ops.empty() && "invalid trivial sequence"); + LLT Ty = MRI->getType(Ops[0]); + for (auto Reg : Ops) + assert(MRI->getType(Reg) == Ty && "type mismatch in input list"); + assert(Ops.size() * MRI->getType(Ops[0]).getSizeInBits() == + MRI->getType(Res).getSizeInBits() && + "input operands do not cover output register"); +#endif + + MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_MERGE_VALUES); + MIB.addDef(Res); + for (unsigned i = 0; i < Ops.size(); ++i) + MIB.addUse(Ops[i]); + return MIB; +} + +MachineInstrBuilder MachineIRBuilder::buildUnmerge(ArrayRef<unsigned> Res, + unsigned Op) { + +#ifndef NDEBUG + assert(!Res.empty() && "invalid trivial sequence"); + LLT Ty = MRI->getType(Res[0]); + for (auto Reg : Res) + assert(MRI->getType(Reg) == Ty && "type mismatch in input list"); + assert(Res.size() * MRI->getType(Res[0]).getSizeInBits() == + MRI->getType(Op).getSizeInBits() && + "input operands do not cover output register"); +#endif + + MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_UNMERGE_VALUES); + for (unsigned i = 0; i < Res.size(); ++i) + MIB.addDef(Res[i]); + MIB.addUse(Op); + return MIB; +} + MachineInstrBuilder MachineIRBuilder::buildIntrinsic(Intrinsic::ID ID, unsigned Res, bool HasSideEffects) { diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir index 63f852030e7..9b27198b961 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir @@ -33,14 +33,14 @@ body: | bb.0.entry: liveins: %x0, %x1, %x2, %x3 ; CHECK-LABEL: name: test_scalar_add_big - ; CHECK-NOT: G_EXTRACT - ; CHECK-NOT: G_SEQUENCE + ; CHECK-NOT: G_MERGE_VALUES + ; CHECK-NOT: G_UNMERGE_VALUES ; CHECK-DAG: [[CARRY0_32:%.*]](s32) = G_CONSTANT i32 0 ; CHECK-DAG: [[CARRY0:%[0-9]+]](s1) = G_TRUNC [[CARRY0_32]] ; CHECK: [[RES_LO:%.*]](s64), [[CARRY:%.*]](s1) = G_UADDE %0, %2, [[CARRY0]] ; CHECK: [[RES_HI:%.*]](s64), {{%.*}}(s1) = G_UADDE %1, %3, [[CARRY]] - ; CHECK-NOT: G_EXTRACT - ; CHECK-NOT: G_SEQUENCE + ; CHECK-NOT: G_MERGE_VALUES + ; CHECK-NOT: G_UNMERGE_VALUES ; CHECK: %x0 = COPY [[RES_LO]] ; CHECK: %x1 = COPY [[RES_HI]] @@ -48,10 +48,10 @@ body: | %1(s64) = COPY %x1 %2(s64) = COPY %x2 %3(s64) = COPY %x3 - %4(s128) = G_SEQUENCE %0, 0, %1, 64 - %5(s128) = G_SEQUENCE %2, 0, %3, 64 + %4(s128) = G_MERGE_VALUES %0, %1 + %5(s128) = G_MERGE_VALUES %2, %3 %6(s128) = G_ADD %4, %5 - %7(s64), %8(s64) = G_EXTRACT %6, 0, 64 + %7(s64), %8(s64) = G_UNMERGE_VALUES %6 %x0 = COPY %7 %x1 = COPY %8 ... @@ -112,10 +112,10 @@ body: | %1(<2 x s64>) = COPY %q1 %2(<2 x s64>) = COPY %q2 %3(<2 x s64>) = COPY %q3 - %4(<4 x s64>) = G_SEQUENCE %0, 0, %1, 128 - %5(<4 x s64>) = G_SEQUENCE %2, 0, %3, 128 + %4(<4 x s64>) = G_MERGE_VALUES %0, %1 + %5(<4 x s64>) = G_MERGE_VALUES %2, %3 %6(<4 x s64>) = G_ADD %4, %5 - %7(<2 x s64>), %8(<2 x s64>) = G_EXTRACT %6, 0, 128 + %7(<2 x s64>), %8(<2 x s64>) = G_UNMERGE_VALUES %6 %q0 = COPY %7 %q1 = COPY %8 ... diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir index 29551135358..e7983af2464 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir @@ -59,7 +59,7 @@ body: | ; CHECK: [[OFFSET1:%[0-9]+]](s64) = G_CONSTANT i64 8 ; CHECK: [[GEP1:%[0-9]+]](p0) = G_GEP %0, [[OFFSET1]](s64) ; CHECK: [[LOAD1:%[0-9]+]](s64) = G_LOAD [[GEP1]](p0) :: (load 16 from %ir.addr) - ; CHECK: %8(s128) = G_SEQUENCE [[LOAD0]](s64), 0, [[LOAD1]](s64), 64 + ; CHECK: %8(s128) = G_MERGE_VALUES [[LOAD0]](s64), [[LOAD1]](s64) %8(s128) = G_LOAD %0(p0) :: (load 16 from %ir.addr) ... @@ -112,6 +112,6 @@ body: | ; CHECK: [[GEP1:%[0-9]+]](p0) = G_GEP %0, [[OFFSET1]](s64) ; CHECK: G_STORE %6(s64), [[GEP1]](p0) :: (store 16 into %ir.addr) %6(s64) = G_PTRTOINT %0(p0) - %7(s128) = G_SEQUENCE %5, 0, %6, 64 + %7(s128) = G_MERGE_VALUES %5, %6 G_STORE %7, %0 :: (store 16 into %ir.addr) ... |