From f4d294cc96f5c891a589c1fd2ec7717d461900f3 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Fri, 3 Mar 2017 22:46:09 +0000 Subject: [PATCH] GlobalISel: add merge/unmerge nodes for legalization. These are simplified variants of the current G_SEQUENCE and G_EXTRACT, which assume the individual parts will be contiguous, homogeneous, and occupy the entirity of the larger register. This makes reasoning about them much easer since you only have to look at the first register being merged and the result to know what the instruction is doing. I intend to gradually replace all uses of the more complicated sequence/extract with these (or single-element insert/extracts), and then remove the older variants. For now we start with legalization. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296921 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/GlobalISel/Legalizer.h | 3 ++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h | 25 ++++++++++++++ include/llvm/Target/GenericOpcodes.td | 15 ++++++++ include/llvm/Target/TargetOpcodes.def | 4 +++ lib/CodeGen/GlobalISel/Legalizer.cpp | 31 +++++++++++++++++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 24 ++++--------- lib/CodeGen/GlobalISel/LegalizerInfo.cpp | 4 ++- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 40 ++++++++++++++++++++++ test/CodeGen/AArch64/GlobalISel/legalize-add.mir | 20 +++++------ .../AArch64/GlobalISel/legalize-load-store.mir | 4 +-- 10 files changed, 139 insertions(+), 31 deletions(-) diff --git a/include/llvm/CodeGen/GlobalISel/Legalizer.h b/include/llvm/CodeGen/GlobalISel/Legalizer.h index 8284ab6dac6..bed7230cc01 100644 --- a/include/llvm/CodeGen/GlobalISel/Legalizer.h +++ b/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/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index a3fa6c263b1..d7fe1c4f63e 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -468,6 +468,31 @@ public: ArrayRef Ops, ArrayRef Indices); + /// Build and insert \p Res = 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 Ops); + + /// Build and insert \p Res0, ... = 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 Res, unsigned Op); + void addUsesWithIndices(MachineInstrBuilder MIB) {} template diff --git a/include/llvm/Target/GenericOpcodes.td b/include/llvm/Target/GenericOpcodes.td index 880fbc46374..fecdd72d6a5 100644 --- a/include/llvm/Target/GenericOpcodes.td +++ b/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/include/llvm/Target/TargetOpcodes.def b/include/llvm/Target/TargetOpcodes.def index 2d1ff50ca10..58e6157778c 100644 --- a/include/llvm/Target/TargetOpcodes.def +++ b/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/lib/CodeGen/GlobalISel/Legalizer.cpp b/lib/CodeGen/GlobalISel/Legalizer.cpp index 8f3d341720b..a849346ce99 100644 --- a/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/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/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 6bb64e068ec..2d28a42c797 100644 --- a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -86,13 +86,9 @@ LegalizerHelper::legalizeInstr(MachineInstr &MI, void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, SmallVectorImpl &VRegs) { - unsigned Size = Ty.getSizeInBits(); - SmallVector 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 Src1Regs, Src2Regs, DstRegs; - SmallVector 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 DstRegs; - SmallVector 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 Src1Regs, Src2Regs, DstRegs; - SmallVector 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/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/lib/CodeGen/GlobalISel/LegalizerInfo.cpp index 75c54c23872..d9e4f848a74 100644 --- a/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ b/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/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index d92bbc1c246..41985e3a328 100644 --- a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -416,6 +416,46 @@ MachineIRBuilder::buildSequence(unsigned Res, return MIB; } +MachineInstrBuilder MachineIRBuilder::buildMerge(unsigned Res, + ArrayRef 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 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/test/CodeGen/AArch64/GlobalISel/legalize-add.mir b/test/CodeGen/AArch64/GlobalISel/legalize-add.mir index 63f852030e7..9b27198b961 100644 --- a/test/CodeGen/AArch64/GlobalISel/legalize-add.mir +++ b/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/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir b/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir index 29551135358..e7983af2464 100644 --- a/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir +++ b/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) ... -- 2.11.0