Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -23,6 +23,59 @@ namespace llvm { +namespace MIB { +/// Wrapper for a VReg use or def to be used with `MachineIRBuilder::buildInstr` +/// variants. If you know whether the register will be used or defined at +/// compile-time, consider using `MIB::Use` or `MIB::Def` instead. +struct Reg { + unsigned TheReg; + unsigned Flags; + + explicit Reg(unsigned TheReg, unsigned Flags = 0) + : TheReg(TheReg), Flags(Flags) {} +}; + +// Two helper classes to explicitly create statically-known uses and defs in a +// uniform manner. They are implemented as classes rather than functions to +// allow the stricter type-checking provided by braced initialization. +// +// Beware, during use these are converted back to a Reg value, with all the +// slicing possibilities C++ offers: make sure they never develop any data +// members you care about. + +/// Create a VReg definition to be used with `MachineIRBuilder::buildInstr` +struct Def : Reg { + Def(unsigned TheReg, unsigned ExtraFlags = 0) + : Reg{TheReg, ExtraFlags | RegState::Define} {} +}; + +/// Create a VReg use to be used with `MachineIRBuilder::buildInstr` +struct Use : Reg { + Use(unsigned TheReg, unsigned Flags = 0) : Reg{TheReg, Flags} { + assert(!(Flags & RegState::Define) && "misleading register definition"); + } +}; + +/// Wrapper for frame index to be used with `MachineIRBuilder::buildInstr` +struct FI { + int Idx; + explicit FI(int Idx) : Idx(Idx) {} +}; + +/// Wrapper for immediate to be used with `MachineIRBuilder::buildInstr` +struct Imm { + int64_t Val; + explicit Imm(int64_t Val) : Val(Val) {} +}; + +/// Wrapper for MachineBasicBlock to be used with `MachineIRBuilder::buildInstr` +struct MBB { + MachineBasicBlock &BB; + explicit MBB(MachineBasicBlock &BB) : BB(BB) {} +}; + +} + // Forward declarations. class MachineFunction; class MachineInstr; @@ -52,15 +105,35 @@ return *TII; } - static void addRegs(MachineInstrBuilder &MIB) {} + static void addOperands(MachineInstrBuilder &MIB) {} - template - static void addRegs(MachineInstrBuilder &MIB, unsigned Reg, - MoreRegs... Regs) { - MIB.addReg(Reg); - addRegs(MIB, Regs...); + template + static void addOperands(MachineInstrBuilder &MIB, MIB::Reg Reg, + MoreOps ... Ops) { + MIB.addReg(Reg.TheReg, Reg.Flags); + addOperands(MIB, Ops...); } + template + static void addOperands(MachineInstrBuilder &MIB, MIB::Imm Imm, + MoreOps ... Ops) { + MIB.addImm(Imm.Val); + addOperands(MIB, Ops...); + } + + template + static void addOperands(MachineInstrBuilder &MIB, MIB::FI Idx, + MoreOps... Ops) { + MIB.addFrameIndex(Idx.Idx); + addOperands(MIB, Ops...); + } + + template + static void addOperands(MachineInstrBuilder &MIB, MIB::MBB MBB, + MoreOps... Ops) { + MIB.addMBB(&MBB.BB); + addOperands(MIB, Ops...); + } public: /// Getter for the function we currently build. @@ -98,60 +171,62 @@ void setDebugLoc(const DebugLoc &DL) { this->DL = DL; } /// Build and insert = \p Opcode [ { \p Tys } ] . - /// \p Ty is the type of the instruction if \p Opcode describes - /// a generic machine instruction. \p Ty must be LLT{} if \p Opcode + /// \p Tys is a list of the types of the instruction if \p Opcode describes + /// a generic machine instruction. \p Tys must be empty if \p Opcode /// does not describe a generic instruction. /// The insertion point is the one set by the last call of either /// setBasicBlock or setMI. /// /// \pre setBasicBlock or setMI must have been called. - /// \pre Ty == LLT{} or isPreISelGenericOpcode(Opcode) + /// \pre Tys.empty() or isPreISelGenericOpcode(Opcode) /// /// \return The newly created instruction. MachineInstr *buildInstr(unsigned Opcode, ArrayRef Tys); - /// Build and insert \p Res = \p Opcode [\p Ty] \p Uses.... - /// \p Ty is the type of the instruction if \p Opcode describes - /// a generic machine instruction. \p Ty must be LLT{} if \p Opcode - /// does not describe a generic instruction. - /// The insertion point is the one set by the last call of either - /// setBasicBlock or setMI. + /// Build and insert `Res(s)... = Opcode [ Ty] Use(s)...`. \p Ty is the + /// type of the instruction if \p Opcode describes a generic machine + /// instruction. \p Ty must be LLT{} if \p Opcode does not describe a generic + /// instruction. The insertion point is the one set by the last call of + /// either setBasicBlock or setMI. /// /// \pre setBasicBlock or setMI must have been called. - /// \pre Ty == LLT{} or isPreISelGenericOpcode(Opcode) + /// \pre Tys.empty() or isPreISelGenericOpcode(Opcode) + /// \pre Each \p Ops parameter must be an instance of a class in the namespace + /// llvm::MIB. /// /// \return The newly created instruction. - template - MachineInstr *buildInstr(unsigned Opcode, ArrayRef Tys, unsigned Res, - MoreRegs... Uses) { + template + MachineInstr *buildInstr(unsigned Opcode, ArrayRef Tys, + MoreOps... Ops) { MachineInstr *NewMI = buildInstr(Opcode, Tys); MachineInstrBuilder MIB{getMF(), NewMI}; - MIB.addReg(Res, RegState::Define); - addRegs(MIB, Uses...); - + addOperands(MIB, Ops...); return NewMI; } - /// Build and insert = \p Opcode . + /// Build and insert `Res(s)... = Opcode Use(s)...`. The insertion point is + /// the one set by the last call of either setBasicBlock or setMI. /// /// \pre setBasicBlock or setMI must have been called. - /// \pre not isPreISelGenericOpcode(\p Opcode) + /// \pre Each \p Ops parameter must be an instance of a class in the namespace + /// llvm::MIB. /// /// \return The newly created instruction. - MachineInstr *buildInstr(unsigned Opcode) { - return buildInstr(Opcode, ArrayRef()); + template + MachineInstr *buildInstr(unsigned Opcode, MoreOps... Ops) { + return buildInstr(Opcode, ArrayRef(), Ops...); } - /// Build and insert \p Res = \p Opcode \p Uses.... - /// The insertion point is the one set by the last call of either - /// setBasicBlock or setMI. - /// - /// \pre setBasicBlock or setMI must have been called. - /// - /// \return The newly created instruction. - template - MachineInstr *buildInstr(unsigned Opcode, unsigned Res, MoreRegs... Uses) { - return buildInstr(Opcode, ArrayRef(), Res, Uses...); + // This version is needed because otherwise the buildInstr(unsigned, + // MoreOps...) instance is preferred, and then instantiation fails when there + // is no specialization available for buildInstr(unsigned, ArrayRef, + // Ops...) where Ops contains an LLT. + template + MachineInstr *buildInstr(unsigned Opcode, LLT Ty, + MoreOps... Ops) { + assert(isPreISelGenericOpcode(Opcode) && + "unexpected type on non-generic opcode"); + return buildInstr(Opcode, ArrayRef(Ty), Ops...); } /// Build and insert \p Res = G_FRAME_INDEX \p Ty \p Idx Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -85,7 +85,8 @@ unsigned Op0 = getOrCreateVReg(*Inst.getOperand(0)); unsigned Op1 = getOrCreateVReg(*Inst.getOperand(1)); unsigned Res = getOrCreateVReg(Inst); - MIRBuilder.buildInstr(Opcode, LLT{*Inst.getType()}, Res, Op0, Op1); + MIRBuilder.buildInstr(Opcode, LLT{*Inst.getType()}, MIB::Def(Res), + MIB::Use(Op0), MIB::Use(Op1)); return true; } @@ -161,7 +162,7 @@ unsigned Op = getOrCreateVReg(*CI.getOperand(0)); unsigned Res = getOrCreateVReg(CI); MIRBuilder.buildInstr(Opcode, {LLT{*CI.getDestTy()}, LLT{*CI.getSrcTy()}}, - Res, Op); + MIB::Def(Res), MIB::Use(Op)); return true; } Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -72,32 +72,29 @@ } MachineInstr *MachineIRBuilder::buildFrameIndex(LLT Ty, unsigned Res, int Idx) { - MachineInstr *NewMI = buildInstr(TargetOpcode::G_FRAME_INDEX, Ty); - auto MIB = MachineInstrBuilder(getMF(), NewMI); - MIB.addReg(Res, RegState::Define); - MIB.addFrameIndex(Idx); - return NewMI; + return buildInstr(TargetOpcode::G_FRAME_INDEX, Ty, MIB::Def{Res}, + MIB::FI{Idx}); } MachineInstr *MachineIRBuilder::buildAdd(LLT Ty, unsigned Res, unsigned Op0, unsigned Op1) { - return buildInstr(TargetOpcode::G_ADD, Ty, Res, Op0, Op1); + return buildInstr(TargetOpcode::G_ADD, Ty, MIB::Def{Res}, MIB::Use{Op0}, + MIB::Use{Op1}); } MachineInstr *MachineIRBuilder::buildBr(MachineBasicBlock &Dest) { - MachineInstr *NewMI = buildInstr(TargetOpcode::G_BR, LLT::unsized()); - MachineInstrBuilder(getMF(), NewMI).addMBB(&Dest); - return NewMI; + return buildInstr(TargetOpcode::G_BR, LLT::unsized(), MIB::MBB{Dest}); } MachineInstr *MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) { - return buildInstr(TargetOpcode::COPY, Res, Op); + return buildInstr(TargetOpcode::COPY, MIB::Def{Res}, MIB::Use{Op}); } MachineInstr *MachineIRBuilder::buildLoad(LLT VTy, LLT PTy, unsigned Res, unsigned Addr, MachineMemOperand &MMO) { - MachineInstr *NewMI = buildInstr(TargetOpcode::G_LOAD, {VTy, PTy}, Res, Addr); + auto NewMI = buildInstr(TargetOpcode::G_LOAD, {VTy, PTy}, MIB::Def{Res}, + MIB::Use{Addr}); NewMI->addMemOperand(getMF(), &MMO); return NewMI; } @@ -105,9 +102,9 @@ MachineInstr *MachineIRBuilder::buildStore(LLT VTy, LLT PTy, unsigned Val, unsigned Addr, MachineMemOperand &MMO) { - MachineInstr *NewMI = buildInstr(TargetOpcode::G_STORE, {VTy, PTy}); + auto NewMI = buildInstr(TargetOpcode::G_STORE, {VTy, PTy}, MIB::Use{Val}, + MIB::Use{Addr}); NewMI->addMemOperand(getMF(), &MMO); - MachineInstrBuilder(getMF(), NewMI).addReg(Val).addReg(Addr); return NewMI; } Index: lib/Target/AArch64/AArch64CallLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64CallLowering.cpp +++ lib/Target/AArch64/AArch64CallLowering.cpp @@ -45,8 +45,7 @@ unsigned ResReg = (Size == 32) ? AArch64::W0 : AArch64::X0; // Set the insertion point to be right before Return. MIRBuilder.setInstr(*Return, /* Before */ true); - MachineInstr *Copy = - MIRBuilder.buildInstr(TargetOpcode::COPY, ResReg, VReg); + MachineInstr *Copy = MIRBuilder.buildCopy(ResReg, VReg); (void)Copy; assert(Copy->getNextNode() == Return && "The insertion did not happen where we expected"); @@ -85,7 +84,7 @@ assert(VA.isRegLoc() && "Not yet implemented"); // Transform the arguments in physical registers into virtual ones. MIRBuilder.getMBB().addLiveIn(VA.getLocReg()); - MIRBuilder.buildInstr(TargetOpcode::COPY, VRegs[i], VA.getLocReg()); + MIRBuilder.buildCopy(VRegs[i], VA.getLocReg()); switch (VA.getLocInfo()) { default: