diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h --- a/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h @@ -55,6 +55,12 @@ virtual bool shouldCSEOpc(unsigned Opc) override; }; +class CSEConfigCopyOnly : public CSEConfig { +public: + virtual ~CSEConfigCopyOnly() = default; + virtual bool shouldCSEOpc(unsigned Opc) override; +}; + /// The CSE Analysis object. /// This installs itself as a delegate to the MachineFunction to track /// new instructions as well as deletions. It however will not be able to @@ -169,7 +175,8 @@ // Profiling methods. const GISelInstProfileBuilder &addNodeIDOpcode(unsigned Opc) const; const GISelInstProfileBuilder &addNodeIDRegType(const LLT &Ty) const; - const GISelInstProfileBuilder &addNodeIDRegType(const unsigned) const; + const GISelInstProfileBuilder &addNodeIDRegType(const unsigned, + unsigned) const; const GISelInstProfileBuilder & addNodeIDRegType(const TargetRegisterClass *RC) const; diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -117,16 +117,21 @@ }; class SrcOp { + struct RegSubRegTy { + unsigned Reg; + unsigned SubReg; + }; union { MachineInstrBuilder SrcMIB; - unsigned Reg; + struct RegSubRegTy RegPair; CmpInst::Predicate Pred; }; public: enum class SrcType { Ty_Reg, Ty_MIB, Ty_Predicate }; - SrcOp(unsigned R) : Reg(R), Ty(SrcType::Ty_Reg) {} - SrcOp(const MachineOperand &Op) : Reg(Op.getReg()), Ty(SrcType::Ty_Reg) {} + SrcOp(unsigned R, unsigned S = 0) : RegPair({R, S}), Ty(SrcType::Ty_Reg) {} + SrcOp(const MachineOperand &Op) + : RegPair({Op.getReg(), 0}), Ty(SrcType::Ty_Reg) {} SrcOp(const MachineInstrBuilder &MIB) : SrcMIB(MIB), Ty(SrcType::Ty_MIB) {} SrcOp(const CmpInst::Predicate P) : Pred(P), Ty(SrcType::Ty_Predicate) {} @@ -136,7 +141,7 @@ MIB.addPredicate(Pred); break; case SrcType::Ty_Reg: - MIB.addUse(Reg); + MIB.addUse(RegPair.Reg, 0, RegPair.SubReg); break; case SrcType::Ty_MIB: MIB.addUse(SrcMIB->getOperand(0).getReg()); @@ -149,7 +154,7 @@ case SrcType::Ty_Predicate: llvm_unreachable("Not a register operand"); case SrcType::Ty_Reg: - return MRI.getType(Reg); + return MRI.getType(RegPair.Reg); case SrcType::Ty_MIB: return MRI.getType(SrcMIB->getOperand(0).getReg()); } @@ -161,13 +166,15 @@ case SrcType::Ty_Predicate: llvm_unreachable("Not a register operand"); case SrcType::Ty_Reg: - return Reg; + return RegPair.Reg; case SrcType::Ty_MIB: return SrcMIB->getOperand(0).getReg(); } llvm_unreachable("Unrecognised SrcOp::SrcType enum"); } + unsigned getSubReg() const { return RegPair.SubReg; } + CmpInst::Predicate getPredicate() const { switch (Ty) { case SrcType::Ty_Predicate: @@ -640,8 +647,7 @@ /// \pre setBasicBlock or setMI must have been called. /// /// \return a MachineInstrBuilder for the newly created instruction. - MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op, - unsigned Subreg = 0); + MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op); /// Build and insert `Res = G_LOAD Addr, MMO`. /// diff --git a/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp b/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp --- a/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp @@ -60,6 +60,11 @@ bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) { return Opc == TargetOpcode::G_CONSTANT; } + +bool CSEConfigCopyOnly::shouldCSEOpc(unsigned Opc) { + return Opc == TargetOpcode::COPY; +} + /// ----------------------------------------- /// -------- GISelCSEInfo -------------// @@ -200,7 +205,7 @@ bool GISelCSEInfo::shouldCSE(unsigned Opc) const { // Only GISel opcodes are CSEable - if (!isPreISelGenericOpcode(Opc)) + if (!isPreISelGenericOpcode(Opc) && Opc != TargetOpcode::COPY) return false; assert(CSEOpt.get() && "CSEConfig not set"); return CSEOpt->shouldCSEOpc(Opc); @@ -300,8 +305,10 @@ } const GISelInstProfileBuilder & -GISelInstProfileBuilder::addNodeIDRegType(const unsigned Reg) const { - addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false)); +GISelInstProfileBuilder::addNodeIDRegType(const unsigned Reg, + unsigned SubReg) const { + addNodeIDMachineOperand(MachineOperand::CreateReg( + Reg, false, false, false, false, false, false, SubReg)); return *this; } @@ -324,6 +331,9 @@ unsigned Reg = MO.getReg(); if (!MO.isDef()) addNodeIDRegNum(Reg); + const auto *TRI = MRI.getTargetRegisterInfo(); + if (TRI->isPhysicalRegister(Reg)) + return *this; LLT Ty = MRI.getType(Reg); if (Ty.isValid()) addNodeIDRegType(Ty); diff --git a/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp --- a/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp @@ -73,8 +73,11 @@ case SrcOp::SrcType::Ty_Predicate: B.addNodeIDImmediate(static_cast(Op.getPredicate())); break; + case SrcOp::SrcType::Ty_MIB: + B.addNodeIDRegType(Op.getReg(), 0); + break; default: - B.addNodeIDRegType(Op.getReg()); + B.addNodeIDRegType(Op.getReg(), Op.getSubReg()); break; } } diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -242,11 +242,8 @@ } MachineInstrBuilder MachineIRBuilder::buildCopy(const DstOp &Res, - const SrcOp &Op, - unsigned Subreg) { - auto Copy = buildInstr(TargetOpcode::COPY, Res, Op); - Copy->getOperand(1).setSubReg(Subreg); - return Copy; + const SrcOp &Op) { + return buildInstr(TargetOpcode::COPY, Res, Op); } MachineInstrBuilder MachineIRBuilder::buildConstant(const DstOp &Res, diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -478,7 +478,7 @@ unsigned SubReg) { MachineIRBuilder MIB(I); auto Copy = MIB.buildCopy({From}, {SrcReg}); - auto SubRegCopy = MIB.buildCopy({To}, {Copy}, SubReg); + auto SubRegCopy = MIB.buildCopy({To}, {Copy.getReg(0), SubReg}); MachineOperand &RegOp = I.getOperand(1); RegOp.setReg(SubRegCopy.getReg(0)); @@ -1104,7 +1104,7 @@ unsigned DstReg = MRI.createGenericVirtualRegister(LLT::scalar(64)); MIB.setInsertPt(MIB.getMBB(), std::next(I.getIterator())); - MIB.buildCopy({I.getOperand(0).getReg()}, {DstReg}, AArch64::sub_32); + MIB.buildCopy({I.getOperand(0).getReg()}, {DstReg, AArch64::sub_32}); RBI.constrainGenericRegister(I.getOperand(0).getReg(), AArch64::GPR32RegClass, MRI); I.getOperand(0).setReg(DstReg); @@ -1938,7 +1938,7 @@ DstReg = MRI.createVirtualRegister(DstRC); // If the lane index is 0, we just use a subregister COPY. if (LaneIdx == 0) { - auto Copy = MIRBuilder.buildCopy({*DstReg}, {VecReg}, ExtractSubReg); + auto Copy = MIRBuilder.buildCopy({*DstReg}, {VecReg, ExtractSubReg}); RBI.constrainGenericRegister(*DstReg, *DstRC, MRI); return &*Copy; } @@ -2115,7 +2115,7 @@ // // Perform the first copy separately as a subregister copy. unsigned CopyTo = I.getOperand(0).getReg(); - auto FirstCopy = MIB.buildCopy({CopyTo}, {InsertRegs[0]}, ExtractSubReg); + auto FirstCopy = MIB.buildCopy({CopyTo}, {InsertRegs[0], ExtractSubReg}); constrainSelectedInstRegOperands(*FirstCopy, TII, TRI, RBI); // Now, perform the remaining copies as vector lane copies. @@ -2387,8 +2387,8 @@ {Concat->getOperand(0).getReg(), IndexLoad->getOperand(0).getReg()}); constrainSelectedInstRegOperands(*TBL1, TII, TRI, RBI); - auto Copy = - MIRBuilder.buildCopy({I.getOperand(0).getReg()}, {TBL1}, AArch64::dsub); + auto Copy = MIRBuilder.buildCopy({I.getOperand(0).getReg()}, + {TBL1.getReg(0), AArch64::dsub}); RBI.constrainGenericRegister(Copy.getReg(0), AArch64::FPR64RegClass, MRI); I.eraseFromParent(); return true; @@ -2538,7 +2538,7 @@ unsigned Reg = MRI.createVirtualRegister(RC); unsigned DstReg = I.getOperand(0).getReg(); - MIRBuilder.buildCopy({DstReg}, {DstVec}, SubReg); + MIRBuilder.buildCopy({DstReg}, {DstVec, SubReg}); MachineOperand &RegOp = I.getOperand(1); RegOp.setReg(Reg); RBI.constrainGenericRegister(DstReg, *RC, MRI); diff --git a/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp b/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp @@ -96,4 +96,28 @@ auto MIBZeroTmp = CSEB.buildConstant(s16, 0); EXPECT_TRUE(&*MIBZero == &*MIBZeroTmp); } + +TEST_F(GISelMITest, TestCSESubRegOp) { + if (!TM) + return; + + LLT s32{LLT::scalar(32)}; + GISelCSEInfo CSEInfo; + CSEInfo.setCSEConfig(make_unique()); + CSEInfo.analyze(*MF); + B.setCSEInfo(&CSEInfo); + CSEMIRBuilder CSEB(B.getState()); + + CSEB.setInsertPt(*EntryMBB, EntryMBB->end()); + auto Copy1 = CSEB.buildInstr(TargetOpcode::COPY, {s32}, {Copies[0]}); + auto MIBCopy = CSEB.buildInstr(TargetOpcode::COPY, {s32}, {Copies[0]}); + EXPECT_EQ(&*MIBCopy, &*Copy1); + + // Check copy of subregs + auto SubRegCopy1 = + CSEB.buildInstr(TargetOpcode::COPY, {s32}, {{Copies[0], 2}}); + auto SubRegCopy2 = + CSEB.buildInstr(TargetOpcode::COPY, {s32}, {{Copies[0], 2}}); + EXPECT_EQ(&*SubRegCopy1, &*SubRegCopy2); +} } // namespace