Index: include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h @@ -0,0 +1,133 @@ +//===-- llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements a version of MachineIRBuilder which does trivial +/// constant folding. +//===----------------------------------------------------------------------===// +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" + +namespace llvm { + +static Optional ConstantFoldBinOp(unsigned Opcode, const unsigned Op1, + const unsigned Op2, + const MachineRegisterInfo &MRI) { + auto MaybeOp1Cst = getConstantVRegVal(Op1, MRI); + auto MaybeOp2Cst = getConstantVRegVal(Op2, MRI); + if (MaybeOp1Cst && MaybeOp2Cst) { + LLT Ty = MRI.getType(Op1); + APInt C1(Ty.getSizeInBits(), *MaybeOp1Cst, true); + APInt C2(Ty.getSizeInBits(), *MaybeOp2Cst, true); + switch (Opcode) { + default: + break; + case TargetOpcode::G_ADD: + return C1 + C2; + case TargetOpcode::G_AND: + return C1 & C2; + case TargetOpcode::G_ASHR: + return C1.ashr(C2); + case TargetOpcode::G_LSHR: + return C1.lshr(C2); + case TargetOpcode::G_MUL: + return C1 * C2; + case TargetOpcode::G_OR: + return C1 | C2; + case TargetOpcode::G_SHL: + return C1 << C2; + case TargetOpcode::G_SUB: + return C1 - C2; + case TargetOpcode::G_XOR: + return C1 ^ C2; + case TargetOpcode::G_UDIV: + if (!C2.getBoolValue()) + break; + return C1.udiv(C2); + case TargetOpcode::G_SDIV: + if (!C2.getBoolValue()) + break; + return C1.sdiv(C2); + case TargetOpcode::G_UREM: + if (!C2.getBoolValue()) + break; + return C1.urem(C2); + case TargetOpcode::G_SREM: + if (!C2.getBoolValue()) + break; + return C1.srem(C2); + } + } + return None; +} + +/// An MIRBuilder which does trivial constant folding of binary ops. +/// Calls to buildInstr will also try to constant fold binary ops. +class ConstantFoldingMIRBuilder + : public FoldableInstructionsBuilder { +public: + // Pull in base class constructors. + using FoldableInstructionsBuilder< + ConstantFoldingMIRBuilder>::FoldableInstructionsBuilder; + // Unhide buildInstr + using FoldableInstructionsBuilder::buildInstr; + + // Implement buildBinaryOp required by FoldableInstructionsBuilder which + // tries to constant fold. + MachineInstrBuilder buildBinaryOp(unsigned Opcode, unsigned Dst, + unsigned Src0, unsigned Src1) { + validateBinaryOp(Dst, Src0, Src1); + auto MaybeCst = ConstantFoldBinOp(Opcode, Src0, Src1, getMF().getRegInfo()); + if (MaybeCst) + return buildConstant(Dst, MaybeCst->getSExtValue()); + return buildInstr(Opcode).addDef(Dst).addUse(Src0).addUse(Src1); + } + + template + MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, UseArg1Ty &&Arg1, + UseArg2Ty &&Arg2) { + unsigned Dst = getDestFromArg(Ty); + return buildInstr(Opc, Dst, getRegFromArg(std::forward(Arg1)), + getRegFromArg(std::forward(Arg2))); + } + + // Try to provide an overload for buildInstr for binary ops in order to constant fold. + MachineInstrBuilder buildInstr(unsigned Opc, unsigned Dst, unsigned Src0, + unsigned Src1) { + switch (Opc) { + default: + break; + case TargetOpcode::G_ADD: + case TargetOpcode::G_AND: + case TargetOpcode::G_ASHR: + case TargetOpcode::G_LSHR: + case TargetOpcode::G_MUL: + case TargetOpcode::G_OR: + case TargetOpcode::G_SHL: + case TargetOpcode::G_SUB: + case TargetOpcode::G_XOR: + case TargetOpcode::G_UDIV: + case TargetOpcode::G_SDIV: + case TargetOpcode::G_UREM: + case TargetOpcode::G_SREM: { + return buildBinaryOp(Opc, Dst, Src0, Src1); + } + } + return buildInstr(Opc).addDef(Dst).addUse(Src0).addUse(Src1); + } + + // Fallback implementation of buildInstr. + template + MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, + UseArgsTy &&... Args) { + auto MIB = buildInstr(Opc).addDef(getDestFromArg(Ty)); + addUsesFromArgs(MIB, std::forward(Args)...); + return MIB; + } +}; +} // namespace llvm Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -31,11 +31,10 @@ class MachineInstr; class TargetInstrInfo; -/// Helper class to build MachineInstr. -/// It keeps internally the insertion point and debug location for all -/// the new instructions we want to create. -/// This information can be modify via the related setters. -class MachineIRBuilder { +/// Class which stores all the state required in a MachineIRBuilder. +/// Since MachineIRBuilders will only store state in this object, it allows +/// to transfer BuilderState between different kinds of MachineIRBuilders. +struct MachineIRBuilderState { /// MachineFunction under construction. MachineFunction *MF; /// Information used to access the description of the opcodes. @@ -52,15 +51,23 @@ /// @} std::function InsertedInstr; +}; +/// Helper class to build MachineInstr. +/// It keeps internally the insertion point and debug location for all +/// the new instructions we want to create. +/// This information can be modify via the related setters. +class MachineIRBuilderBase { + + MachineIRBuilderState State; const TargetInstrInfo &getTII() { - assert(TII && "TargetInstrInfo is not set"); - return *TII; + assert(State.TII && "TargetInstrInfo is not set"); + return *State.TII; } void validateTruncExt(unsigned Dst, unsigned Src, bool IsExtend); - MachineInstrBuilder buildBinaryOp(unsigned Opcode, unsigned Res, unsigned Op0, unsigned Op1); +protected: unsigned getDestFromArg(unsigned Reg) { return Reg; } unsigned getDestFromArg(LLT Ty) { return getMF().getRegInfo().createGenericVirtualRegister(Ty); @@ -88,30 +95,41 @@ return MIB->getOperand(0).getReg(); } + void validateBinaryOp(unsigned Dst, unsigned Src0, unsigned Src1); + public: /// Some constructors for easy use. - MachineIRBuilder() = default; - MachineIRBuilder(MachineFunction &MF) { setMF(MF); } - MachineIRBuilder(MachineInstr &MI) : MachineIRBuilder(*MI.getMF()) { + MachineIRBuilderBase() = default; + MachineIRBuilderBase(MachineFunction &MF) { setMF(MF); } + MachineIRBuilderBase(MachineInstr &MI) : MachineIRBuilderBase(*MI.getMF()) { setInstr(MI); } + MachineIRBuilderBase(const MachineIRBuilderState &BState) : State(BState) {} + /// Getter for the function we currently build. MachineFunction &getMF() { - assert(MF && "MachineFunction is not set"); - return *MF; + assert(State.MF && "MachineFunction is not set"); + return *State.MF; } + /// Getter for DebugLoc + const DebugLoc &getDL() { return State.DL; } + + /// Getter for MRI + MachineRegisterInfo *getMRI() { return State.MRI; } + + /// Getter for the State + MachineIRBuilderState &getState() { return State; } + /// Getter for the basic block we currently build. MachineBasicBlock &getMBB() { - assert(MBB && "MachineBasicBlock is not set"); - return *MBB; + assert(State.MBB && "MachineBasicBlock is not set"); + return *State.MBB; } /// Current insertion point for new instructions. - MachineBasicBlock::iterator getInsertPt() { - return II; - } + MachineBasicBlock::iterator getInsertPt() { return State.II; } /// Set the insertion point before the specified position. /// \pre MBB must be in getMF(). @@ -141,10 +159,10 @@ /// @} /// Set the debug location to \p DL for all the next build instructions. - void setDebugLoc(const DebugLoc &DL) { this->DL = DL; } + void setDebugLoc(const DebugLoc &DL) { this->State.DL = DL; } /// Get the current instruction's debug location. - DebugLoc getDebugLoc() { return DL; } + DebugLoc getDebugLoc() { return State.DL; } /// Build and insert = \p Opcode . /// The insertion point is the one set by the last call of either @@ -155,20 +173,6 @@ /// \return a MachineInstrBuilder for the newly created instruction. MachineInstrBuilder buildInstr(unsigned Opcode); - /// DAG like Generic method for building arbitrary instructions as above. - /// \Opc opcode for the instruction. - /// \Ty Either LLT/TargetRegisterClass/unsigned types for Dst - /// \Args Variadic list of uses of types(unsigned/MachineInstrBuilder) - /// Uses of type MachineInstrBuilder will perform - /// getOperand(0).getReg() to convert to register. - template - MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, - UseArgsTy &&... Args) { - auto MIB = buildInstr(Opc).addDef(getDestFromArg(Ty)); - addUsesFromArgs(MIB, std::forward(Args)...); - return MIB; - } - /// Build but don't insert = \p Opcode . /// /// \pre setMF, setBasicBlock or setMI must have been called. @@ -226,59 +230,6 @@ /// \return a MachineInstrBuilder for the newly created instruction. MachineInstrBuilder buildGlobalValue(unsigned Res, const GlobalValue *GV); - /// Build and insert \p Res = G_ADD \p Op0, \p Op1 - /// - /// G_ADD sets \p Res to the sum of integer parameters \p Op0 and \p Op1, - /// truncated to their width. - /// - /// \pre setBasicBlock or setMI must have been called. - /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers - /// with the same (scalar or vector) type). - /// - /// \return a MachineInstrBuilder for the newly created instruction. - MachineInstrBuilder buildAdd(unsigned Res, unsigned Op0, - unsigned Op1); - template - MachineInstrBuilder buildAdd(DstTy &&Ty, UseArgsTy &&... UseArgs) { - unsigned Res = getDestFromArg(Ty); - return buildAdd(Res, (getRegFromArg(UseArgs))...); - } - - /// Build and insert \p Res = G_SUB \p Op0, \p Op1 - /// - /// G_SUB sets \p Res to the sum of integer parameters \p Op0 and \p Op1, - /// truncated to their width. - /// - /// \pre setBasicBlock or setMI must have been called. - /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers - /// with the same (scalar or vector) type). - /// - /// \return a MachineInstrBuilder for the newly created instruction. - template - MachineInstrBuilder buildSub(DstTy &&Ty, UseArgsTy &&... UseArgs) { - unsigned Res = getDestFromArg(Ty); - return buildSub(Res, (getRegFromArg(UseArgs))...); - } - MachineInstrBuilder buildSub(unsigned Res, unsigned Op0, - unsigned Op1); - - /// Build and insert \p Res = G_MUL \p Op0, \p Op1 - /// - /// G_MUL sets \p Res to the sum of integer parameters \p Op0 and \p Op1, - /// truncated to their width. - /// - /// \pre setBasicBlock or setMI must have been called. - /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers - /// with the same (scalar or vector) type). - /// - /// \return a MachineInstrBuilder for the newly created instruction. - template - MachineInstrBuilder buildMul(DstTy &&Ty, UseArgsTy &&... UseArgs) { - unsigned Res = getDestFromArg(Ty); - return buildMul(Res, (getRegFromArg(UseArgs))...); - } - MachineInstrBuilder buildMul(unsigned Res, unsigned Op0, - unsigned Op1); /// Build and insert \p Res = G_GEP \p Op0, \p Op1 /// @@ -347,38 +298,6 @@ MachineInstrBuilder buildUAdde(unsigned Res, unsigned CarryOut, unsigned Op0, unsigned Op1, unsigned CarryIn); - /// Build and insert \p Res = G_AND \p Op0, \p Op1 - /// - /// G_AND sets \p Res to the bitwise and of integer parameters \p Op0 and \p - /// Op1. - /// - /// \pre setBasicBlock or setMI must have been called. - /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers - /// with the same (scalar or vector) type). - /// - /// \return a MachineInstrBuilder for the newly created instruction. - template - MachineInstrBuilder buildAnd(DstTy &&Dst, UseArgsTy &&... UseArgs) { - return buildAnd(getDestFromArg(Dst), getRegFromArg(UseArgs)...); - } - MachineInstrBuilder buildAnd(unsigned Res, unsigned Op0, - unsigned Op1); - - /// Build and insert \p Res = G_OR \p Op0, \p Op1 - /// - /// G_OR sets \p Res to the bitwise or of integer parameters \p Op0 and \p - /// Op1. - /// - /// \pre setBasicBlock or setMI must have been called. - /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers - /// with the same (scalar or vector) type). - /// - /// \return a MachineInstrBuilder for the newly created instruction. - template - MachineInstrBuilder buildOr(DstTy &&Dst, UseArgsTy &&... UseArgs) { - return buildOr(getDestFromArg(Dst), getRegFromArg(UseArgs)...); - } - MachineInstrBuilder buildOr(unsigned Res, unsigned Op0, unsigned Op1); /// Build and insert \p Res = G_ANYEXT \p Op0 /// @@ -804,5 +723,140 @@ MachineMemOperand &MMO); }; +/// A CRTP class that contains methods for building instructions that can +/// be constant folded. MachineIRBuilders that want to inherit from this will +/// need to implement buildBinaryOp (for constant folding binary ops). +/// Alternatively, they can implement buildInstr(Opc, Dst, Uses...) to perform +/// additional folding for Opc. +template +class FoldableInstructionsBuilder : public MachineIRBuilderBase { + Base &base() { return static_cast(*this); } + +public: + using MachineIRBuilderBase::MachineIRBuilderBase; + /// Build and insert \p Res = G_ADD \p Op0, \p Op1 + /// + /// G_ADD sets \p Res to the sum of integer parameters \p Op0 and \p Op1, + /// truncated to their width. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers + /// with the same (scalar or vector) type). + /// + /// \return a MachineInstrBuilder for the newly created instruction. + + MachineInstrBuilder buildAdd(unsigned Dst, unsigned Src0, unsigned Src1) { + return base().buildBinaryOp(TargetOpcode::G_ADD, Dst, Src0, Src1); + } + template + MachineInstrBuilder buildAdd(DstTy &&Ty, UseArgsTy &&... UseArgs) { + unsigned Res = base().getDestFromArg(Ty); + return base().buildAdd(Res, (base().getRegFromArg(UseArgs))...); + } + + /// Build and insert \p Res = G_SUB \p Op0, \p Op1 + /// + /// G_SUB sets \p Res to the sum of integer parameters \p Op0 and \p Op1, + /// truncated to their width. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers + /// with the same (scalar or vector) type). + /// + /// \return a MachineInstrBuilder for the newly created instruction. + + MachineInstrBuilder buildSub(unsigned Dst, unsigned Src0, unsigned Src1) { + return base().buildBinaryOp(TargetOpcode::G_SUB, Dst, Src0, Src1); + } + template + MachineInstrBuilder buildSub(DstTy &&Ty, UseArgsTy &&... UseArgs) { + unsigned Res = base().getDestFromArg(Ty); + return base().buildSub(Res, (base().getRegFromArg(UseArgs))...); + } + + /// Build and insert \p Res = G_MUL \p Op0, \p Op1 + /// + /// G_MUL sets \p Res to the sum of integer parameters \p Op0 and \p Op1, + /// truncated to their width. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers + /// with the same (scalar or vector) type). + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildMul(unsigned Dst, unsigned Src0, unsigned Src1) { + return base().buildBinaryOp(TargetOpcode::G_MUL, Dst, Src0, Src1); + } + template + MachineInstrBuilder buildMul(DstTy &&Ty, UseArgsTy &&... UseArgs) { + unsigned Res = base().getDestFromArg(Ty); + return base().buildMul(Res, (base().getRegFromArg(UseArgs))...); + } + + /// Build and insert \p Res = G_AND \p Op0, \p Op1 + /// + /// G_AND sets \p Res to the bitwise and of integer parameters \p Op0 and \p + /// Op1. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers + /// with the same (scalar or vector) type). + /// + /// \return a MachineInstrBuilder for the newly created instruction. + + MachineInstrBuilder buildAnd(unsigned Dst, unsigned Src0, unsigned Src1) { + return base().buildBinaryOp(TargetOpcode::G_AND, Dst, Src0, Src1); + } + template + MachineInstrBuilder buildAnd(DstTy &&Ty, UseArgsTy &&... UseArgs) { + unsigned Res = base().getDestFromArg(Ty); + return base().buildAnd(Res, (base().getRegFromArg(UseArgs))...); + } + + /// Build and insert \p Res = G_OR \p Op0, \p Op1 + /// + /// G_OR sets \p Res to the bitwise or of integer parameters \p Op0 and \p + /// Op1. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers + /// with the same (scalar or vector) type). + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildOr(unsigned Dst, unsigned Src0, unsigned Src1) { + return base().buildBinaryOp(TargetOpcode::G_OR, Dst, Src0, Src1); + } + template + MachineInstrBuilder buildOr(DstTy &&Ty, UseArgsTy &&... UseArgs) { + unsigned Res = base().getDestFromArg(Ty); + return base().buildOr(Res, (base().getRegFromArg(UseArgs))...); + } +}; + +class MachineIRBuilder : public FoldableInstructionsBuilder { +public: + using FoldableInstructionsBuilder< + MachineIRBuilder>::FoldableInstructionsBuilder; + MachineInstrBuilder buildBinaryOp(unsigned Opcode, unsigned Dst, + unsigned Src0, unsigned Src1) { + validateBinaryOp(Dst, Src0, Src1); + return buildInstr(Opcode).addDef(Dst).addUse(Src0).addUse(Src1); + } + using FoldableInstructionsBuilder::buildInstr; + /// DAG like Generic method for building arbitrary instructions as above. + /// \Opc opcode for the instruction. + /// \Ty Either LLT/TargetRegisterClass/unsigned types for Dst + /// \Args Variadic list of uses of types(unsigned/MachineInstrBuilder) + /// Uses of type MachineInstrBuilder will perform + /// getOperand(0).getReg() to convert to register. + template + MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, + UseArgsTy &&... Args) { + auto MIB = buildInstr(Opc).addDef(getDestFromArg(Ty)); + addUsesFromArgs(MIB, std::forward(Args)...); + return MIB; + } +}; + } // End namespace llvm. #endif // LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -22,96 +22,99 @@ using namespace llvm; -void MachineIRBuilder::setMF(MachineFunction &MF) { - this->MF = &MF; - this->MBB = nullptr; - this->MRI = &MF.getRegInfo(); - this->TII = MF.getSubtarget().getInstrInfo(); - this->DL = DebugLoc(); - this->II = MachineBasicBlock::iterator(); - this->InsertedInstr = nullptr; -} - -void MachineIRBuilder::setMBB(MachineBasicBlock &MBB) { - this->MBB = &MBB; - this->II = MBB.end(); +void MachineIRBuilderBase::setMF(MachineFunction &MF) { + State.MF = &MF; + State.MBB = nullptr; + State.MRI = &MF.getRegInfo(); + State.TII = MF.getSubtarget().getInstrInfo(); + State.DL = DebugLoc(); + State.II = MachineBasicBlock::iterator(); + State.InsertedInstr = nullptr; +} + +void MachineIRBuilderBase::setMBB(MachineBasicBlock &MBB) { + State.MBB = &MBB; + State.II = MBB.end(); assert(&getMF() == MBB.getParent() && "Basic block is in a different function"); } -void MachineIRBuilder::setInstr(MachineInstr &MI) { +void MachineIRBuilderBase::setInstr(MachineInstr &MI) { assert(MI.getParent() && "Instruction is not part of a basic block"); setMBB(*MI.getParent()); - this->II = MI.getIterator(); + State.II = MI.getIterator(); } -void MachineIRBuilder::setInsertPt(MachineBasicBlock &MBB, - MachineBasicBlock::iterator II) { +void MachineIRBuilderBase::setInsertPt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator II) { assert(MBB.getParent() == &getMF() && "Basic block is in a different function"); - this->MBB = &MBB; - this->II = II; + State.MBB = &MBB; + State.II = II; } -void MachineIRBuilder::recordInsertions( +void MachineIRBuilderBase::recordInsertions( std::function Inserted) { - InsertedInstr = std::move(Inserted); + State.InsertedInstr = std::move(Inserted); } -void MachineIRBuilder::stopRecordingInsertions() { - InsertedInstr = nullptr; +void MachineIRBuilderBase::stopRecordingInsertions() { + State.InsertedInstr = nullptr; } //------------------------------------------------------------------------------ // Build instruction variants. //------------------------------------------------------------------------------ -MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opcode) { +MachineInstrBuilder MachineIRBuilderBase::buildInstr(unsigned Opcode) { return insertInstr(buildInstrNoInsert(Opcode)); } -MachineInstrBuilder MachineIRBuilder::buildInstrNoInsert(unsigned Opcode) { - MachineInstrBuilder MIB = BuildMI(getMF(), DL, getTII().get(Opcode)); +MachineInstrBuilder MachineIRBuilderBase::buildInstrNoInsert(unsigned Opcode) { + MachineInstrBuilder MIB = BuildMI(getMF(), getDL(), getTII().get(Opcode)); return MIB; } - -MachineInstrBuilder MachineIRBuilder::insertInstr(MachineInstrBuilder MIB) { +MachineInstrBuilder MachineIRBuilderBase::insertInstr(MachineInstrBuilder MIB) { getMBB().insert(getInsertPt(), MIB); - if (InsertedInstr) - InsertedInstr(MIB); + if (State.InsertedInstr) + State.InsertedInstr(MIB); return MIB; } MachineInstrBuilder -MachineIRBuilder::buildDirectDbgValue(unsigned Reg, const MDNode *Variable, - const MDNode *Expr) { +MachineIRBuilderBase::buildDirectDbgValue(unsigned Reg, const MDNode *Variable, + const MDNode *Expr) { assert(isa(Variable) && "not a variable"); assert(cast(Expr)->isValid() && "not an expression"); - assert(cast(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); - return insertInstr(BuildMI(getMF(), DL, getTII().get(TargetOpcode::DBG_VALUE), + assert( + cast(Variable)->isValidLocationForIntrinsic(getDL()) && + "Expected inlined-at fields to agree"); + return insertInstr(BuildMI(getMF(), getDL(), + getTII().get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ false, Reg, Variable, Expr)); } -MachineInstrBuilder -MachineIRBuilder::buildIndirectDbgValue(unsigned Reg, const MDNode *Variable, - const MDNode *Expr) { +MachineInstrBuilder MachineIRBuilderBase::buildIndirectDbgValue( + unsigned Reg, const MDNode *Variable, const MDNode *Expr) { assert(isa(Variable) && "not a variable"); assert(cast(Expr)->isValid() && "not an expression"); - assert(cast(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); - return insertInstr(BuildMI(getMF(), DL, getTII().get(TargetOpcode::DBG_VALUE), + assert( + cast(Variable)->isValidLocationForIntrinsic(getDL()) && + "Expected inlined-at fields to agree"); + return insertInstr(BuildMI(getMF(), getDL(), + getTII().get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true, Reg, Variable, Expr)); } -MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI, - const MDNode *Variable, - const MDNode *Expr) { +MachineInstrBuilder +MachineIRBuilderBase::buildFIDbgValue(int FI, const MDNode *Variable, + const MDNode *Expr) { assert(isa(Variable) && "not a variable"); assert(cast(Expr)->isValid() && "not an expression"); - assert(cast(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); + assert( + cast(Variable)->isValidLocationForIntrinsic(getDL()) && + "Expected inlined-at fields to agree"); return buildInstr(TargetOpcode::DBG_VALUE) .addFrameIndex(FI) .addImm(0) @@ -119,13 +122,13 @@ .addMetadata(Expr); } -MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C, - const MDNode *Variable, - const MDNode *Expr) { +MachineInstrBuilder MachineIRBuilderBase::buildConstDbgValue( + const Constant &C, const MDNode *Variable, const MDNode *Expr) { assert(isa(Variable) && "not a variable"); assert(cast(Expr)->isValid() && "not an expression"); - assert(cast(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); + assert( + cast(Variable)->isValidLocationForIntrinsic(getDL()) && + "Expected inlined-at fields to agree"); auto MIB = buildInstr(TargetOpcode::DBG_VALUE); if (auto *CI = dyn_cast(&C)) { if (CI->getBitWidth() > 64) @@ -142,17 +145,18 @@ return MIB.addImm(0).addMetadata(Variable).addMetadata(Expr); } -MachineInstrBuilder MachineIRBuilder::buildFrameIndex(unsigned Res, int Idx) { - assert(MRI->getType(Res).isPointer() && "invalid operand type"); +MachineInstrBuilder MachineIRBuilderBase::buildFrameIndex(unsigned Res, + int Idx) { + assert(getMRI()->getType(Res).isPointer() && "invalid operand type"); return buildInstr(TargetOpcode::G_FRAME_INDEX) .addDef(Res) .addFrameIndex(Idx); } -MachineInstrBuilder MachineIRBuilder::buildGlobalValue(unsigned Res, - const GlobalValue *GV) { - assert(MRI->getType(Res).isPointer() && "invalid operand type"); - assert(MRI->getType(Res).getAddressSpace() == +MachineInstrBuilder +MachineIRBuilderBase::buildGlobalValue(unsigned Res, const GlobalValue *GV) { + assert(getMRI()->getType(Res).isPointer() && "invalid operand type"); + assert(getMRI()->getType(Res).getAddressSpace() == GV->getType()->getAddressSpace() && "address space mismatch"); @@ -161,29 +165,20 @@ .addGlobalAddress(GV); } -MachineInstrBuilder MachineIRBuilder::buildBinaryOp(unsigned Opcode, unsigned Res, unsigned Op0, - unsigned Op1) { - assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) && +void MachineIRBuilderBase::validateBinaryOp(unsigned Res, unsigned Op0, + unsigned Op1) { + assert((getMRI()->getType(Res).isScalar() || + getMRI()->getType(Res).isVector()) && "invalid operand type"); - assert(MRI->getType(Res) == MRI->getType(Op0) && - MRI->getType(Res) == MRI->getType(Op1) && "type mismatch"); - - return buildInstr(Opcode) - .addDef(Res) - .addUse(Op0) - .addUse(Op1); -} - -MachineInstrBuilder MachineIRBuilder::buildAdd(unsigned Res, unsigned Op0, - unsigned Op1) { - return buildBinaryOp(TargetOpcode::G_ADD, Res, Op0, Op1); + assert(getMRI()->getType(Res) == getMRI()->getType(Op0) && + getMRI()->getType(Res) == getMRI()->getType(Op1) && "type mismatch"); } -MachineInstrBuilder MachineIRBuilder::buildGEP(unsigned Res, unsigned Op0, - unsigned Op1) { - assert(MRI->getType(Res).isPointer() && - MRI->getType(Res) == MRI->getType(Op0) && "type mismatch"); - assert(MRI->getType(Op1).isScalar() && "invalid offset type"); +MachineInstrBuilder MachineIRBuilderBase::buildGEP(unsigned Res, unsigned Op0, + unsigned Op1) { + assert(getMRI()->getType(Res).isPointer() && + getMRI()->getType(Res) == getMRI()->getType(Op0) && "type mismatch"); + assert(getMRI()->getType(Op1).isScalar() && "invalid offset type"); return buildInstr(TargetOpcode::G_GEP) .addDef(Res) @@ -192,8 +187,8 @@ } Optional -MachineIRBuilder::materializeGEP(unsigned &Res, unsigned Op0, - const LLT &ValueTy, uint64_t Value) { +MachineIRBuilderBase::materializeGEP(unsigned &Res, unsigned Op0, + const LLT &ValueTy, uint64_t Value) { assert(Res == 0 && "Res is a result argument"); assert(ValueTy.isScalar() && "invalid offset type"); @@ -202,17 +197,18 @@ return None; } - Res = MRI->createGenericVirtualRegister(MRI->getType(Op0)); - unsigned TmpReg = MRI->createGenericVirtualRegister(ValueTy); + Res = getMRI()->createGenericVirtualRegister(getMRI()->getType(Op0)); + unsigned TmpReg = getMRI()->createGenericVirtualRegister(ValueTy); buildConstant(TmpReg, Value); return buildGEP(Res, Op0, TmpReg); } -MachineInstrBuilder MachineIRBuilder::buildPtrMask(unsigned Res, unsigned Op0, - uint32_t NumBits) { - assert(MRI->getType(Res).isPointer() && - MRI->getType(Res) == MRI->getType(Op0) && "type mismatch"); +MachineInstrBuilder MachineIRBuilderBase::buildPtrMask(unsigned Res, + unsigned Op0, + uint32_t NumBits) { + assert(getMRI()->getType(Res).isPointer() && + getMRI()->getType(Res) == getMRI()->getType(Op0) && "type mismatch"); return buildInstr(TargetOpcode::G_PTR_MASK) .addDef(Res) @@ -220,89 +216,70 @@ .addImm(NumBits); } -MachineInstrBuilder MachineIRBuilder::buildSub(unsigned Res, unsigned Op0, - unsigned Op1) { - return buildBinaryOp(TargetOpcode::G_SUB, Res, Op0, Op1); -} - -MachineInstrBuilder MachineIRBuilder::buildMul(unsigned Res, unsigned Op0, - unsigned Op1) { - return buildBinaryOp(TargetOpcode::G_MUL, Res, Op0, Op1); -} - -MachineInstrBuilder MachineIRBuilder::buildAnd(unsigned Res, unsigned Op0, - unsigned Op1) { - return buildBinaryOp(TargetOpcode::G_AND, Res, Op0, Op1); -} - -MachineInstrBuilder MachineIRBuilder::buildOr(unsigned Res, unsigned Op0, - unsigned Op1) { - return buildBinaryOp(TargetOpcode::G_OR, Res, Op0, Op1); -} - -MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) { +MachineInstrBuilder MachineIRBuilderBase::buildBr(MachineBasicBlock &Dest) { return buildInstr(TargetOpcode::G_BR).addMBB(&Dest); } -MachineInstrBuilder MachineIRBuilder::buildBrIndirect(unsigned Tgt) { - assert(MRI->getType(Tgt).isPointer() && "invalid branch destination"); +MachineInstrBuilder MachineIRBuilderBase::buildBrIndirect(unsigned Tgt) { + assert(getMRI()->getType(Tgt).isPointer() && "invalid branch destination"); return buildInstr(TargetOpcode::G_BRINDIRECT).addUse(Tgt); } -MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) { - assert(MRI->getType(Res) == LLT() || MRI->getType(Op) == LLT() || - MRI->getType(Res) == MRI->getType(Op)); +MachineInstrBuilder MachineIRBuilderBase::buildCopy(unsigned Res, unsigned Op) { + assert(getMRI()->getType(Res) == LLT() || getMRI()->getType(Op) == LLT() || + getMRI()->getType(Res) == getMRI()->getType(Op)); return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, - const ConstantInt &Val) { - LLT Ty = MRI->getType(Res); +MachineInstrBuilder +MachineIRBuilderBase::buildConstant(unsigned Res, const ConstantInt &Val) { + LLT Ty = getMRI()->getType(Res); assert((Ty.isScalar() || Ty.isPointer()) && "invalid operand type"); const ConstantInt *NewVal = &Val; if (Ty.getSizeInBits() != Val.getBitWidth()) - NewVal = ConstantInt::get(MF->getFunction().getContext(), + NewVal = ConstantInt::get(getMF().getFunction().getContext(), Val.getValue().sextOrTrunc(Ty.getSizeInBits())); return buildInstr(TargetOpcode::G_CONSTANT).addDef(Res).addCImm(NewVal); } -MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, - int64_t Val) { - auto IntN = IntegerType::get(MF->getFunction().getContext(), - MRI->getType(Res).getSizeInBits()); +MachineInstrBuilder MachineIRBuilderBase::buildConstant(unsigned Res, + int64_t Val) { + auto IntN = IntegerType::get(getMF().getFunction().getContext(), + getMRI()->getType(Res).getSizeInBits()); ConstantInt *CI = ConstantInt::get(IntN, Val, true); return buildConstant(Res, *CI); } -MachineInstrBuilder MachineIRBuilder::buildFConstant(unsigned Res, - const ConstantFP &Val) { - assert(MRI->getType(Res).isScalar() && "invalid operand type"); +MachineInstrBuilder +MachineIRBuilderBase::buildFConstant(unsigned Res, const ConstantFP &Val) { + assert(getMRI()->getType(Res).isScalar() && "invalid operand type"); return buildInstr(TargetOpcode::G_FCONSTANT).addDef(Res).addFPImm(&Val); } -MachineInstrBuilder MachineIRBuilder::buildFConstant(unsigned Res, double Val) { - LLT DstTy = MRI->getType(Res); - auto &Ctx = MF->getFunction().getContext(); +MachineInstrBuilder MachineIRBuilderBase::buildFConstant(unsigned Res, + double Val) { + LLT DstTy = getMRI()->getType(Res); + auto &Ctx = getMF().getFunction().getContext(); auto *CFP = ConstantFP::get(Ctx, getAPFloatFromSize(Val, DstTy.getSizeInBits())); return buildFConstant(Res, *CFP); } -MachineInstrBuilder MachineIRBuilder::buildBrCond(unsigned Tst, - MachineBasicBlock &Dest) { - assert(MRI->getType(Tst).isScalar() && "invalid operand type"); +MachineInstrBuilder MachineIRBuilderBase::buildBrCond(unsigned Tst, + MachineBasicBlock &Dest) { + assert(getMRI()->getType(Tst).isScalar() && "invalid operand type"); return buildInstr(TargetOpcode::G_BRCOND).addUse(Tst).addMBB(&Dest); } -MachineInstrBuilder MachineIRBuilder::buildLoad(unsigned Res, unsigned Addr, - MachineMemOperand &MMO) { - assert(MRI->getType(Res).isValid() && "invalid operand type"); - assert(MRI->getType(Addr).isPointer() && "invalid operand type"); +MachineInstrBuilder MachineIRBuilderBase::buildLoad(unsigned Res, unsigned Addr, + MachineMemOperand &MMO) { + assert(getMRI()->getType(Res).isValid() && "invalid operand type"); + assert(getMRI()->getType(Addr).isPointer() && "invalid operand type"); return buildInstr(TargetOpcode::G_LOAD) .addDef(Res) @@ -310,10 +287,11 @@ .addMemOperand(&MMO); } -MachineInstrBuilder MachineIRBuilder::buildStore(unsigned Val, unsigned Addr, - MachineMemOperand &MMO) { - assert(MRI->getType(Val).isValid() && "invalid operand type"); - assert(MRI->getType(Addr).isPointer() && "invalid operand type"); +MachineInstrBuilder MachineIRBuilderBase::buildStore(unsigned Val, + unsigned Addr, + MachineMemOperand &MMO) { + assert(getMRI()->getType(Val).isValid() && "invalid operand type"); + assert(getMRI()->getType(Addr).isPointer() && "invalid operand type"); return buildInstr(TargetOpcode::G_STORE) .addUse(Val) @@ -321,15 +299,16 @@ .addMemOperand(&MMO); } -MachineInstrBuilder MachineIRBuilder::buildUAdde(unsigned Res, - unsigned CarryOut, - unsigned Op0, unsigned Op1, - unsigned CarryIn) { - assert(MRI->getType(Res).isScalar() && "invalid operand type"); - assert(MRI->getType(Res) == MRI->getType(Op0) && - MRI->getType(Res) == MRI->getType(Op1) && "type mismatch"); - assert(MRI->getType(CarryOut).isScalar() && "invalid operand type"); - assert(MRI->getType(CarryOut) == MRI->getType(CarryIn) && "type mismatch"); +MachineInstrBuilder MachineIRBuilderBase::buildUAdde(unsigned Res, + unsigned CarryOut, + unsigned Op0, unsigned Op1, + unsigned CarryIn) { + assert(getMRI()->getType(Res).isScalar() && "invalid operand type"); + assert(getMRI()->getType(Res) == getMRI()->getType(Op0) && + getMRI()->getType(Res) == getMRI()->getType(Op1) && "type mismatch"); + assert(getMRI()->getType(CarryOut).isScalar() && "invalid operand type"); + assert(getMRI()->getType(CarryOut) == getMRI()->getType(CarryIn) && + "type mismatch"); return buildInstr(TargetOpcode::G_UADDE) .addDef(Res) @@ -339,58 +318,64 @@ .addUse(CarryIn); } -MachineInstrBuilder MachineIRBuilder::buildAnyExt(unsigned Res, unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildAnyExt(unsigned Res, + unsigned Op) { validateTruncExt(Res, Op, true); return buildInstr(TargetOpcode::G_ANYEXT).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildSExt(unsigned Res, unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildSExt(unsigned Res, unsigned Op) { validateTruncExt(Res, Op, true); return buildInstr(TargetOpcode::G_SEXT).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildZExt(unsigned Res, unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildZExt(unsigned Res, unsigned Op) { validateTruncExt(Res, Op, true); return buildInstr(TargetOpcode::G_ZEXT).addDef(Res).addUse(Op); } -MachineInstrBuilder -MachineIRBuilder::buildExtOrTrunc(unsigned ExtOpc, unsigned Res, unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildExtOrTrunc(unsigned ExtOpc, + unsigned Res, + unsigned Op) { assert((TargetOpcode::G_ANYEXT == ExtOpc || TargetOpcode::G_ZEXT == ExtOpc || TargetOpcode::G_SEXT == ExtOpc) && "Expecting Extending Opc"); - assert(MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()); - assert(MRI->getType(Res).isScalar() == MRI->getType(Op).isScalar()); + assert(getMRI()->getType(Res).isScalar() || + getMRI()->getType(Res).isVector()); + assert(getMRI()->getType(Res).isScalar() == getMRI()->getType(Op).isScalar()); unsigned Opcode = TargetOpcode::COPY; - if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits()) + if (getMRI()->getType(Res).getSizeInBits() > + getMRI()->getType(Op).getSizeInBits()) Opcode = ExtOpc; - else if (MRI->getType(Res).getSizeInBits() < MRI->getType(Op).getSizeInBits()) + else if (getMRI()->getType(Res).getSizeInBits() < + getMRI()->getType(Op).getSizeInBits()) Opcode = TargetOpcode::G_TRUNC; else - assert(MRI->getType(Res) == MRI->getType(Op)); + assert(getMRI()->getType(Res) == getMRI()->getType(Op)); return buildInstr(Opcode).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res, - unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildSExtOrTrunc(unsigned Res, + unsigned Op) { return buildExtOrTrunc(TargetOpcode::G_SEXT, Res, Op); } -MachineInstrBuilder MachineIRBuilder::buildZExtOrTrunc(unsigned Res, - unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildZExtOrTrunc(unsigned Res, + unsigned Op) { return buildExtOrTrunc(TargetOpcode::G_ZEXT, Res, Op); } -MachineInstrBuilder MachineIRBuilder::buildAnyExtOrTrunc(unsigned Res, - unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildAnyExtOrTrunc(unsigned Res, + unsigned Op) { return buildExtOrTrunc(TargetOpcode::G_ANYEXT, Res, Op); } -MachineInstrBuilder MachineIRBuilder::buildCast(unsigned Dst, unsigned Src) { - LLT SrcTy = MRI->getType(Src); - LLT DstTy = MRI->getType(Dst); +MachineInstrBuilder MachineIRBuilderBase::buildCast(unsigned Dst, + unsigned Src) { + LLT SrcTy = getMRI()->getType(Src); + LLT DstTy = getMRI()->getType(Dst); if (SrcTy == DstTy) return buildCopy(Dst, Src); @@ -407,17 +392,18 @@ return buildInstr(Opcode).addDef(Dst).addUse(Src); } -MachineInstrBuilder MachineIRBuilder::buildExtract(unsigned Res, unsigned Src, - uint64_t Index) { +MachineInstrBuilder +MachineIRBuilderBase::buildExtract(unsigned Res, unsigned Src, uint64_t Index) { #ifndef NDEBUG - assert(MRI->getType(Src).isValid() && "invalid operand type"); - assert(MRI->getType(Res).isValid() && "invalid operand type"); - assert(Index + MRI->getType(Res).getSizeInBits() <= - MRI->getType(Src).getSizeInBits() && + assert(getMRI()->getType(Src).isValid() && "invalid operand type"); + assert(getMRI()->getType(Res).isValid() && "invalid operand type"); + assert(Index + getMRI()->getType(Res).getSizeInBits() <= + getMRI()->getType(Src).getSizeInBits() && "extracting off end of register"); #endif - if (MRI->getType(Res).getSizeInBits() == MRI->getType(Src).getSizeInBits()) { + if (getMRI()->getType(Res).getSizeInBits() == + getMRI()->getType(Src).getSizeInBits()) { assert(Index == 0 && "insertion past the end of a register"); return buildCast(Res, Src); } @@ -428,25 +414,25 @@ .addImm(Index); } -void MachineIRBuilder::buildSequence(unsigned Res, ArrayRef Ops, - ArrayRef Indices) { +void MachineIRBuilderBase::buildSequence(unsigned Res, ArrayRef Ops, + ArrayRef Indices) { #ifndef NDEBUG assert(Ops.size() == Indices.size() && "incompatible args"); assert(!Ops.empty() && "invalid trivial sequence"); assert(std::is_sorted(Indices.begin(), Indices.end()) && "sequence offsets must be in ascending order"); - assert(MRI->getType(Res).isValid() && "invalid operand type"); + assert(getMRI()->getType(Res).isValid() && "invalid operand type"); for (auto Op : Ops) - assert(MRI->getType(Op).isValid() && "invalid operand type"); + assert(getMRI()->getType(Op).isValid() && "invalid operand type"); #endif - LLT ResTy = MRI->getType(Res); - LLT OpTy = MRI->getType(Ops[0]); + LLT ResTy = getMRI()->getType(Res); + LLT OpTy = getMRI()->getType(Ops[0]); unsigned OpSize = OpTy.getSizeInBits(); bool MaybeMerge = true; for (unsigned i = 0; i < Ops.size(); ++i) { - if (MRI->getType(Ops[i]) != OpTy || Indices[i] != i * OpSize) { + if (getMRI()->getType(Ops[i]) != OpTy || Indices[i] != i * OpSize) { MaybeMerge = false; break; } @@ -457,31 +443,32 @@ return; } - unsigned ResIn = MRI->createGenericVirtualRegister(ResTy); + unsigned ResIn = getMRI()->createGenericVirtualRegister(ResTy); buildUndef(ResIn); for (unsigned i = 0; i < Ops.size(); ++i) { - unsigned ResOut = - i + 1 == Ops.size() ? Res : MRI->createGenericVirtualRegister(ResTy); + unsigned ResOut = i + 1 == Ops.size() + ? Res + : getMRI()->createGenericVirtualRegister(ResTy); buildInsert(ResOut, ResIn, Ops[i], Indices[i]); ResIn = ResOut; } } -MachineInstrBuilder MachineIRBuilder::buildUndef(unsigned Res) { +MachineInstrBuilder MachineIRBuilderBase::buildUndef(unsigned Res) { return buildInstr(TargetOpcode::G_IMPLICIT_DEF).addDef(Res); } -MachineInstrBuilder MachineIRBuilder::buildMerge(unsigned Res, - ArrayRef Ops) { +MachineInstrBuilder MachineIRBuilderBase::buildMerge(unsigned Res, + ArrayRef Ops) { #ifndef NDEBUG assert(!Ops.empty() && "invalid trivial sequence"); - LLT Ty = MRI->getType(Ops[0]); + LLT Ty = getMRI()->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() && + assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list"); + assert(Ops.size() * getMRI()->getType(Ops[0]).getSizeInBits() == + getMRI()->getType(Res).getSizeInBits() && "input operands do not cover output register"); #endif @@ -495,16 +482,16 @@ return MIB; } -MachineInstrBuilder MachineIRBuilder::buildUnmerge(ArrayRef Res, - unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildUnmerge(ArrayRef Res, + unsigned Op) { #ifndef NDEBUG assert(!Res.empty() && "invalid trivial sequence"); - LLT Ty = MRI->getType(Res[0]); + LLT Ty = getMRI()->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() && + assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list"); + assert(Res.size() * getMRI()->getType(Res[0]).getSizeInBits() == + getMRI()->getType(Op).getSizeInBits() && "input operands do not cover output register"); #endif @@ -515,13 +502,15 @@ return MIB; } -MachineInstrBuilder MachineIRBuilder::buildInsert(unsigned Res, unsigned Src, - unsigned Op, unsigned Index) { - assert(Index + MRI->getType(Op).getSizeInBits() <= - MRI->getType(Res).getSizeInBits() && +MachineInstrBuilder MachineIRBuilderBase::buildInsert(unsigned Res, + unsigned Src, unsigned Op, + unsigned Index) { + assert(Index + getMRI()->getType(Op).getSizeInBits() <= + getMRI()->getType(Res).getSizeInBits() && "insertion past the end of a register"); - if (MRI->getType(Res).getSizeInBits() == MRI->getType(Op).getSizeInBits()) { + if (getMRI()->getType(Res).getSizeInBits() == + getMRI()->getType(Op).getSizeInBits()) { return buildCast(Res, Op); } @@ -532,9 +521,9 @@ .addImm(Index); } -MachineInstrBuilder MachineIRBuilder::buildIntrinsic(Intrinsic::ID ID, - unsigned Res, - bool HasSideEffects) { +MachineInstrBuilder MachineIRBuilderBase::buildIntrinsic(Intrinsic::ID ID, + unsigned Res, + bool HasSideEffects) { auto MIB = buildInstr(HasSideEffects ? TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS : TargetOpcode::G_INTRINSIC); @@ -544,28 +533,30 @@ return MIB; } -MachineInstrBuilder MachineIRBuilder::buildTrunc(unsigned Res, unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildTrunc(unsigned Res, + unsigned Op) { validateTruncExt(Res, Op, false); return buildInstr(TargetOpcode::G_TRUNC).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildFPTrunc(unsigned Res, unsigned Op) { +MachineInstrBuilder MachineIRBuilderBase::buildFPTrunc(unsigned Res, + unsigned Op) { validateTruncExt(Res, Op, false); return buildInstr(TargetOpcode::G_FPTRUNC).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildICmp(CmpInst::Predicate Pred, - unsigned Res, unsigned Op0, - unsigned Op1) { +MachineInstrBuilder MachineIRBuilderBase::buildICmp(CmpInst::Predicate Pred, + unsigned Res, unsigned Op0, + unsigned Op1) { #ifndef NDEBUG - assert(MRI->getType(Op0) == MRI->getType(Op0) && "type mismatch"); + assert(getMRI()->getType(Op0) == getMRI()->getType(Op0) && "type mismatch"); assert(CmpInst::isIntPredicate(Pred) && "invalid predicate"); - if (MRI->getType(Op0).isScalar() || MRI->getType(Op0).isPointer()) - assert(MRI->getType(Res).isScalar() && "type mismatch"); + if (getMRI()->getType(Op0).isScalar() || getMRI()->getType(Op0).isPointer()) + assert(getMRI()->getType(Res).isScalar() && "type mismatch"); else - assert(MRI->getType(Res).isVector() && - MRI->getType(Res).getNumElements() == - MRI->getType(Op0).getNumElements() && + assert(getMRI()->getType(Res).isVector() && + getMRI()->getType(Res).getNumElements() == + getMRI()->getType(Op0).getNumElements() && "type mismatch"); #endif @@ -576,20 +567,21 @@ .addUse(Op1); } -MachineInstrBuilder MachineIRBuilder::buildFCmp(CmpInst::Predicate Pred, - unsigned Res, unsigned Op0, - unsigned Op1) { +MachineInstrBuilder MachineIRBuilderBase::buildFCmp(CmpInst::Predicate Pred, + unsigned Res, unsigned Op0, + unsigned Op1) { #ifndef NDEBUG - assert((MRI->getType(Op0).isScalar() || MRI->getType(Op0).isVector()) && + assert((getMRI()->getType(Op0).isScalar() || + getMRI()->getType(Op0).isVector()) && "invalid operand type"); - assert(MRI->getType(Op0) == MRI->getType(Op1) && "type mismatch"); + assert(getMRI()->getType(Op0) == getMRI()->getType(Op1) && "type mismatch"); assert(CmpInst::isFPPredicate(Pred) && "invalid predicate"); - if (MRI->getType(Op0).isScalar()) - assert(MRI->getType(Res).isScalar() && "type mismatch"); + if (getMRI()->getType(Op0).isScalar()) + assert(getMRI()->getType(Res).isScalar() && "type mismatch"); else - assert(MRI->getType(Res).isVector() && - MRI->getType(Res).getNumElements() == - MRI->getType(Op0).getNumElements() && + assert(getMRI()->getType(Res).isVector() && + getMRI()->getType(Res).getNumElements() == + getMRI()->getType(Op0).getNumElements() && "type mismatch"); #endif @@ -600,21 +592,23 @@ .addUse(Op1); } -MachineInstrBuilder MachineIRBuilder::buildSelect(unsigned Res, unsigned Tst, - unsigned Op0, unsigned Op1) { +MachineInstrBuilder MachineIRBuilderBase::buildSelect(unsigned Res, + unsigned Tst, + unsigned Op0, + unsigned Op1) { #ifndef NDEBUG - LLT ResTy = MRI->getType(Res); + LLT ResTy = getMRI()->getType(Res); assert((ResTy.isScalar() || ResTy.isVector() || ResTy.isPointer()) && "invalid operand type"); - assert(ResTy == MRI->getType(Op0) && ResTy == MRI->getType(Op1) && + assert(ResTy == getMRI()->getType(Op0) && ResTy == getMRI()->getType(Op1) && "type mismatch"); if (ResTy.isScalar() || ResTy.isPointer()) - assert(MRI->getType(Tst).isScalar() && "type mismatch"); + assert(getMRI()->getType(Tst).isScalar() && "type mismatch"); else - assert((MRI->getType(Tst).isScalar() || - (MRI->getType(Tst).isVector() && - MRI->getType(Tst).getNumElements() == - MRI->getType(Op0).getNumElements())) && + assert((getMRI()->getType(Tst).isScalar() || + (getMRI()->getType(Tst).isVector() && + getMRI()->getType(Tst).getNumElements() == + getMRI()->getType(Op0).getNumElements())) && "type mismatch"); #endif @@ -625,15 +619,14 @@ .addUse(Op1); } -MachineInstrBuilder MachineIRBuilder::buildInsertVectorElement(unsigned Res, - unsigned Val, - unsigned Elt, - unsigned Idx) { +MachineInstrBuilder +MachineIRBuilderBase::buildInsertVectorElement(unsigned Res, unsigned Val, + unsigned Elt, unsigned Idx) { #ifndef NDEBUG - LLT ResTy = MRI->getType(Res); - LLT ValTy = MRI->getType(Val); - LLT EltTy = MRI->getType(Elt); - LLT IdxTy = MRI->getType(Idx); + LLT ResTy = getMRI()->getType(Res); + LLT ValTy = getMRI()->getType(Val); + LLT EltTy = getMRI()->getType(Elt); + LLT IdxTy = getMRI()->getType(Idx); assert(ResTy.isVector() && ValTy.isVector() && "invalid operand type"); assert(IdxTy.isScalar() && "invalid operand type"); assert(ResTy.getNumElements() == ValTy.getNumElements() && "type mismatch"); @@ -647,13 +640,13 @@ .addUse(Idx); } -MachineInstrBuilder MachineIRBuilder::buildExtractVectorElement(unsigned Res, - unsigned Val, - unsigned Idx) { +MachineInstrBuilder +MachineIRBuilderBase::buildExtractVectorElement(unsigned Res, unsigned Val, + unsigned Idx) { #ifndef NDEBUG - LLT ResTy = MRI->getType(Res); - LLT ValTy = MRI->getType(Val); - LLT IdxTy = MRI->getType(Idx); + LLT ResTy = getMRI()->getType(Res); + LLT ValTy = getMRI()->getType(Val); + LLT IdxTy = getMRI()->getType(Idx); assert(ValTy.isVector() && "invalid operand type"); assert((ResTy.isScalar() || ResTy.isPointer()) && "invalid operand type"); assert(IdxTy.isScalar() && "invalid operand type"); @@ -667,14 +660,14 @@ } MachineInstrBuilder -MachineIRBuilder::buildAtomicCmpXchg(unsigned OldValRes, unsigned Addr, - unsigned CmpVal, unsigned NewVal, - MachineMemOperand &MMO) { +MachineIRBuilderBase::buildAtomicCmpXchg(unsigned OldValRes, unsigned Addr, + unsigned CmpVal, unsigned NewVal, + MachineMemOperand &MMO) { #ifndef NDEBUG - LLT OldValResTy = MRI->getType(OldValRes); - LLT AddrTy = MRI->getType(Addr); - LLT CmpValTy = MRI->getType(CmpVal); - LLT NewValTy = MRI->getType(NewVal); + LLT OldValResTy = getMRI()->getType(OldValRes); + LLT AddrTy = getMRI()->getType(Addr); + LLT CmpValTy = getMRI()->getType(CmpVal); + LLT NewValTy = getMRI()->getType(NewVal); assert(OldValResTy.isScalar() && "invalid operand type"); assert(AddrTy.isPointer() && "invalid operand type"); assert(CmpValTy.isValid() && "invalid operand type"); @@ -691,11 +684,11 @@ .addMemOperand(&MMO); } -void MachineIRBuilder::validateTruncExt(unsigned Dst, unsigned Src, - bool IsExtend) { +void MachineIRBuilderBase::validateTruncExt(unsigned Dst, unsigned Src, + bool IsExtend) { #ifndef NDEBUG - LLT SrcTy = MRI->getType(Src); - LLT DstTy = MRI->getType(Dst); + LLT SrcTy = getMRI()->getType(Src); + LLT DstTy = getMRI()->getType(Dst); if (DstTy.isVector()) { assert(SrcTy.isVector() && "mismatched cast between vecot and non-vector"); Index: unittests/CodeGen/GlobalISel/PatternMatchTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/PatternMatchTest.cpp +++ unittests/CodeGen/GlobalISel/PatternMatchTest.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h" #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Utils.h" @@ -228,6 +229,35 @@ ASSERT_TRUE(match); ASSERT_EQ(Src0, Copies[0]); ASSERT_EQ(Src1, Copies[1]); + + // Try to use the FoldableInstructionsBuilder to build binary ops. + ConstantFoldingMIRBuilder CFB(B.getState()); + LLT s32 = LLT::scalar(32); + auto MIBCAdd = + CFB.buildAdd(s32, CFB.buildConstant(s32, 0), CFB.buildConstant(s32, 1)); + // This should be a constant now. + match = mi_match(MIBCAdd->getOperand(0).getReg(), MRI, m_ICst(Cst)); + ASSERT_TRUE(match); + ASSERT_EQ(Cst, 1); + auto MIBCAdd1 = + CFB.buildInstr(TargetOpcode::G_ADD, s32, CFB.buildConstant(s32, 0), + CFB.buildConstant(s32, 1)); + // This should be a constant now. + match = mi_match(MIBCAdd1->getOperand(0).getReg(), MRI, m_ICst(Cst)); + ASSERT_TRUE(match); + ASSERT_EQ(Cst, 1); + + // Try one of the other constructors of MachineIRBuilder to make sure it's + // compatible. + ConstantFoldingMIRBuilder CFB1(*MF); + CFB1.setInsertPt(*EntryMBB, EntryMBB->end()); + auto MIBCSub = + CFB1.buildInstr(TargetOpcode::G_SUB, s32, CFB1.buildConstant(s32, 1), + CFB1.buildConstant(s32, 1)); + // This should be a constant now. + match = mi_match(MIBCSub->getOperand(0).getReg(), MRI, m_ICst(Cst)); + ASSERT_TRUE(match); + ASSERT_EQ(Cst, 0); } TEST(PatternMatchInstr, MatchFPUnaryOp) {