Index: include/llvm/CodeGen/GlobalISel/CSEInfo.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/CSEInfo.h @@ -0,0 +1,206 @@ +//===- llvm/CodeGen/GlobalISel/CSEInfo.h ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Provides analysis for continuously CSEing during GISel passes. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CODEGEN_GLOBALISEL_CSEINFO_H +#define LLVM_CODEGEN_GLOBALISEL_CSEINFO_H + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/CodeGen/GlobalISel/GISelWorkList.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Support/Allocator.h" + +namespace llvm { + +/// A class that wraps MachineInstrs and derives from FoldingSetNode in order to +/// be uniqued in a CSEMap. The tradeoff here is extra memory allocations for +/// UniqueMachineInstr vs making MachineInstr bigger. +class UniqueMachineInstr : public FoldingSetNode { + friend class GISelCSEInfo; + const MachineInstr *MI; + explicit UniqueMachineInstr(const MachineInstr *MI) : MI(MI) {} + +public: + void Profile(FoldingSetNodeID &ID); +}; + +/// 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 +/// track instruction mutations. In such cases, recordNewInstruction should be +/// called (for eg inside MachineIRBuilder::recordInsertion). +/// Also because of how just the instruction can be inserted without adding any +/// operands to the instruction, instructions are uniqued and inserted lazily. +/// CSEInfo should assert when trying to enter an incomplete instruction into +/// the CSEMap. There is Opcode level granularity on which instructions can be +/// CSE'd and for now, only Generic instructions are CSEable. +class GISelCSEInfo : public MachineFunction::Delegate { + // Make it accessible only to CSEMIRBuilder. + friend class CSEMIRBuilder; + + BumpPtrAllocator UniqueInstrAllocator; + FoldingSet CSEMap; + MachineRegisterInfo *MRI = nullptr; + MachineFunction *MF = nullptr; + using ShouldCSECallBackTy = std::function; + ShouldCSECallBackTy ShouldCSEFn; + + /// Keep a cache of UniqueInstrs for each MachineInstr. In GISel, + /// often instructions are mutated (while their ID has completely changed). + /// Whenever mutation happens, invalidate the UniqueMachineInstr for the + /// MachineInstr + DenseMap InstrMapping; + + /// Store instructions that are not fully formed in TemporaryInsts. + /// Also because CSE insertion happens lazily, we can remove insts from this + /// list and avoid inserting and then removing from the CSEMap. + GISelWorkList<8> TemporaryInsts; + + // Only used in asserts. + DenseMap OpcodeHitTable; + + bool isUniqueMachineInstValid(const UniqueMachineInstr &UMI) const; + + void invalidateUniqueMachineInstr(UniqueMachineInstr *UMI); + + UniqueMachineInstr *getNodeIfExists(FoldingSetNodeID &ID, + MachineBasicBlock *MBB, void *&InsertPos); + + /// Allocate and construct a new UniqueMachineInstr for MI and return. + UniqueMachineInstr *getUniqueInstrForMI(const MachineInstr *MI); + + void insertNode(UniqueMachineInstr *UMI, void *InsertPos = nullptr); + + void MF_HandleInsertion(const MachineInstr &MI) override; + void MF_HandleRemoval(const MachineInstr &MI) override; + + /// Get the MachineInstr(Unique) if it exists already in the CSEMap and the + /// same MachineBasicBlock. + MachineInstr *getMachineInstrIfExists(FoldingSetNodeID &ID, + MachineBasicBlock *MBB, + void *&InsertPos); + + /// Use this method to allocate a new UniqueMachineInstr for MI and insert it + /// into the CSEMap. MI should return true for shouldCSE(MI->getOpcode()) + void insertInstr(MachineInstr *MI, void *InsertPos = nullptr); + +public: + GISelCSEInfo() = default; + + virtual ~GISelCSEInfo(); + + void setMF(MachineFunction &MF); + + /// Records a newly created inst in a list and lazily insert it to the CSEMap. + /// Sometimes, this method might be called with a partially constructed + /// MachineInstr, + // (right after BuildMI without adding any operands) - and in such cases, + // defer the hashing of the instruction to a later stage. + void recordNewInstruction(MachineInstr *MI); + + /// Use this callback to inform CSE about a newly fully created instruction. + void handleRecordedInst(MachineInstr *MI); + + /// Use this callback to insert all the recorded instructions. At this point, + /// all of these insts need to be fully constructed and should not be missing + /// any operands. + void handleRecordedInsts(); + + /// Remove this inst from the CSE map. If this inst has not been inserted yet, + /// it will be removed from the Tempinsts list if it exists. + void handleRemoveInst(MachineInstr *MI); + + void releaseMemory(); + + void setShouldCSECallback(ShouldCSECallBackTy Fn) { + ShouldCSEFn = std::move(Fn); + } + + bool shouldCSE(unsigned Opc); + + void analyze(MachineFunction &MF); + + void countOpcodeHit(unsigned Opc); + + void print(); +}; + +/// A simple RAII based CSEInfo installer. +/// Use this in a scope to install a delegate to the MachineFunction and reset +/// it at the end of the scope. +class RAIIDelegateInstaller { + MachineFunction &MF; + MachineFunction::Delegate *Delegate; + +public: + RAIIDelegateInstaller(MachineFunction &MF, MachineFunction::Delegate *Del); + ~RAIIDelegateInstaller(); +}; + +class TargetRegisterClass; +class RegisterBank; + +// Simple builder class to easily profile properties about MIs. +class GISelInstProfileBuilder { + FoldingSetNodeID &ID; + const MachineRegisterInfo &MRI; + +public: + GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI) + : ID(ID), MRI(MRI) {} + // 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 TargetRegisterClass *RC) const; + const GISelInstProfileBuilder &addNodeIDRegType(const RegisterBank *RB) const; + + const GISelInstProfileBuilder &addNodeIDRegNum(unsigned Reg) const; + + const GISelInstProfileBuilder &addNodeIDImmediate(int64_t Imm) const; + const GISelInstProfileBuilder & + addNodeIDMBB(const MachineBasicBlock *MBB) const; + + const GISelInstProfileBuilder & + addNodeIDMachineOperand(const MachineOperand &MO) const; + + const GISelInstProfileBuilder &addNodeID(const MachineInstr *MI) const; +}; + +/// The actual analysis pass wrapper. +class GISelCSEAnalysisWrapperPass : public MachineFunctionPass { + GISelCSEInfo Info; + +public: + static char ID; + GISelCSEAnalysisWrapperPass() : MachineFunctionPass(ID) { + initializeGISelCSEAnalysisWrapperPassPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + GISelCSEInfo &getCSEInfo() { return Info; } + const GISelCSEInfo &getCSEInfo() const { return Info; } + + bool runOnMachineFunction(MachineFunction &MF) override; + + void releaseMemory() override { Info.releaseMemory(); } +}; + +} // namespace llvm + +#endif Index: include/llvm/CodeGen/GlobalISel/CSEMIRBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/CSEMIRBuilder.h @@ -0,0 +1,433 @@ +//===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.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 CSEs insts within +/// a MachineBasicBlock. +//===----------------------------------------------------------------------===// +#ifndef LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H +#define LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H + +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" + +namespace llvm { + +/// Defines a builder that does CSE of MachineInstructions using GISelCSEInfo. +/// Eg usage. +/// +/// +/// GISelCSEInfo *Info = +/// &getAnalysis().getCSEInfo(); CSEMIRBuilder +/// CB(Builder.getState()); // Create CB. CB.setCSEInfo(Info); // If not +/// already done. auto A = CB.buildConstant(s32, 42); auto B = +/// CB.buildConstant(s32, 42); assert(A == B); unsigned CReg = +/// MRI.createGenericVirtualRegister(s32); auto C = CB.buildConstant(CReg, 42); +/// // Explicitly passing in a register would materialize a copy if possible. +/// CSEMIRBuilder also does trivial constant folding for binary ops. +class CSEMIRBuilder : public FoldableInstructionsBuilder { + + /// Returns true if A dominates B (within the same basic block). + /// Both iterators must be in the same basic block. + // + // TODO: Another approach for checking dominance is having two iterators and + // making them go towards each other until they meet or reach begin/end. Which + // approach is better? Should this even change dynamically? For G_CONSTANTS + // most of which will be at the top of the BB, the top down approach would be + // a better choice. Does IRTranslator placing constants at the beginning still + // make sense? Should this change based on Opcode? + bool dominates(MachineBasicBlock::const_iterator A, + MachineBasicBlock::const_iterator B) const { + assert(A->getParent() == B->getParent() && + "Iterators should be in same block"); + const MachineBasicBlock *BBA = A->getParent(); + MachineBasicBlock::const_iterator I = BBA->begin(); + for (; &*I != A && &*I != B; ++I) + ; + return &*I == A; + } + + template + MachineInstrBuilder buildCopyIfRequired(MachineInstr *MI, T) { + // No need to build copy here. + return MachineInstrBuilder(getMF(), MI); + } + + MachineInstrBuilder buildCopyIfRequired(MachineInstr *MI, unsigned Dst) { + // We need to build a copy from MI to Dst. + return buildCopy(Dst, MI->getOperand(0).getReg()); + } + + /// For given ID, find a machineinstr in the CSE Map. If found, check if it + /// dominates the current insertion point and if not, move it just before the + /// current insertion point and return it. If not found, return Null + /// MachineInstrBuilder. + template + MachineInstrBuilder + getDominatingInstrForID(FoldingSetNodeID &ID, GISelCSEInfo &CSEInfo, + void *&NodeInsertPos, DstTy &&Dst) { + auto *CurMBB = &getMBB(); + auto *Node = CSEInfo.getMachineInstrIfExists(ID, CurMBB, NodeInsertPos); + if (Node) { + auto CurrPos = getInsertPt(); + if (!dominates(Node, CurrPos)) + CurMBB->splice(CurrPos, CurMBB, Node); + // return MachineInstrBuilder(getMF(), Node); + return buildCopyIfRequired(Node, std::forward(Dst)); + } + return MachineInstrBuilder(); + } + + /// Simple check if we can CSE (we have the CSEInfo) or if this Opcode is + /// safe to CSE. + bool canPerformCSEForOpc(unsigned Opc, GISelCSEInfo *CSEInfo) { + if (!CSEInfo || !CSEInfo->shouldCSE(Opc)) + return false; + return true; + } + + void profileDst(unsigned Reg, GISelInstProfileBuilder &B) { + LLT Ty = getMRI()->getType(Reg); + B.addNodeIDRegType(Ty); + } + template + void profileDst(DstType &&Dst, GISelInstProfileBuilder &B) { + B.addNodeIDRegType(Dst); + } + + void profileDsts(ArrayRef Dsts, GISelInstProfileBuilder &B) { + for (auto &Dst : Dsts) + profileDst(Dst, B); + } + + /// Build method for binary operations. Returns null builder if not CSEable. + template + MachineInstrBuilder buildInstrCSE(unsigned Opc, DstTy &&Dst, UseArg1Ty &&Arg1, + UseArg2Ty &&Arg2, void *&NodeInsertPos) { + auto *CSEInfo = getCSEInfo(); + if (!canPerformCSEForOpc(Opc, CSEInfo)) + return MachineInstrBuilder(); + + FoldingSetNodeID ID; + auto Profile = profileMBBOpcDst(ID, Opc, std::forward(Dst)); + Profile.addNodeIDRegType(getRegFromArg(std::forward(Arg1))) + .addNodeIDRegType(getRegFromArg(std::forward(Arg2))); + return getDominatingInstrForID(ID, *CSEInfo, NodeInsertPos, + std::forward(Dst)); + } + + /// build method for unary operations. Returns null builder if not CSEable. + template + MachineInstrBuilder buildInstrCSE(unsigned Opc, DstTy &&Dst, UseArg1Ty &&Arg1, + void *&NodeInsertPos) { + auto *CSEInfo = getCSEInfo(); + if (!canPerformCSEForOpc(Opc, CSEInfo)) + return MachineInstrBuilder(); + FoldingSetNodeID ID; + auto Profile = profileMBBOpcDst(ID, Opc, std::forward(Dst)); + Profile.addNodeIDRegType(getRegFromArg(std::forward(Arg1))); + return getDominatingInstrForID(ID, *CSEInfo, NodeInsertPos, + std::forward(Dst)); + } + + /// build method for building integer constants. Returns null builder if not + /// CSEable. + template + MachineInstrBuilder buildConstantCSE(DstTy &&Dst, int64_t Cst, + void *&NodeInsertPos) { + auto IntN = + IntegerType::get(getMF().getFunction().getContext(), + getTypeSize(std::forward(Dst), *getMRI())); + ConstantInt *CI = ConstantInt::get(IntN, Cst, true); + return buildConstantCSE(std::forward(Dst), *CI, NodeInsertPos); + } + + /// Common profiling helpers. + GISelInstProfileBuilder profileMBBOpc(FoldingSetNodeID &ID, unsigned Opc) { + auto Profile = GISelInstProfileBuilder(ID, *getMRI()) + .addNodeIDMBB(&getMBB()) + .addNodeIDOpcode(Opc); + return Profile; + } + + template + GISelInstProfileBuilder profileMBBOpcDst(FoldingSetNodeID &ID, unsigned Opc, + DstTy &&Dst) { + auto Profile = profileMBBOpc(ID, Opc); + // Profile the Dst. + profileDst(Dst, Profile); + return Profile; + } + + template + MachineInstrBuilder buildConstantCSE(DstTy &&Dst, const ConstantInt &CI, + void *&NodeInsertPos) { + unsigned Opc = TargetOpcode::G_CONSTANT; + auto *CSEInfo = getCSEInfo(); + if (!canPerformCSEForOpc(Opc, CSEInfo)) + return MachineInstrBuilder(); + FoldingSetNodeID ID; + auto Profile = profileMBBOpcDst(ID, Opc, std::forward(Dst)); + Profile.addNodeIDMachineOperand(MachineOperand::CreateCImm(&CI)); + return getDominatingInstrForID(ID, *CSEInfo, NodeInsertPos, + std::forward(Dst)); + } + + template + MachineInstrBuilder buildFConstantCSE(DstTy &&Dst, double Val, + void *&NodeInsertPos) { + auto *CFP = ConstantFP::get( + getMF().getFunction().getContext(), + getAPFloatFromSize(Val, + getTypeSize(std::forward(Dst), *getMRI()))); + return buildFConstantCSE(std::forward(Dst), *CFP, NodeInsertPos); + } + + template + MachineInstrBuilder buildFConstantCSE(DstTy &&Dst, const ConstantFP &CFP, + void *&NodeInsertPos) { + unsigned Opc = TargetOpcode::G_FCONSTANT; + auto *CSEInfo = getCSEInfo(); + if (!canPerformCSEForOpc(Opc, CSEInfo)) + return MachineInstrBuilder(); + FoldingSetNodeID ID; + auto Profile = profileMBBOpcDst(ID, Opc, std::forward(Dst)); + Profile.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&CFP)); + return getDominatingInstrForID(ID, *CSEInfo, NodeInsertPos, + std::forward(Dst)); + } + + template + MachineInstrBuilder buildUndefCSE(DstTy &&Dst, void *&NodeInsertPos) { + unsigned Opc = TargetOpcode::G_IMPLICIT_DEF; + auto *CSEInfo = getCSEInfo(); + if (!canPerformCSEForOpc(Opc, CSEInfo)) + return MachineInstrBuilder(); + FoldingSetNodeID ID; + profileMBBOpcDst(ID, Opc, std::forward(Dst)); + return getDominatingInstrForID(ID, *CSEInfo, NodeInsertPos, + std::forward(Dst)); + } + + template + MachineInstrBuilder buildUnmergeCSE(ArrayRef Dsts, SrcTy &&Src, + void *&NodeInsertPos) { + unsigned Opc = TargetOpcode::G_UNMERGE_VALUES; + auto *CSEInfo = getCSEInfo(); + if (!canPerformCSEForOpc(Opc, CSEInfo)) + return MachineInstrBuilder(); + FoldingSetNodeID ID; + auto Profile = profileMBBOpc(ID, Opc); + profileDsts(Dsts, Profile); + Profile.addNodeIDRegType(getRegFromArg(std::forward(Src))); + return getDominatingInstrForID(ID, *CSEInfo, NodeInsertPos, Dsts); + } + + unsigned getTypeSize(const LLT &Ty, const MachineRegisterInfo &MRI) { + return Ty.getSizeInBits(); + } + unsigned getTypeSize(unsigned Reg, const MachineRegisterInfo &MRI) { + return MRI.getType(Reg).getSizeInBits(); + } + + MachineInstrBuilder memoizeMIBIfPossible(MachineInstrBuilder MIB, + GISelCSEInfo *CSEInfo, + void *NodeInsertPos) { + if (!canPerformCSEForOpc(MIB->getOpcode(), CSEInfo)) + return MIB; + MachineInstr *MIBInstr = MIB; + CSEInfo->insertInstr(MIBInstr, NodeInsertPos); + return MIB; + } + + MachineInstrBuilder buildInstr(unsigned Opc, unsigned Dst, unsigned Src0, + void *NodeInsertPos) { + auto MIB = buildInstr(Opc).addDef(Dst).addUse(Src0); + auto *CSEInfo = getCSEInfo(); + return memoizeMIBIfPossible(MIB, CSEInfo, NodeInsertPos); + } + +public: + // Pull in base class constructors. + using FoldableInstructionsBuilder::FoldableInstructionsBuilder; + // Unhide buildInstr + using FoldableInstructionsBuilder::buildInstr; + using Super = FoldableInstructionsBuilder; + + void setMF(MachineFunction &MF) { Super::setMF(MF); } + + template + MachineInstrBuilder buildConstant(DstTy &&Dst, CstTy &&Cst) { + void *NodeInsertPos = nullptr; + auto *CSEInfo = getCSEInfo(); + if (auto MIB = buildConstantCSE(std::forward(Dst), + std::forward(Cst), NodeInsertPos)) { + CSEInfo->countOpcodeHit(TargetOpcode::G_CONSTANT); + return MIB; + } + auto MIB = Super::buildConstant(std::forward(Dst), + std::forward(Cst)); + // Memoize the instruction. + return memoizeMIBIfPossible(MIB, CSEInfo, NodeInsertPos); + } + + template + MachineInstrBuilder buildFConstant(DstTy &&Dst, CstTy &&Cst) { + void *NodeInsertPos = nullptr; + auto *CSEInfo = getCSEInfo(); + if (auto MIB = buildFConstantCSE(std::forward(Dst), + std::forward(Cst), NodeInsertPos)) { + CSEInfo->countOpcodeHit(TargetOpcode::G_FCONSTANT); + return MIB; + } + auto MIB = Super::buildFConstant(std::forward(Dst), + std::forward(Cst)); + // Memoize the instruction. + return memoizeMIBIfPossible(MIB, CSEInfo, NodeInsertPos); + } + + template MachineInstrBuilder buildUndef(DstTy &&Dst) { + void *NodeInsertPos = nullptr; + unsigned Opc = TargetOpcode::G_IMPLICIT_DEF; + auto *CSEInfo = getCSEInfo(); + if (auto MIB = buildUndefCSE(std::forward(Dst), NodeInsertPos)) { + CSEInfo->countOpcodeHit(Opc); + return MIB; + } + auto MIB = buildInstr(Opc).addDef(getDestFromArg(std::forward(Dst))); + return memoizeMIBIfPossible(MIB, CSEInfo, NodeInsertPos); + } + + // TODO: Support the following Opcodes + // EXTRACT_VECTOR_ELT, INSERT_VECTOR_ELT. + // SELECT, SELECT_CC, ICMP, FCMP + // TRUNC, FPTRUNC + // EXTORTRUNC, and the various extends. + // GEP + // GLOBAL_VALUE + // FRAME_INDEX + + // Implement buildBinaryOp required by FoldableInstructionsBuilder which + // tries to constant fold. + template + MachineInstrBuilder buildBinaryOp(unsigned Opcode, DstTy &&Dst, unsigned Src0, + unsigned Src1, + void *NodeInsertPos = nullptr) { + // First perform basic constant folding. + auto MaybeCst = ConstantFoldBinOp(Opcode, Src0, Src1, getMF().getRegInfo()); + if (MaybeCst) + return buildConstant(std::forward(Dst), MaybeCst->getSExtValue()); + // Try to see if we can CSE this. + auto *CSEInfo = getCSEInfo(); + if (auto MIB = buildInstrCSE(Opcode, std::forward(Dst), Src0, Src1, + NodeInsertPos)) { + CSEInfo->countOpcodeHit(Opcode); + return MIB; + } + // Now build the instruction. + unsigned DstReg = getDestFromArg(std::forward(Dst)); + validateBinaryOp(DstReg, Src0, Src1); + auto MIB = buildInstr(Opcode).addDef(DstReg).addUse(Src0).addUse(Src1); + return memoizeMIBIfPossible(MIB, CSEInfo, NodeInsertPos); + } + + template + MachineInstrBuilder buildUnmerge(ArrayRef Dsts, SrcTy &&Src) { + void *NodeInsertPos = nullptr; + if (auto MIB = + buildUnmergeCSE(Dsts, std::forward(Src), NodeInsertPos)) { + getCSEInfo()->countOpcodeHit(TargetOpcode::G_UNMERGE_VALUES); + return MIB; + } + SmallVector DstRegs; + for (auto &Dst : Dsts) + DstRegs.push_back(getMRI()->createGenericVirtualRegister(Dst)); + return buildUnmerge(DstRegs, std::forward(Src)); + } + + template + MachineInstrBuilder buildUnmerge(ArrayRef Dsts, SrcTy &&Src) { + auto MIB = + Super::buildUnmerge(Dsts, getRegFromArg(std::forward(Src))); + auto *CSEInfo = getCSEInfo(); + return memoizeMIBIfPossible(MIB, CSEInfo, nullptr); + } + + template + MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, UseArg1Ty &&Arg1, + UseArg2Ty &&Arg2) { + void *NodeInsertPos = nullptr; + if (auto MIB = buildInstrCSE(Opc, std::forward(Ty), + getRegFromArg(std::forward(Arg1)), + getRegFromArg(std::forward(Arg2)), + NodeInsertPos)) { + getCSEInfo()->countOpcodeHit(Opc); + return MIB; + } + return buildInstr(Opc, std::forward(Ty), + getRegFromArg(std::forward(Arg1)), + getRegFromArg(std::forward(Arg2)), + NodeInsertPos); + } + + template + MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, UseArg1Ty &&Arg1) { + void *NodeInsertPos = nullptr; + if (auto MIB = buildInstrCSE(Opc, std::forward(Ty), + getRegFromArg(std::forward(Arg1)), + NodeInsertPos)) { + getCSEInfo()->countOpcodeHit(Opc); + return MIB; + } + unsigned Dst = getDestFromArg(Ty); + return buildInstr(Opc, Dst, getRegFromArg(std::forward(Arg1)), + NodeInsertPos); + } + + // Try to provide an overload for buildInstr for binary ops in order to + // constant fold. + template + MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Dst, unsigned Src0, + unsigned Src1, void *NodeInsertPos = nullptr) { + 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, std::forward(Dst), Src0, Src1, + NodeInsertPos); + } + } + return buildInstr(Opc) + .addDef(getDestFromArg(std::forward(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 +#endif Index: include/llvm/CodeGen/GlobalISel/Combiner.h =================================================================== --- include/llvm/CodeGen/GlobalISel/Combiner.h +++ include/llvm/CodeGen/GlobalISel/Combiner.h @@ -21,6 +21,7 @@ namespace llvm { class MachineRegisterInfo; class CombinerInfo; +class GISelCSEInfo; class TargetPassConfig; class MachineFunction; @@ -38,14 +39,14 @@ public: Combiner(CombinerInfo &CombinerInfo, const TargetPassConfig *TPC); - bool combineMachineInstrs(MachineFunction &MF); + bool combineMachineInstrs(MachineFunction &MF, GISelCSEInfo *); protected: CombinerInfo &CInfo; MachineRegisterInfo *MRI = nullptr; const TargetPassConfig *TPC; - MachineIRBuilder Builder; + MachineIRBuilderState BuilderState; }; } // End namespace llvm. Index: include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -26,7 +26,7 @@ class MachineInstr; class CombinerHelper { - MachineIRBuilder &Builder; + MachineIRBuilder Builder; MachineRegisterInfo &MRI; CombinerChangeObserver &Observer; @@ -34,7 +34,7 @@ void scheduleForVisit(MachineInstr &MI); public: - CombinerHelper(CombinerChangeObserver &Observer, MachineIRBuilder &B); + CombinerHelper(CombinerChangeObserver &Observer, MachineIRBuilderState &B); /// If \p MI is COPY, try to combine it. /// Returns true if MI changed. Index: include/llvm/CodeGen/GlobalISel/CombinerInfo.h =================================================================== --- include/llvm/CodeGen/GlobalISel/CombinerInfo.h +++ include/llvm/CodeGen/GlobalISel/CombinerInfo.h @@ -20,7 +20,7 @@ class CombinerChangeObserver; class LegalizerInfo; class MachineInstr; -class MachineIRBuilder; +struct MachineIRBuilderState; class MachineRegisterInfo; // Contains information relevant to enabling/disabling various combines for a @@ -44,7 +44,7 @@ bool LegalizeIllegalOps; // TODO: Make use of this. const LegalizerInfo *LInfo; virtual bool combine(CombinerChangeObserver &Observer, MachineInstr &MI, - MachineIRBuilder &B) const = 0; + MachineIRBuilderState &State) const = 0; }; } // namespace llvm Index: include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h @@ -15,57 +15,6 @@ 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 Index: include/llvm/CodeGen/GlobalISel/GISelWorkList.h =================================================================== --- include/llvm/CodeGen/GlobalISel/GISelWorkList.h +++ include/llvm/CodeGen/GlobalISel/GISelWorkList.h @@ -53,6 +53,11 @@ WorklistMap.erase(It); } + void clear() { + Worklist.clear(); + WorklistMap.clear(); + } + MachineInstr *pop_back_val() { MachineInstr *I; do { Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -442,10 +442,12 @@ // I.e., compared to regular MIBuilder, this one also inserts the instruction // in the current block, it can creates block, etc., basically a kind of // IRBuilder, but for Machine IR. + MachineIRBuilderState CurBuilderState; MachineIRBuilder CurBuilder; // Builder set to the entry block (just after ABI lowering instructions). Used // as a convenient location for Constants. + MachineIRBuilderState EntryBuilderState; MachineIRBuilder EntryBuilder; // The MachineFunction currently being translated. Index: include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h +++ include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h @@ -12,9 +12,9 @@ // at the end of the legalization. //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Legalizer.h" #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" -#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" @@ -23,14 +23,15 @@ namespace llvm { class LegalizationArtifactCombiner { - MachineIRBuilder &Builder; + MachineIRBuilderState &BuilderState; MachineRegisterInfo &MRI; const LegalizerInfo &LI; public: - LegalizationArtifactCombiner(MachineIRBuilder &B, MachineRegisterInfo &MRI, - const LegalizerInfo &LI) - : Builder(B), MRI(MRI), LI(LI) {} + LegalizationArtifactCombiner(MachineIRBuilderState &State, + MachineRegisterInfo &MRI, + const LegalizerInfo &LI) + : BuilderState(State), MRI(MRI), LI(LI) {} bool tryCombineAnyExt(MachineInstr &MI, SmallVectorImpl &DeadInsts) { @@ -41,6 +42,7 @@ LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;); unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = DefMI->getOperand(1).getReg(); + CSEMIRBuilder Builder(BuilderState); Builder.setInstr(MI); // We get a copy/trunc/extend depending on the sizes Builder.buildAnyExtOrTrunc(DstReg, SrcReg); @@ -63,6 +65,7 @@ isInstUnsupported({TargetOpcode::G_CONSTANT, {DstTy}})) return false; LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;); + CSEMIRBuilder Builder(BuilderState); Builder.setInstr(MI); unsigned ZExtSrc = MI.getOperand(1).getReg(); LLT ZExtSrcTy = MRI.getType(ZExtSrc); @@ -92,6 +95,7 @@ isInstUnsupported({TargetOpcode::G_CONSTANT, {DstTy}})) return false; LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;); + CSEMIRBuilder Builder(BuilderState); Builder.setInstr(MI); unsigned SExtSrc = MI.getOperand(1).getReg(); LLT SExtSrcTy = MRI.getType(SExtSrc); @@ -119,6 +123,7 @@ if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(1).getReg(), MRI)) { + CSEMIRBuilder Builder(BuilderState); Builder.setInstr(MI); unsigned DstReg = MI.getOperand(0).getReg(); LLT DstTy = MRI.getType(DstReg); @@ -162,6 +167,7 @@ if (NumDefs % NumMergeRegs != 0) return false; + MachineIRBuilder Builder(BuilderState); Builder.setInstr(MI); // Transform to UNMERGEs, for example // %1 = G_MERGE_VALUES %4, %5 @@ -184,6 +190,7 @@ if (NumMergeRegs % NumDefs != 0) return false; + MachineIRBuilder Builder(BuilderState); Builder.setInstr(MI); // Transform to MERGEs // %6 = G_MERGE_VALUES %17, %18, %19, %20 Index: include/llvm/CodeGen/GlobalISel/LegalizerHelper.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -21,6 +21,7 @@ #ifndef LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZEHELPER_H #define LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZEHELPER_H +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/LowLevelType.h" @@ -88,7 +89,9 @@ /// Expose MIRBuilder so clients can set their own RecordInsertInstruction /// functions - MachineIRBuilder MIRBuilder; + MachineIRBuilderState MIRBuilderState; + // MachineIRBuilder MIRBuilder; + CSEMIRBuilder MIRBuilder; /// Expose LegalizerInfo so the clients can re-use. const LegalizerInfo &getLegalizerInfo() const { return LI; } @@ -121,7 +124,7 @@ /// Helper function that creates the given libcall. LegalizerHelper::LegalizeResult -createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall, +createLibcall(MachineIRBuilderState &State, RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result, ArrayRef Args); Index: include/llvm/CodeGen/GlobalISel/LegalizerInfo.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -37,6 +37,7 @@ class MachineInstr; class MachineIRBuilder; +struct MachineIRBuilderState; class MachineRegisterInfo; class MCInstrInfo; @@ -947,9 +948,8 @@ bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const; - virtual bool legalizeCustom(MachineInstr &MI, - MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const; + virtual bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, + MachineIRBuilderState &State) const; private: /// Determine what action should be taken to legalize the given generic Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -14,6 +14,7 @@ #ifndef LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H #define LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H +#include "llvm/CodeGen/GlobalISel/CSEInfo.h" #include "llvm/CodeGen/GlobalISel/Types.h" #include "llvm/CodeGen/LowLevelType.h" @@ -51,6 +52,15 @@ /// @} std::function InsertedInstr; + + GISelCSEInfo *CSEInfo = nullptr; + void recordInsertions(std::function InsertedInstr); + void stopRecordingInsertions(); + void setCSEInfo(GISelCSEInfo *Info) { CSEInfo = Info; } + + void setMF(MachineFunction &MF); + void setMBB(MachineBasicBlock &MBB); + void setInstr(MachineInstr &MI); }; /// Helper class to build MachineInstr. @@ -59,7 +69,7 @@ /// This information can be modify via the related setters. class MachineIRBuilderBase { - MachineIRBuilderState State; + MachineIRBuilderState &State; void validateTruncExt(unsigned Dst, unsigned Src, bool IsExtend); protected: @@ -94,13 +104,17 @@ public: /// Some constructors for easy use. - MachineIRBuilderBase() = default; - MachineIRBuilderBase(MachineFunction &MF) { setMF(MF); } - MachineIRBuilderBase(MachineInstr &MI) : MachineIRBuilderBase(*MI.getMF()) { + MachineIRBuilderBase() = delete; + MachineIRBuilderBase(MachineFunction &MF, MachineIRBuilderState &State) + : State(State) { + setMF(MF); + } + MachineIRBuilderBase(MachineInstr &MI, MachineIRBuilderState &State) + : MachineIRBuilderBase(*MI.getMF(), State) { setInstr(MI); } - MachineIRBuilderBase(const MachineIRBuilderState &BState) : State(BState) {} + MachineIRBuilderBase(MachineIRBuilderState &BState) : State(BState) {} const TargetInstrInfo &getTII() { assert(State.TII && "TargetInstrInfo is not set"); @@ -128,6 +142,8 @@ return *State.MBB; } + GISelCSEInfo *getCSEInfo() { return State.CSEInfo; } + /// Current insertion point for new instructions. MachineBasicBlock::iterator getInsertPt() { return State.II; } @@ -137,18 +153,20 @@ void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II); /// @} + void setCSEInfo(GISelCSEInfo *Info) { State.CSEInfo = Info; } + /// \name Setters for the insertion point. /// @{ /// Set the MachineFunction where to build instructions. - void setMF(MachineFunction &); + void setMF(MachineFunction &MF) { State.setMF(MF); } /// Set the insertion point to the end of \p MBB. /// \pre \p MBB must be contained by getMF(). - void setMBB(MachineBasicBlock &MBB); + void setMBB(MachineBasicBlock &MBB) { State.setMBB(MBB); }; /// Set the insertion point to before MI. /// \pre MI must be in getMF(). - void setInstr(MachineInstr &MI); + void setInstr(MachineInstr &MI) { State.setInstr(MI); } /// @} /// \name Control where instructions we create are recorded (typically for Index: include/llvm/CodeGen/GlobalISel/RegBankSelect.h =================================================================== --- include/llvm/CodeGen/GlobalISel/RegBankSelect.h +++ include/llvm/CodeGen/GlobalISel/RegBankSelect.h @@ -505,6 +505,7 @@ std::unique_ptr MORE; /// Helper class used for every code morphing. + MachineIRBuilderState MIRBuilderState; MachineIRBuilder MIRBuilder; /// Optimization mode of the pass. Index: include/llvm/CodeGen/GlobalISel/Utils.h =================================================================== --- include/llvm/CodeGen/GlobalISel/Utils.h +++ include/llvm/CodeGen/GlobalISel/Utils.h @@ -108,5 +108,8 @@ /// fallback. void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU); +Optional ConstantFoldBinOp(unsigned Opcode, const unsigned Op1, + const unsigned Op2, + const MachineRegisterInfo &MRI); } // End namespace llvm. #endif Index: include/llvm/CodeGen/SlotIndexes.h =================================================================== --- include/llvm/CodeGen/SlotIndexes.h +++ include/llvm/CodeGen/SlotIndexes.h @@ -448,7 +448,7 @@ /// MI is not required to have an index. SlotIndex getIndexBefore(const MachineInstr &MI) const { const MachineBasicBlock *MBB = MI.getParent(); - assert(MBB && "MI must be inserted in a basic block"); + assert(MBB && "MI must be inserted inna basic block"); MachineBasicBlock::const_iterator I = MI, B = MBB->begin(); while (true) { if (I == B) @@ -465,7 +465,7 @@ /// MI is not required to have an index. SlotIndex getIndexAfter(const MachineInstr &MI) const { const MachineBasicBlock *MBB = MI.getParent(); - assert(MBB && "MI must be inserted in a basic block"); + assert(MBB && "MI must be inserted inna basic block"); MachineBasicBlock::const_iterator I = MI, E = MBB->end(); while (true) { ++I; Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -196,6 +196,7 @@ void initializeLegacyLICMPassPass(PassRegistry&); void initializeLegacyLoopSinkPassPass(PassRegistry&); void initializeLegalizerPass(PassRegistry&); +void initializeGISelCSEAnalysisWrapperPassPass(PassRegistry &); void initializeLibCallsShrinkWrapLegacyPassPass(PassRegistry&); void initializeLintPass(PassRegistry&); void initializeLiveDebugValuesPass(PassRegistry&); Index: include/llvm/Support/LowLevelTypeImpl.h =================================================================== --- include/llvm/Support/LowLevelTypeImpl.h +++ include/llvm/Support/LowLevelTypeImpl.h @@ -147,6 +147,7 @@ bool operator!=(const LLT &RHS) const { return !(*this == RHS); } friend struct DenseMapInfo; + friend class GISelInstProfileBuilder; private: /// LLT is packed into 64 bits as follows: @@ -231,6 +232,11 @@ maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo); } } + + uint64_t getUniqueRAWLLTData() const { + return ((uint64_t)RawData) << 2 | ((uint64_t)IsPointer) << 1 | + ((uint64_t)IsVector); + } }; inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { @@ -250,8 +256,7 @@ return Invalid; } static inline unsigned getHashValue(const LLT &Ty) { - uint64_t Val = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 | - ((uint64_t)Ty.IsVector); + uint64_t Val = Ty.getUniqueRAWLLTData(); return DenseMapInfo::getHashValue(Val); } static bool isEqual(const LLT &LHS, const LLT &RHS) { Index: lib/Analysis/VectorUtils.cpp =================================================================== --- lib/Analysis/VectorUtils.cpp +++ lib/Analysis/VectorUtils.cpp @@ -54,8 +54,6 @@ case Intrinsic::fabs: case Intrinsic::minnum: case Intrinsic::maxnum: - case Intrinsic::minimum: - case Intrinsic::maximum: case Intrinsic::copysign: case Intrinsic::floor: case Intrinsic::ceil: Index: lib/CodeGen/GlobalISel/CMakeLists.txt =================================================================== --- lib/CodeGen/GlobalISel/CMakeLists.txt +++ lib/CodeGen/GlobalISel/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMGlobalISel + CSEInfo.cpp CallLowering.cpp GlobalISel.cpp Combiner.cpp Index: lib/CodeGen/GlobalISel/CSEInfo.cpp =================================================================== --- /dev/null +++ lib/CodeGen/GlobalISel/CSEInfo.cpp @@ -0,0 +1,354 @@ +//===- CSEInfo.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// +#include "llvm/CodeGen/GlobalISel/CSEInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +#define DEBUG_TYPE "cseinfo" + +using namespace llvm; +char llvm::GISelCSEAnalysisWrapperPass::ID = 0; +INITIALIZE_PASS_BEGIN(GISelCSEAnalysisWrapperPass, DEBUG_TYPE, + "Analysis containing CSE Info", false, true) +INITIALIZE_PASS_END(GISelCSEAnalysisWrapperPass, DEBUG_TYPE, + "Analysis containing CSE Info", false, true) + +/// -------- UniqueMachineInstr -------------// + +void UniqueMachineInstr::Profile(FoldingSetNodeID &ID) { + GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI); +} +/// ----------------------------------------- + +/// -------- GISelCSEInfo -------------// +void GISelCSEInfo::setMF(MachineFunction &MF) { + this->MF = &MF; + this->MRI = &MF.getRegInfo(); +} + +GISelCSEInfo::~GISelCSEInfo() {} + +bool GISelCSEInfo::isUniqueMachineInstValid( + const UniqueMachineInstr &UMI) const { + // Should we check here and assert that the instruction has been fully + // constructed? + // FIXME: Any other checks required to be done here? Remove this method if + // none. + return true; +} + +void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) { + bool Removed = CSEMap.RemoveNode(UMI); + (void)Removed; + assert(Removed && "Invalidation called on invalid UMI"); + // FIXME: Should UMI be deallocated/destroyed? +} + +UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID, + MachineBasicBlock *MBB, + void *&InsertPos) { + auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos); + if (Node) { + if (!isUniqueMachineInstValid(*Node)) { + invalidateUniqueMachineInstr(Node); + return nullptr; + } + + if (Node->MI->getParent() != MBB) + return nullptr; + } + return Node; +} + +void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) { + handleRecordedInsts(); + assert(UMI); + UniqueMachineInstr *MaybeNewNode = UMI; + if (InsertPos) + CSEMap.InsertNode(UMI, InsertPos); + else + MaybeNewNode = CSEMap.GetOrInsertNode(UMI); + if (MaybeNewNode != UMI) { + // A similar node exists in the folding set. Let's ignore this one. + return; + } + assert(InstrMapping.count(UMI->MI) == 0 && + "This instruction should not be in the map"); + InstrMapping[UMI->MI] = MaybeNewNode; +} + +UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) { + assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node"); + auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI); + return Node; +} + +void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) { + assert(MI); + // If it exists in temporary insts, remove it. + TemporaryInsts.remove(MI); + auto *Node = getUniqueInstrForMI(MI); + insertNode(Node, InsertPos); +} + +MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID, + MachineBasicBlock *MBB, + void *&InsertPos) { + handleRecordedInsts(); + if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) { + LLVM_DEBUG(dbgs() << "CSEInfo: Found Instr " << *Inst->MI << "\n";); + return const_cast(Inst->MI); + } + return nullptr; +} + +void GISelCSEInfo::countOpcodeHit(unsigned Opc) { +#ifndef NDEBUG + if (OpcodeHitTable.count(Opc)) + OpcodeHitTable[Opc] += 1; + else + OpcodeHitTable[Opc] = 1; +#endif + // Else do nothing. +} + +void GISelCSEInfo::recordNewInstruction(MachineInstr *MI) { + if (shouldCSE(MI->getOpcode())) { + TemporaryInsts.insert(MI); + LLVM_DEBUG(dbgs() << "CSEInfo: Recording new MI" << *MI << "\n";); + } +} + +void GISelCSEInfo::handleRecordedInst(MachineInstr *MI) { + assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE"); + auto *UMI = InstrMapping.lookup(MI); + LLVM_DEBUG(dbgs() << "CSEInfo: Handling recorded MI" << *MI << "\n";); + if (UMI) { + // Invalidate this MI. + invalidateUniqueMachineInstr(UMI); + InstrMapping.erase(MI); + } + /// Now insert the new instruction. + if (UMI) { + /// We'll reuse the same UniqueMachineInstr to avoid the new + /// allocation. + *UMI = UniqueMachineInstr(MI); + insertNode(UMI, nullptr); + } else { + /// This is a new instruction. Allocate a new UniqueMachineInstr and + /// Insert. + insertInstr(MI); + } +} + +void GISelCSEInfo::handleRemoveInst(MachineInstr *MI) { + if (auto *UMI = InstrMapping.lookup(MI)) { + invalidateUniqueMachineInstr(UMI); + InstrMapping.erase(MI); + } + TemporaryInsts.remove(MI); +} + +void GISelCSEInfo::handleRecordedInsts() { + while (!TemporaryInsts.empty()) { + auto *MI = TemporaryInsts.pop_back_val(); + handleRecordedInst(MI); + } +} + +bool GISelCSEInfo::shouldCSE(unsigned Opc) { + // First allow the callback to decide. + if (ShouldCSEFn && ShouldCSEFn(Opc)) + return true; + // Only GISel opcodes are CSEable + if (!isPreISelGenericOpcode(Opc)) + return false; + 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: + case TargetOpcode::G_CONSTANT: + case TargetOpcode::G_FCONSTANT: + case TargetOpcode::G_ZEXT: + case TargetOpcode::G_SEXT: + case TargetOpcode::G_ANYEXT: + case TargetOpcode::G_UNMERGE_VALUES: + case TargetOpcode::G_TRUNC: + return true; + } + return false; +} + +void GISelCSEInfo::MF_HandleRemoval(const MachineInstr &MI) { + handleRemoveInst(&const_cast(MI)); +} + +void GISelCSEInfo::MF_HandleInsertion(const MachineInstr &MI) { + recordNewInstruction(&const_cast(MI)); +} + +void GISelCSEInfo::analyze(MachineFunction &MF) { + setMF(MF); + for (auto &MBB : MF) { + if (MBB.empty()) + continue; + for (MachineInstr &MI : MBB) { + if (!shouldCSE(MI.getOpcode())) + continue; + LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI << "\n";); + insertInstr(&MI); + } + } +} + +void GISelCSEInfo::releaseMemory() { + // print(); + CSEMap.clear(); + InstrMapping.clear(); + UniqueInstrAllocator.Reset(); + TemporaryInsts.clear(); + ShouldCSEFn = nullptr; + MRI = nullptr; + MF = nullptr; +#ifndef NDEBUG + OpcodeHitTable.clear(); +#endif +} + +void GISelCSEInfo::print() { +#ifndef NDEBUG + for (auto &It : OpcodeHitTable) { + dbgs() << "CSE Count for Opc " << It.first << " : " << It.second << "\n"; + }; +#endif +} +/// ----------------------------------------- +RAIIDelegateInstaller::RAIIDelegateInstaller(MachineFunction &MF, + MachineFunction::Delegate *Del) + : MF(MF), Delegate(Del) { + // Register this as the delegate for handling insertions and deletions of + // instructions. + MF.setDelegate(Del); +} + +RAIIDelegateInstaller::~RAIIDelegateInstaller() { MF.resetDelegate(Delegate); } +// ---- Profiling methods for FoldingSetNode --- // +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeID(const MachineInstr *MI) const { + addNodeIDMBB(MI->getParent()); + addNodeIDOpcode(MI->getOpcode()); + for (auto &Op : MI->operands()) + addNodeIDMachineOperand(Op); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc) const { + ID.AddInteger(Opc); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const LLT &Ty) const { + uint64_t Val = Ty.getUniqueRAWLLTData(); + ID.AddInteger(Val); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass *RC) const { + ID.AddPointer(RC); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank *RB) const { + ID.AddPointer(RB); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm) const { + ID.AddInteger(Imm); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegNum(unsigned Reg) const { + ID.AddInteger(Reg); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const unsigned Reg) const { + addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false)); + return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock *MBB) const { + ID.AddPointer(MBB); + return *this; +} + +const GISelInstProfileBuilder &GISelInstProfileBuilder::addNodeIDMachineOperand( + const MachineOperand &MO) const { + if (MO.isReg()) { + unsigned Reg = MO.getReg(); + if (!MO.isDef()) + addNodeIDRegNum(Reg); + LLT Ty = MRI.getType(Reg); + if (Ty.isValid()) + addNodeIDRegType(Ty); + auto *RB = MRI.getRegBankOrNull(Reg); + if (RB) + addNodeIDRegType(RB); + auto *RC = MRI.getRegClassOrNull(Reg); + if (RC) + addNodeIDRegType(RC); + assert(!MO.isImplicit() && "Unhandled case"); + } else if (MO.isImm()) + ID.AddInteger(MO.getImm()); + else if (MO.isCImm()) + ID.AddPointer(MO.getCImm()); + else if (MO.isFPImm()) + ID.AddPointer(MO.getFPImm()); + else if (MO.isPredicate()) + ID.AddInteger(MO.getPredicate()); + else + llvm_unreachable("Unhandled operand type"); + // Handle other types + return *this; +} + +void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction &MF) { + releaseMemory(); + // Do the analysis + Info.analyze(MF); + return false; +} Index: lib/CodeGen/GlobalISel/Combiner.cpp =================================================================== --- lib/CodeGen/GlobalISel/Combiner.cpp +++ lib/CodeGen/GlobalISel/Combiner.cpp @@ -12,12 +12,13 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GlobalISel/Combiner.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/CodeGen/GlobalISel/CSEInfo.h" #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" -#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" -#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" -#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" @@ -58,7 +59,8 @@ (void)this->TPC; // FIXME: Remove when used. } -bool Combiner::combineMachineInstrs(MachineFunction &MF) { +bool Combiner::combineMachineInstrs(MachineFunction &MF, + GISelCSEInfo *CSEInfo) { // If the ISel pipeline failed, do not bother running this pass. // FIXME: Should this be here or in individual combiner passes. if (MF.getProperties().hasProperty( @@ -66,7 +68,9 @@ return false; MRI = &MF.getRegInfo(); + MachineIRBuilder Builder(BuilderState); Builder.setMF(MF); + Builder.setCSEInfo(CSEInfo); LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); @@ -101,7 +105,7 @@ while (!WorkList.empty()) { MachineInstr *CurrInst = WorkList.pop_back_val(); LLVM_DEBUG(dbgs() << "Try combining " << *CurrInst << "\n";); - Changed |= CInfo.combine(Observer, *CurrInst, Builder); + Changed |= CInfo.combine(Observer, *CurrInst, BuilderState); } MFChanged |= Changed; } while (Changed); Index: lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -19,8 +19,8 @@ using namespace llvm; CombinerHelper::CombinerHelper(CombinerChangeObserver &Observer, - MachineIRBuilder &B) - : Builder(B), MRI(Builder.getMF().getRegInfo()), Observer(Observer) {} + MachineIRBuilderState &State) + : Builder(State), MRI(Builder.getMF().getRegInfo()), Observer(Observer) {} void CombinerHelper::eraseInstr(MachineInstr &MI) { Observer.erasedInstr(MI); Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -100,7 +100,9 @@ ORE.emit(R); } -IRTranslator::IRTranslator() : MachineFunctionPass(ID) { +IRTranslator::IRTranslator() + : MachineFunctionPass(ID), CurBuilder(CurBuilderState), + EntryBuilder(EntryBuilderState) { initializeIRTranslatorPass(*PassRegistry::getPassRegistry()); } @@ -1576,8 +1578,8 @@ // MachineIRBuilder::DebugLoc can outlive the DILocation it holds. Clear it // to avoid accessing free’d memory (in runOnMachineFunction) and to avoid // destroying it twice (in ~IRTranslator() and ~LLVMContext()) - EntryBuilder = MachineIRBuilder(); - CurBuilder = MachineIRBuilder(); + EntryBuilderState = MachineIRBuilderState(); + CurBuilderState = MachineIRBuilderState(); } bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { Index: lib/CodeGen/GlobalISel/Legalizer.cpp =================================================================== --- lib/CodeGen/GlobalISel/Legalizer.cpp +++ lib/CodeGen/GlobalISel/Legalizer.cpp @@ -16,6 +16,7 @@ #include "llvm/CodeGen/GlobalISel/Legalizer.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/GlobalISel/CSEInfo.h" #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" @@ -37,6 +38,7 @@ "Legalize the Machine IR a function's Machine IR", false, false) INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass) INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE, "Legalize the Machine IR a function's Machine IR", false, false) @@ -47,6 +49,8 @@ void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); getSelectionDAGFallbackAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU); } @@ -76,6 +80,9 @@ LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n'); init(MF); const TargetPassConfig &TPC = getAnalysis(); + auto &WrapperPass = getAnalysis(); + auto &CSEInfo = WrapperPass.getCSEInfo(); + RAIIDelegateInstaller DelInstall(MF, &CSEInfo); MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); LegalizerHelper Helper(MF); @@ -103,7 +110,7 @@ InstList.insert(&MI); } } - Helper.MIRBuilder.recordInsertions([&](MachineInstr *MI) { + Helper.MIRBuilderState.recordInsertions([&](MachineInstr *MI) { // Only legalize pre-isel generic instructions. // Legalization process could generate Target specific pseudo // instructions with generic types. Don't record them @@ -113,10 +120,15 @@ else InstList.insert(MI); } + // This is needed for mutations. CSEInfo already knows about new + // instructions. + CSEInfo.recordNewInstruction(MI); LLVM_DEBUG(dbgs() << ".. .. New MI: " << *MI;); }); + Helper.MIRBuilderState.setCSEInfo(&CSEInfo); const LegalizerInfo &LInfo(Helper.getLegalizerInfo()); - LegalizationArtifactCombiner ArtCombiner(Helper.MIRBuilder, MF.getRegInfo(), LInfo); + LegalizationArtifactCombiner ArtCombiner(Helper.MIRBuilderState, + MF.getRegInfo(), LInfo); auto RemoveDeadInstFromLists = [&InstList, &ArtifactList](MachineInstr *DeadMI) { InstList.remove(DeadMI); @@ -138,12 +150,13 @@ // Error out if we couldn't legalize this instruction. We may want to // fall back to DAG ISel instead in the future. if (Res == LegalizerHelper::UnableToLegalize) { - Helper.MIRBuilder.stopRecordingInsertions(); + Helper.MIRBuilderState.stopRecordingInsertions(); reportGISelFailure(MF, TPC, MORE, "gisel-legalize", "unable to legalize instruction", MI); return false; } Changed |= Res == LegalizerHelper::Legalized; + // Assume the current inst is erased. } while (!ArtifactList.empty()) { MachineInstr &MI = *ArtifactList.pop_back_val(); Index: lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -30,13 +30,14 @@ using namespace LegalizeActions; LegalizerHelper::LegalizerHelper(MachineFunction &MF) - : MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()) { - MIRBuilder.setMF(MF); + : MIRBuilder(MIRBuilderState), MRI(MF.getRegInfo()), + LI(*MF.getSubtarget().getLegalizerInfo()) { + MIRBuilderState.setMF(MF); } LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI) - : MRI(MF.getRegInfo()), LI(LI) { - MIRBuilder.setMF(MF); + : MIRBuilder(MIRBuilderState), MRI(MF.getRegInfo()), LI(LI) { + MIRBuilderState.setMF(MF); } LegalizerHelper::LegalizeResult LegalizerHelper::legalizeInstrStep(MachineInstr &MI) { @@ -64,8 +65,8 @@ return fewerElementsVector(MI, Step.TypeIdx, Step.NewType); case Custom: LLVM_DEBUG(dbgs() << ".. Custom legalization\n"); - return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized - : UnableToLegalize; + return LI.legalizeCustom(MI, MRI, MIRBuilderState) ? Legalized + : UnableToLegalize; default: LLVM_DEBUG(dbgs() << ".. Unable to legalize\n"); return UnableToLegalize; @@ -117,9 +118,10 @@ } LegalizerHelper::LegalizeResult -llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall, +llvm::createLibcall(MachineIRBuilderState &State, RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result, ArrayRef Args) { + MachineIRBuilder MIRBuilder(State); auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering(); auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); const char *Name = TLI.getLibcallName(Libcall); @@ -134,14 +136,14 @@ // Useful for libcalls where all operands have the same type. static LegalizerHelper::LegalizeResult -simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, +simpleLibcall(MachineInstr &MI, MachineIRBuilderState &State, unsigned Size, Type *OpType) { auto Libcall = getRTLibDesc(MI.getOpcode(), Size); SmallVector Args; for (unsigned i = 1; i < MI.getNumOperands(); i++) Args.push_back({MI.getOperand(i).getReg(), OpType}); - return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), OpType}, + return createLibcall(State, Libcall, {MI.getOperand(0).getReg(), OpType}, Args); } @@ -168,10 +170,10 @@ } static LegalizerHelper::LegalizeResult -conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType, +conversionLibcall(MachineInstr &MI, MachineIRBuilderState &State, Type *ToType, Type *FromType) { RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType); - return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ToType}, + return createLibcall(State, Libcall, {MI.getOperand(0).getReg(), ToType}, {{MI.getOperand(1).getReg(), FromType}}); } @@ -191,7 +193,7 @@ case TargetOpcode::G_SREM: case TargetOpcode::G_UREM: { Type *HLTy = Type::getInt32Ty(Ctx); - auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy); + auto Status = simpleLibcall(MI, MIRBuilderState, Size, HLTy); if (Status != Legalized) return Status; break; @@ -204,7 +206,7 @@ case TargetOpcode::G_FPOW: case TargetOpcode::G_FREM: { Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); - auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy); + auto Status = simpleLibcall(MI, MIRBuilderState, Size, HLTy); if (Status != Legalized) return Status; break; @@ -216,7 +218,7 @@ if (ToSize != 64 || FromSize != 32) return UnableToLegalize; LegalizeResult Status = conversionLibcall( - MI, MIRBuilder, Type::getDoubleTy(Ctx), Type::getFloatTy(Ctx)); + MI, MIRBuilderState, Type::getDoubleTy(Ctx), Type::getFloatTy(Ctx)); if (Status != Legalized) return Status; break; @@ -228,7 +230,7 @@ if (ToSize != 32 || FromSize != 64) return UnableToLegalize; LegalizeResult Status = conversionLibcall( - MI, MIRBuilder, Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx)); + MI, MIRBuilderState, Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx)); if (Status != Legalized) return Status; break; @@ -241,7 +243,7 @@ if (ToSize != 32 || (FromSize != 32 && FromSize != 64)) return UnableToLegalize; LegalizeResult Status = conversionLibcall( - MI, MIRBuilder, Type::getInt32Ty(Ctx), + MI, MIRBuilderState, Type::getInt32Ty(Ctx), FromSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx)); if (Status != Legalized) return Status; @@ -255,7 +257,7 @@ if (FromSize != 32 || (ToSize != 32 && ToSize != 64)) return UnableToLegalize; LegalizeResult Status = conversionLibcall( - MI, MIRBuilder, + MI, MIRBuilderState, ToSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx), Type::getInt32Ty(Ctx)); if (Status != Legalized) Index: lib/CodeGen/GlobalISel/LegalizerInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -375,8 +375,9 @@ return getAction(MI, MRI).Action == Legal; } -bool LegalizerInfo::legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const { +bool LegalizerInfo::legalizeCustom( + MachineInstr &MI, MachineRegisterInfo &MRI, + MachineIRBuilderState &MIRBuilderState) const { return false; } Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -22,27 +22,26 @@ using namespace llvm; -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 MachineIRBuilderState::setMF(MachineFunction &MF) { + this->MF = &MF; + MBB = nullptr; + MRI = &MF.getRegInfo(); + TII = MF.getSubtarget().getInstrInfo(); + DL = DebugLoc(); + II = MachineBasicBlock::iterator(); + 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 MachineIRBuilderState::setMBB(MachineBasicBlock &MBB) { + this->MBB = &MBB; + II = MBB.end(); + assert(MF == MBB.getParent() && "Basic block is in a different function"); } -void MachineIRBuilderBase::setInstr(MachineInstr &MI) { +void MachineIRBuilderState::setInstr(MachineInstr &MI) { assert(MI.getParent() && "Instruction is not part of a basic block"); setMBB(*MI.getParent()); - State.II = MI.getIterator(); + II = MI.getIterator(); } void MachineIRBuilderBase::setInsertPt(MachineBasicBlock &MBB, @@ -58,6 +57,15 @@ State.InsertedInstr(InsertedInstr); } +void MachineIRBuilderState::recordInsertions( + std::function Inserted) { + InsertedInstr = std::move(Inserted); +} + +void MachineIRBuilderState::stopRecordingInsertions() { + InsertedInstr = nullptr; +} + void MachineIRBuilderBase::recordInsertions( std::function Inserted) { State.InsertedInstr = std::move(Inserted); Index: lib/CodeGen/GlobalISel/RegBankSelect.cpp =================================================================== --- lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -71,7 +71,8 @@ false) RegBankSelect::RegBankSelect(Mode RunningMode) - : MachineFunctionPass(ID), OptMode(RunningMode) { + : MachineFunctionPass(ID), MIRBuilder(MIRBuilderState), + OptMode(RunningMode) { initializeRegBankSelectPass(*PassRegistry::getPassRegistry()); if (RegBankSelectMode.getNumOccurrences() != 0) { OptMode = RegBankSelectMode; Index: lib/CodeGen/GlobalISel/Utils.cpp =================================================================== --- lib/CodeGen/GlobalISel/Utils.cpp +++ lib/CodeGen/GlobalISel/Utils.cpp @@ -235,6 +235,57 @@ return APF; } +Optional llvm::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; +} + void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) { AU.addPreserved(); } Index: lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.cpp +++ lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -665,7 +665,8 @@ MachineBasicBlock &MBB = *I.getParent(); MachineFunction &MF = *MBB.getParent(); MachineRegisterInfo &MRI = MF.getRegInfo(); - MachineIRBuilder MIB(I); + MachineIRBuilderState State; + MachineIRBuilder MIB(I, State); auto MovZ = MIB.buildInstr(AArch64::MOVZXi, &AArch64::GPR64RegClass); MovZ->addOperand(MF, I.getOperand(1)); Index: lib/Target/AArch64/AArch64LegalizerInfo.h =================================================================== --- lib/Target/AArch64/AArch64LegalizerInfo.h +++ lib/Target/AArch64/AArch64LegalizerInfo.h @@ -28,11 +28,11 @@ AArch64LegalizerInfo(const AArch64Subtarget &ST); bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const override; + MachineIRBuilderState &) const override; private: bool legalizeVaArg(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const; + MachineIRBuilderState &State) const; }; } // End llvm namespace. #endif Index: lib/Target/AArch64/AArch64LegalizerInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64LegalizerInfo.cpp +++ lib/Target/AArch64/AArch64LegalizerInfo.cpp @@ -391,13 +391,13 @@ bool AArch64LegalizerInfo::legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const { + MachineIRBuilderState &State) const { switch (MI.getOpcode()) { default: // No idea what to do. return false; case TargetOpcode::G_VAARG: - return legalizeVaArg(MI, MRI, MIRBuilder); + return legalizeVaArg(MI, MRI, State); } llvm_unreachable("expected switch to return"); @@ -405,7 +405,8 @@ bool AArch64LegalizerInfo::legalizeVaArg(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const { + MachineIRBuilderState &State) const { + MachineIRBuilder MIRBuilder(State); MIRBuilder.setInstr(MI); MachineFunction &MF = MIRBuilder.getMF(); unsigned Align = MI.getOperand(2).getImm(); Index: lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp =================================================================== --- lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp +++ lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp @@ -33,13 +33,13 @@ : CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false, /*LegalizerInfo*/ nullptr) {} virtual bool combine(CombinerChangeObserver &Observer, MachineInstr &MI, - MachineIRBuilder &B) const override; + MachineIRBuilderState &State) const override; }; -bool AArch64PreLegalizerCombinerInfo::combine(CombinerChangeObserver &Observer, - MachineInstr &MI, - MachineIRBuilder &B) const { - CombinerHelper Helper(Observer, B); +bool AArch64PreLegalizerCombinerInfo::combine( + CombinerChangeObserver &Observer, MachineInstr &MI, + MachineIRBuilderState &State) const { + CombinerHelper Helper(Observer, State); switch (MI.getOpcode()) { default: @@ -88,7 +88,7 @@ auto *TPC = &getAnalysis(); AArch64PreLegalizerCombinerInfo PCInfo; Combiner C(PCInfo, TPC); - return C.combineMachineInstrs(MF); + return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr); } char AArch64PreLegalizerCombiner::ID = 0; Index: lib/Target/AMDGPU/SIInstructions.td =================================================================== --- lib/Target/AMDGPU/SIInstructions.td +++ lib/Target/AMDGPU/SIInstructions.td @@ -1327,21 +1327,11 @@ (S_XOR_B64 $src0, $src1) >; -def : GCNPat < - (i1 (sub i1:$src0, i1:$src1)), - (S_XOR_B64 $src0, $src1) ->; - let AddedComplexity = 1 in { def : GCNPat < (i1 (add i1:$src0, (i1 -1))), (S_NOT_B64 $src0) >; - -def : GCNPat < - (i1 (sub i1:$src0, (i1 -1))), - (S_NOT_B64 $src0) ->; } def : GCNPat < Index: lib/Target/ARM/ARMLegalizerInfo.h =================================================================== --- lib/Target/ARM/ARMLegalizerInfo.h +++ lib/Target/ARM/ARMLegalizerInfo.h @@ -29,7 +29,7 @@ ARMLegalizerInfo(const ARMSubtarget &ST); bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const override; + MachineIRBuilderState &State) const override; private: void setFCmpLibcallsGNU(); Index: lib/Target/ARM/ARMLegalizerInfo.cpp =================================================================== --- lib/Target/ARM/ARMLegalizerInfo.cpp +++ lib/Target/ARM/ARMLegalizerInfo.cpp @@ -302,9 +302,10 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const { + MachineIRBuilderState &State) const { using namespace TargetOpcode; + MachineIRBuilder MIRBuilder(State); MIRBuilder.setInstr(MI); LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); @@ -328,7 +329,7 @@ auto RetVal = MRI.createGenericVirtualRegister( getLLTForType(*RetTy, MIRBuilder.getMF().getDataLayout())); - auto Status = createLibcall(MIRBuilder, Libcall, {RetVal, RetTy}, + auto Status = createLibcall(State, Libcall, {RetVal, RetTy}, {{MI.getOperand(1).getReg(), ArgTy}, {MI.getOperand(2).getReg(), ArgTy}}); if (Status != LegalizerHelper::Legalized) @@ -371,7 +372,7 @@ for (auto Libcall : Libcalls) { auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32)); auto Status = - createLibcall(MIRBuilder, Libcall.LibcallID, {LibcallResult, RetTy}, + createLibcall(State, Libcall.LibcallID, {LibcallResult, RetTy}, {{MI.getOperand(2).getReg(), ArgTy}, {MI.getOperand(3).getReg(), ArgTy}}); Index: lib/Target/X86/X86FastISel.cpp =================================================================== --- lib/Target/X86/X86FastISel.cpp +++ lib/Target/X86/X86FastISel.cpp @@ -3734,6 +3734,9 @@ switch (VT.SimpleTy) { default: llvm_unreachable("Unexpected value type"); case MVT::i1: + // TODO: Support this properly. + if (Subtarget->hasAVX512()) + return 0; VT = MVT::i8; LLVM_FALLTHROUGH; case MVT::i8: Opc = X86::MOV8ri; break; Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1227,14 +1227,14 @@ default: return nullptr; case LibFunc_expf: case LibFunc_exp: case LibFunc_expl: - ExpName = TLI->getName(LibFunc_exp); + ExpName = "exp"; ID = Intrinsic::exp; LibFnFloat = LibFunc_expf; LibFnDouble = LibFunc_exp; LibFnLongDouble = LibFunc_expl; break; case LibFunc_exp2f: case LibFunc_exp2: case LibFunc_exp2l: - ExpName = TLI->getName(LibFunc_exp2); + ExpName = "exp2"; ID = Intrinsic::exp2; LibFnFloat = LibFunc_exp2f; LibFnDouble = LibFunc_exp2; Index: test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll +++ test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll @@ -45,6 +45,7 @@ ; VERIFY-NEXT: Verify generated machine code ; ENABLED-NEXT: PreLegalizerCombiner ; VERIFY-NEXT: Verify generated machine code +; ENABLED-NEXT: Analysis containing CSE Info ; ENABLED-NEXT: Legalizer ; VERIFY-NEXT: Verify generated machine code ; ENABLED-NEXT: RegBankSelect Index: test/CodeGen/AArch64/GlobalISel/legalize-add.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-add.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-add.mir @@ -1,3 +1,4 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py # RUN: llc -O0 -run-pass=legalizer %s -o - | FileCheck %s @@ -71,20 +72,20 @@ body: | bb.0.entry: liveins: $x0, $x1, $x2, $x3 - ; CHECK-LABEL: name: test_scalar_add_big_nonpow2 - ; CHECK-NOT: G_MERGE_VALUES - ; CHECK-NOT: G_UNMERGE_VALUES - ; CHECK-DAG: [[CARRY0_32:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 - ; CHECK-DAG: [[CARRY0:%[0-9]+]]:_(s1) = G_TRUNC [[CARRY0_32]] - ; CHECK: [[RES_LO:%[0-9]+]]:_(s64), [[CARRY1:%[0-9]+]]:_(s1) = G_UADDE %0, %1, [[CARRY0]] - ; CHECK: [[RES_MI:%[0-9]+]]:_(s64), [[CARRY2:%[0-9]+]]:_(s1) = G_UADDE %1, %2, [[CARRY1]] - ; CHECK: [[RES_HI:%[0-9]+]]:_(s64), {{%.*}}(s1) = G_UADDE %2, %3, [[CARRY2]] - ; CHECK-NOT: G_MERGE_VALUES - ; CHECK-NOT: G_UNMERGE_VALUES - ; CHECK: $x0 = COPY [[RES_LO]] - ; CHECK: $x1 = COPY [[RES_MI]] - ; CHECK: $x2 = COPY [[RES_HI]] + ; CHECK-LABEL: name: test_scalar_add_big_nonpow2 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK: [[COPY3:%[0-9]+]]:_(s64) = COPY $x3 + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[C]](s32) + ; CHECK: [[UADDE:%[0-9]+]]:_(s64), [[UADDE1:%[0-9]+]]:_(s1) = G_UADDE [[COPY]], [[COPY1]], [[TRUNC]] + ; CHECK: [[UADDE2:%[0-9]+]]:_(s64), [[UADDE3:%[0-9]+]]:_(s1) = G_UADDE [[COPY1]], [[COPY2]], [[UADDE1]] + ; CHECK: [[UADDE4:%[0-9]+]]:_(s64), [[UADDE5:%[0-9]+]]:_(s1) = G_UADDE [[COPY2]], [[COPY3]], [[UADDE3]] + ; CHECK: $x0 = COPY [[UADDE]](s64) + ; CHECK: $x1 = COPY [[UADDE2]](s64) + ; CHECK: $x2 = COPY [[UADDE4]](s64) %0(s64) = COPY $x0 %1(s64) = COPY $x1 %2(s64) = COPY $x2 @@ -163,18 +164,18 @@ body: | bb.0.entry: liveins: $q0, $q1, $q2, $q3 - ; CHECK-LABEL: name: test_vector_add_nonpow2 - ; CHECK-NOT: G_EXTRACT - ; CHECK-NOT: G_SEQUENCE - ; CHECK: [[RES_LO:%[0-9]+]]:_(<2 x s64>) = G_ADD %0, %1 - ; CHECK: [[RES_MI:%[0-9]+]]:_(<2 x s64>) = G_ADD %1, %2 - ; CHECK: [[RES_HI:%[0-9]+]]:_(<2 x s64>) = G_ADD %2, %3 - ; CHECK-NOT: G_EXTRACT - ; CHECK-NOT: G_SEQUENCE - ; CHECK: $q0 = COPY [[RES_LO]] - ; CHECK: $q1 = COPY [[RES_MI]] - ; CHECK: $q2 = COPY [[RES_HI]] + ; CHECK-LABEL: name: test_vector_add_nonpow2 + ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s64>) = COPY $q1 + ; CHECK: [[COPY2:%[0-9]+]]:_(<2 x s64>) = COPY $q2 + ; CHECK: [[COPY3:%[0-9]+]]:_(<2 x s64>) = COPY $q3 + ; CHECK: [[ADD:%[0-9]+]]:_(<2 x s64>) = G_ADD [[COPY]], [[COPY1]] + ; CHECK: [[ADD1:%[0-9]+]]:_(<2 x s64>) = G_ADD [[COPY1]], [[COPY2]] + ; CHECK: [[ADD2:%[0-9]+]]:_(<2 x s64>) = G_ADD [[COPY2]], [[COPY3]] + ; CHECK: $q0 = COPY [[ADD]](<2 x s64>) + ; CHECK: $q1 = COPY [[ADD1]](<2 x s64>) + ; CHECK: $q2 = COPY [[ADD2]](<2 x s64>) %0(<2 x s64>) = COPY $q0 %1(<2 x s64>) = COPY $q1 %2(<2 x s64>) = COPY $q2 Index: test/CodeGen/AArch64/GlobalISel/legalize-cmp.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-cmp.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-cmp.mir @@ -40,9 +40,8 @@ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC]], [[C]] - ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC1]], [[C1]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC1]], [[C]] ; CHECK: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[AND]](s32), [[AND1]] ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[ICMP1]](s32) ; CHECK: $w0 = COPY [[COPY3]](s32) Index: test/CodeGen/AArch64/GlobalISel/legalize-div.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-div.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-div.mir @@ -29,19 +29,17 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) ; CHECK: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[TRUNC]], [[C]] ; CHECK: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC1]], [[C1]] - ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] + ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC1]], [[C]] + ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]] ; CHECK: [[SDIV:%[0-9]+]]:_(s32) = G_SDIV [[ASHR]], [[ASHR1]] ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[SDIV]](s32) ; CHECK: $w0 = COPY [[COPY2]](s32) - ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC2]], [[C2]] - ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 + ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC2]], [[C1]] ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC3]], [[C3]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC3]], [[C1]] ; CHECK: [[UDIV:%[0-9]+]]:_(s32) = G_UDIV [[AND]], [[AND1]] ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[UDIV]](s32) ; CHECK: $w0 = COPY [[COPY3]](s32) Index: test/CodeGen/AArch64/GlobalISel/legalize-ext.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-ext.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-ext.mir @@ -93,9 +93,9 @@ ; CHECK: [[FPEXT:%[0-9]+]]:_(s64) = G_FPEXT [[TRUNC12]](s32) ; CHECK: $x0 = COPY [[FPEXT]](s64) ; CHECK: [[C7:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; CHECK: [[COPY7:%[0-9]+]]:_(s32) = COPY [[C7]](s32) + ; CHECK: $w0 = COPY [[COPY7]](s32) ; CHECK: $w0 = COPY [[C7]](s32) - ; CHECK: [[C8:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 - ; CHECK: $w0 = COPY [[C8]](s32) ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF ; CHECK: $w0 = COPY [[DEF]](s32) %0(s64) = COPY $x0 Index: test/CodeGen/AArch64/GlobalISel/legalize-phi.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-phi.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-phi.mir @@ -1,3 +1,4 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=aarch64-unknown-unknown -verify-machineinstrs -run-pass=legalizer %s -o - | FileCheck %s --- | ; ModuleID = '/tmp/test.ll' @@ -296,7 +297,7 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[C1]](s32) ; CHECK: bb.1: ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, [[TRUNC3:%[0-9]+]](s16), %bb.1 + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, %13(s16), %bb.1 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY [[C]](s32) ; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[ANYEXT]], [[COPY1]] @@ -306,7 +307,7 @@ ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C2]] ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[AND]](s32), [[COPY]] ; CHECK: [[TRUNC2:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP]](s32) - ; CHECK: [[TRUNC3]]:_(s16) = G_TRUNC [[ADD]](s32) + ; CHECK: [[TRUNC3:%[0-9]+]]:_(s16) = G_TRUNC [[ADD]](s32) ; CHECK: G_BRCOND [[TRUNC2]](s1), %bb.1 ; CHECK: bb.2: ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 @@ -363,14 +364,14 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[C]](s32) ; CHECK: bb.1: ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, [[COPY1:%[0-9]+]](s16), %bb.1 + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, %7(s16), %bb.1 ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[PHI]](s16) ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ANYEXT]], [[C1]] ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[AND]](s32), [[COPY]] ; CHECK: [[TRUNC2:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP]](s32) - ; CHECK: [[COPY1]]:_(s16) = COPY [[PHI]](s16) + ; CHECK: [[COPY1:%[0-9]+]]:_(s16) = COPY [[PHI]](s16) ; CHECK: G_BRCOND [[TRUNC2]](s1), %bb.1 ; CHECK: bb.2: ; CHECK: $w0 = COPY [[AND]](s32) @@ -441,21 +442,19 @@ ; CHECK: successors: %bb.3(0x80000000) ; CHECK: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[C2]] ; CHECK: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[ADD1]](s32) - ; CHECK: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[ADD1]](s32) ; CHECK: G_BR %bb.3 ; CHECK: bb.2: ; CHECK: successors: %bb.3(0x80000000) - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s16) = G_TRUNC [[C3]](s32) - ; CHECK: [[TRUNC4:%[0-9]+]]:_(s16) = G_TRUNC [[ADD]](s32) + ; CHECK: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[C3]](s32) + ; CHECK: [[TRUNC3:%[0-9]+]]:_(s16) = G_TRUNC [[ADD]](s32) ; CHECK: bb.3: - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC2]](s16), %bb.1, [[TRUNC4]](s16), %bb.2 - ; CHECK: [[PHI1:%[0-9]+]]:_(s16) = G_PHI [[TRUNC1]](s16), %bb.1, [[TRUNC3]](s16), %bb.2 + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC1]](s16), %bb.1, [[TRUNC3]](s16), %bb.2 + ; CHECK: [[PHI1:%[0-9]+]]:_(s16) = G_PHI [[TRUNC1]](s16), %bb.1, [[TRUNC2]](s16), %bb.2 ; CHECK: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ANYEXT]], [[C4]] - ; CHECK: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI1]](s16) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ANYEXT1]], [[C5]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ANYEXT1]], [[C4]] ; CHECK: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[AND]], [[AND1]] ; CHECK: $w0 = COPY [[ADD2]](s32) ; CHECK: RET_ReallyLR implicit $w0 @@ -542,22 +541,21 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP]](s32) ; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[C1]] ; CHECK: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[ADD]](s32) - ; CHECK: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[ADD]](s32) ; CHECK: G_BRCOND [[TRUNC]](s1), %bb.1 ; CHECK: G_BR %bb.2 ; CHECK: bb.1: ; CHECK: successors: %bb.2(0x40000000), %bb.1(0x40000000) - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC2]](s16), %bb.0, [[TRUNC5:%[0-9]+]](s16), %bb.1 - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s8) = G_TRUNC [[PHI]](s16) + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC1]](s16), %bb.0, %20(s16), %bb.1 + ; CHECK: [[TRUNC2:%[0-9]+]]:_(s8) = G_TRUNC [[PHI]](s16) ; CHECK: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ANYEXT]], [[C5]] ; CHECK: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[AND]], [[C2]] ; CHECK: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[ADD1]](s32), [[C3]] - ; CHECK: [[TRUNC4:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP1]](s32) + ; CHECK: [[TRUNC3:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP1]](s32) ; CHECK: [[COPY2:%[0-9]+]]:_(s16) = COPY [[PHI]](s16) - ; CHECK: [[TRUNC5]]:_(s16) = G_TRUNC [[C4]](s32) - ; CHECK: G_BRCOND [[TRUNC4]](s1), %bb.2 + ; CHECK: [[TRUNC4:%[0-9]+]]:_(s16) = G_TRUNC [[C4]](s32) + ; CHECK: G_BRCOND [[TRUNC3]](s1), %bb.2 ; CHECK: G_BR %bb.1 ; CHECK: bb.2: ; CHECK: [[PHI1:%[0-9]+]]:_(s16) = G_PHI [[COPY2]](s16), %bb.1, [[TRUNC1]](s16), %bb.0 Index: test/CodeGen/AArch64/GlobalISel/legalize-rem.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-rem.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-rem.mir @@ -95,10 +95,9 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) ; CHECK: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[TRUNC]], [[C]] ; CHECK: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC1]], [[C1]] - ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] + ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC1]], [[C]] + ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]] ; CHECK: [[SDIV:%[0-9]+]]:_(s32) = G_SDIV [[ASHR]], [[ASHR1]] ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[SDIV]](s32) ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) Index: test/CodeGen/AArch64/GlobalISel/legalize-shift.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-shift.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-shift.mir @@ -36,20 +36,13 @@ ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[ASHR]], [[AND]] ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[ASHR1]](s32) ; CHECK: $w0 = COPY [[COPY2]](s32) - ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC2]], [[C2]] - ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[AND2:%[0-9]+]]:_(s32) = G_AND [[TRUNC3]], [[C3]] - ; CHECK: [[LSHR:%[0-9]+]]:_(s32) = G_LSHR [[AND1]], [[AND2]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC2]], [[C1]] + ; CHECK: [[LSHR:%[0-9]+]]:_(s32) = G_LSHR [[AND1]], [[AND]] ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[LSHR]](s32) ; CHECK: $w0 = COPY [[COPY3]](s32) - ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 - ; CHECK: [[TRUNC5:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[AND3:%[0-9]+]]:_(s32) = G_AND [[TRUNC5]], [[C4]] - ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC4]], [[AND3]] + ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC3]], [[AND]] ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SHL1]](s32) ; CHECK: $w0 = COPY [[COPY4]](s32) %0(s64) = COPY $x0 Index: test/CodeGen/AArch64/GlobalISel/legalize-simple.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-simple.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-simple.mir @@ -43,7 +43,7 @@ - { id: 16, class: _ } body: | ; CHECK-LABEL: name: test_simple - ; CHECK: bb.0.{{[a-zA-Z0-9]+}}: + ; CHECK: bb.0.entry: ; CHECK: successors: %bb.1(0x80000000) ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 ; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s64) @@ -52,20 +52,17 @@ ; CHECK: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[INTTOPTR]](p0) ; CHECK: $x0 = COPY [[PTRTOINT]](s64) ; CHECK: G_BRCOND [[TRUNC]](s1), %bb.1 - ; CHECK: bb.1.{{[a-zA-Z0-9]+}}: + ; CHECK: bb.1.next: ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC2]], [[TRUNC3]] + ; CHECK: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC2]], [[TRUNC2]] ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY [[SELECT]](s32) ; CHECK: $w0 = COPY [[COPY1]](s32) - ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[TRUNC5:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[SELECT1:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC4]], [[TRUNC5]] + ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK: [[SELECT1:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC3]], [[TRUNC3]] ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[SELECT1]](s32) ; CHECK: $w0 = COPY [[COPY2]](s32) - ; CHECK: [[TRUNC6:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[TRUNC7:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[SELECT2:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC6]], [[TRUNC7]] + ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK: [[SELECT2:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC4]], [[TRUNC4]] ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[SELECT2]](s32) ; CHECK: $w0 = COPY [[COPY3]](s32) ; CHECK: [[SELECT3:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC1]], [[TRUNC1]] Index: test/CodeGen/AArch64/O0-pipeline.ll =================================================================== --- test/CodeGen/AArch64/O0-pipeline.ll +++ test/CodeGen/AArch64/O0-pipeline.ll @@ -34,6 +34,7 @@ ; CHECK-NEXT: Module Verifier ; CHECK-NEXT: IRTranslator ; CHECK-NEXT: AArch64PreLegalizerCombiner +; CHECK-NEXT: Analysis containing CSE Info ; CHECK-NEXT: Legalizer ; CHECK-NEXT: RegBankSelect ; CHECK-NEXT: Localizer Index: test/CodeGen/AMDGPU/add_i1.ll =================================================================== --- test/CodeGen/AMDGPU/add_i1.ll +++ test/CodeGen/AMDGPU/add_i1.ll @@ -19,29 +19,3 @@ store i1 %add, i1 addrspace(1)* %out ret void } - -; GCN-LABEL: {{^}}add_i1_cf: -; GCN: v_cmp_ne_u32_e32 vcc, 0, {{v[0-9]+}} -; GCN-NEXT: s_not_b64 s{{\[[0-9]+:[0-9]+\]}}, vcc -define amdgpu_kernel void @add_i1_cf(i1 addrspace(1)* %out, i1 addrspace(1)* %a, i1 addrspace(1)* %b) { -entry: - %tid = call i32 @llvm.amdgcn.workitem.id.x() - %d_cmp = icmp ult i32 %tid, 16 - br i1 %d_cmp, label %if, label %else - -if: - %0 = load volatile i1, i1 addrspace(1)* %a - br label %endif - -else: - %1 = load volatile i1, i1 addrspace(1)* %b - br label %endif - -endif: - %2 = phi i1 [%0, %if], [%1, %else] - %3 = add i1 %2, -1 - store i1 %3, i1 addrspace(1)* %out - ret void -} - -declare i32 @llvm.amdgcn.workitem.id.x() Index: test/CodeGen/AMDGPU/sub_i1.ll =================================================================== --- test/CodeGen/AMDGPU/sub_i1.ll +++ /dev/null @@ -1,47 +0,0 @@ -; RUN: llc -march=amdgcn -mcpu=gfx900 -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s - - -; GCN-LABEL: {{^}}sub_var_var_i1: -; GCN: s_xor_b64 -define amdgpu_kernel void @sub_var_var_i1(i1 addrspace(1)* %out, i1 addrspace(1)* %in0, i1 addrspace(1)* %in1) { - %a = load volatile i1, i1 addrspace(1)* %in0 - %b = load volatile i1, i1 addrspace(1)* %in1 - %sub = sub i1 %a, %b - store i1 %sub, i1 addrspace(1)* %out - ret void -} - -; GCN-LABEL: {{^}}sub_var_imm_i1: -; GCN: s_not_b64 -define amdgpu_kernel void @sub_var_imm_i1(i1 addrspace(1)* %out, i1 addrspace(1)* %in) { - %a = load volatile i1, i1 addrspace(1)* %in - %sub = sub i1 %a, 1 - store i1 %sub, i1 addrspace(1)* %out - ret void -} - -; GCN-LABEL: {{^}}sub_i1_cf: -; GCN: v_cmp_ne_u32_e32 vcc, 0, {{v[0-9]+}} -; GCN-NEXT: s_not_b64 s{{\[[0-9]+:[0-9]+\]}}, vcc -define amdgpu_kernel void @sub_i1_cf(i1 addrspace(1)* %out, i1 addrspace(1)* %a, i1 addrspace(1)* %b) { -entry: - %tid = call i32 @llvm.amdgcn.workitem.id.x() - %d_cmp = icmp ult i32 %tid, 16 - br i1 %d_cmp, label %if, label %else - -if: - %0 = load volatile i1, i1 addrspace(1)* %a - br label %endif - -else: - %1 = load volatile i1, i1 addrspace(1)* %b - br label %endif - -endif: - %2 = phi i1 [%0, %if], [%1, %else] - %3 = sub i1 %2, -1 - store i1 %3, i1 addrspace(1)* %out - ret void -} - -declare i32 @llvm.amdgcn.workitem.id.x() Index: test/CodeGen/X86/GlobalISel/legalize-add.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-add.mir +++ test/CodeGen/X86/GlobalISel/legalize-add.mir @@ -29,16 +29,14 @@ ; X64-LABEL: name: test_add_i1 ; X64: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; X64: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; X64: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; X64: [[ADD:%[0-9]+]]:_(s8) = G_ADD [[TRUNC]], [[TRUNC1]] + ; X64: [[ADD:%[0-9]+]]:_(s8) = G_ADD [[TRUNC]], [[TRUNC]] ; X64: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[ADD]](s8) ; X64: $eax = COPY [[ANYEXT]](s32) ; X64: RET 0 ; X32-LABEL: name: test_add_i1 ; X32: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; X32: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; X32: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; X32: [[ADD:%[0-9]+]]:_(s8) = G_ADD [[TRUNC]], [[TRUNC1]] + ; X32: [[ADD:%[0-9]+]]:_(s8) = G_ADD [[TRUNC]], [[TRUNC]] ; X32: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[ADD]](s8) ; X32: $eax = COPY [[ANYEXT]](s32) ; X32: RET 0 Index: test/CodeGen/X86/GlobalISel/legalize-and-scalar.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-and-scalar.mir +++ test/CodeGen/X86/GlobalISel/legalize-and-scalar.mir @@ -43,8 +43,7 @@ ; CHECK-LABEL: name: test_and_i1 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[AND:%[0-9]+]]:_(s8) = G_AND [[TRUNC]], [[TRUNC1]] + ; CHECK: [[AND:%[0-9]+]]:_(s8) = G_AND [[TRUNC]], [[TRUNC]] ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[AND]](s8) ; CHECK: $eax = COPY [[ANYEXT]](s32) ; CHECK: RET 0 Index: test/CodeGen/X86/GlobalISel/legalize-mul-scalar.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-mul-scalar.mir +++ test/CodeGen/X86/GlobalISel/legalize-mul-scalar.mir @@ -35,8 +35,7 @@ ; CHECK-LABEL: name: test_mul_i1 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[MUL:%[0-9]+]]:_(s8) = G_MUL [[TRUNC]], [[TRUNC1]] + ; CHECK: [[MUL:%[0-9]+]]:_(s8) = G_MUL [[TRUNC]], [[TRUNC]] ; CHECK: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF ; CHECK: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 ; CHECK: [[COPY1:%[0-9]+]]:_(s8) = COPY [[MUL]](s8) Index: test/CodeGen/X86/GlobalISel/legalize-or-scalar.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-or-scalar.mir +++ test/CodeGen/X86/GlobalISel/legalize-or-scalar.mir @@ -43,8 +43,7 @@ ; CHECK-LABEL: name: test_or_i1 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[OR:%[0-9]+]]:_(s8) = G_OR [[TRUNC]], [[TRUNC1]] + ; CHECK: [[OR:%[0-9]+]]:_(s8) = G_OR [[TRUNC]], [[TRUNC]] ; CHECK: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF ; CHECK: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 ; CHECK: [[COPY1:%[0-9]+]]:_(s8) = COPY [[OR]](s8) Index: test/CodeGen/X86/GlobalISel/legalize-sub.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-sub.mir +++ test/CodeGen/X86/GlobalISel/legalize-sub.mir @@ -26,8 +26,7 @@ ; CHECK-LABEL: name: test_sub_i1 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[SUB:%[0-9]+]]:_(s8) = G_SUB [[TRUNC]], [[TRUNC1]] + ; CHECK: [[SUB:%[0-9]+]]:_(s8) = G_SUB [[TRUNC]], [[TRUNC]] ; CHECK: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF ; CHECK: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 ; CHECK: [[COPY1:%[0-9]+]]:_(s8) = COPY [[SUB]](s8) Index: test/CodeGen/X86/GlobalISel/legalize-xor-scalar.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-xor-scalar.mir +++ test/CodeGen/X86/GlobalISel/legalize-xor-scalar.mir @@ -43,8 +43,12 @@ ; CHECK-LABEL: name: test_xor_i1 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) - ; CHECK: [[XOR:%[0-9]+]]:_(s8) = G_XOR [[TRUNC]], [[TRUNC1]] + ; CHECK: [[XOR:%[0-9]+]]:_(s8) = G_XOR [[TRUNC]], [[TRUNC]] + ; CHECK: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF + ; CHECK: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 + ; CHECK: [[COPY1:%[0-9]+]]:_(s8) = COPY [[XOR]](s8) + ; CHECK: [[AND:%[0-9]+]]:_(s8) = G_AND [[COPY1]], [[C]] + ; CHECK: G_STORE [[AND]](s8), [[DEF]](p0) :: (store 1) ; CHECK: RET 0 %0(s32) = COPY $edx %1(s1) = G_TRUNC %0(s32) Index: test/Transforms/LoopVectorize/intrinsic.ll =================================================================== --- test/Transforms/LoopVectorize/intrinsic.ll +++ test/Transforms/LoopVectorize/intrinsic.ll @@ -1247,59 +1247,3 @@ for.end: ; preds = %for.body, %entry ret void } - -declare float @llvm.minimum.f32(float, float) nounwind readnone - -;CHECK-LABEL: @minimum_f32( -;CHECK: llvm.minimum.v4f32 -;CHECK: ret void -define void @minimum_f32(i32 %n, float* noalias %y, float* noalias %x, float* noalias %z) nounwind uwtable { -entry: - %cmp9 = icmp sgt i32 %n, 0 - br i1 %cmp9, label %for.body, label %for.end - -for.body: ; preds = %entry, %for.body - %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %entry ] - %arrayidx = getelementptr inbounds float, float* %y, i64 %indvars.iv - %0 = load float, float* %arrayidx, align 4 - %arrayidx2 = getelementptr inbounds float, float* %z, i64 %indvars.iv - %1 = load float, float* %arrayidx2, align 4 - %call = tail call float @llvm.minimum.f32(float %0, float %1) nounwind readnone - %arrayidx4 = getelementptr inbounds float, float* %x, i64 %indvars.iv - store float %call, float* %arrayidx4, align 4 - %indvars.iv.next = add i64 %indvars.iv, 1 - %lftr.wideiv = trunc i64 %indvars.iv.next to i32 - %exitcond = icmp eq i32 %lftr.wideiv, %n - br i1 %exitcond, label %for.end, label %for.body - -for.end: ; preds = %for.body, %entry - ret void -} - -declare float @llvm.maximum.f32(float, float) nounwind readnone - -;CHECK-LABEL: @maximum_f32( -;CHECK: llvm.maximum.v4f32 -;CHECK: ret void -define void @maximum_f32(i32 %n, float* noalias %y, float* noalias %x, float* noalias %z) nounwind uwtable { -entry: - %cmp9 = icmp sgt i32 %n, 0 - br i1 %cmp9, label %for.body, label %for.end - -for.body: ; preds = %entry, %for.body - %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %entry ] - %arrayidx = getelementptr inbounds float, float* %y, i64 %indvars.iv - %0 = load float, float* %arrayidx, align 4 - %arrayidx2 = getelementptr inbounds float, float* %z, i64 %indvars.iv - %1 = load float, float* %arrayidx2, align 4 - %call = tail call float @llvm.maximum.f32(float %0, float %1) nounwind readnone - %arrayidx4 = getelementptr inbounds float, float* %x, i64 %indvars.iv - store float %call, float* %arrayidx4, align 4 - %indvars.iv.next = add i64 %indvars.iv, 1 - %lftr.wideiv = trunc i64 %indvars.iv.next to i32 - %exitcond = icmp eq i32 %lftr.wideiv, %n - br i1 %exitcond, label %for.end, label %for.body - -for.end: ; preds = %for.body, %entry - ret void -} Index: test/Transforms/Scalarizer/intrinsics.ll =================================================================== --- test/Transforms/Scalarizer/intrinsics.ll +++ test/Transforms/Scalarizer/intrinsics.ll @@ -5,8 +5,6 @@ ; Binary fp declare <2 x float> @llvm.minnum.v2f32(<2 x float>, <2 x float>) -declare <2 x float> @llvm.minimum.v2f32(<2 x float>, <2 x float>) -declare <2 x float> @llvm.maximum.v2f32(<2 x float>, <2 x float>) ; Ternary fp declare <2 x float> @llvm.fma.v2f32(<2 x float>, <2 x float>, <2 x float>) @@ -42,28 +40,6 @@ ret <2 x float> %minnum } -; CHECK-LABEL: @scalarize_minimum_v2f32( -; CHECK: %minimum.i0 = call float @llvm.minimum.f32(float %x.i0, float %y.i0) -; CHECK: %minimum.i1 = call float @llvm.minimum.f32(float %x.i1, float %y.i1) -; CHECK: %minimum.upto0 = insertelement <2 x float> undef, float %minimum.i0, i32 0 -; CHECK: %minimum = insertelement <2 x float> %minimum.upto0, float %minimum.i1, i32 1 -; CHECK: ret <2 x float> %minimum -define <2 x float> @scalarize_minimum_v2f32(<2 x float> %x, <2 x float> %y) #0 { - %minimum = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> %y) - ret <2 x float> %minimum -} - -; CHECK-LABEL: @scalarize_maximum_v2f32( -; CHECK: %maximum.i0 = call float @llvm.maximum.f32(float %x.i0, float %y.i0) -; CHECK: %maximum.i1 = call float @llvm.maximum.f32(float %x.i1, float %y.i1) -; CHECK: %maximum.upto0 = insertelement <2 x float> undef, float %maximum.i0, i32 0 -; CHECK: %maximum = insertelement <2 x float> %maximum.upto0, float %maximum.i1, i32 1 -; CHECK: ret <2 x float> %maximum -define <2 x float> @scalarize_maximum_v2f32(<2 x float> %x, <2 x float> %y) #0 { - %maximum = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> %y) - ret <2 x float> %maximum -} - ; CHECK-LABEL: @scalarize_fma_v2f32( ; CHECK: %fma.i0 = call float @llvm.fma.f32(float %x.i0, float %y.i0, float %z.i0) ; CHECK: %fma.i1 = call float @llvm.fma.f32(float %x.i1, float %y.i1, float %z.i1) Index: tools/llvm-exegesis/lib/Assembler.cpp =================================================================== --- tools/llvm-exegesis/lib/Assembler.cpp +++ tools/llvm-exegesis/lib/Assembler.cpp @@ -120,7 +120,8 @@ if (TII->getReturnOpcode() < TII->getNumOpcodes()) { llvm::BuildMI(MBB, DL, TII->get(TII->getReturnOpcode())); } else { - llvm::MachineIRBuilder MIB(MF); + llvm::MachineIRBuilderState State; + llvm::MachineIRBuilder MIB(MF, State); MIB.setMBB(*MBB); MF.getSubtarget().getCallLowering()->lowerReturn(MIB, nullptr, {}); } Index: unittests/CodeGen/GlobalISel/CMakeLists.txt =================================================================== --- unittests/CodeGen/GlobalISel/CMakeLists.txt +++ unittests/CodeGen/GlobalISel/CMakeLists.txt @@ -13,4 +13,5 @@ LegalizerInfoTest.cpp PatternMatchTest.cpp LegalizerHelperTest.cpp + CSETest.cpp ) Index: unittests/CodeGen/GlobalISel/CSETest.cpp =================================================================== --- /dev/null +++ unittests/CodeGen/GlobalISel/CSETest.cpp @@ -0,0 +1,60 @@ +//===- CSETest.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GISelMITest.h" +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" + +namespace { + +TEST_F(GISelMITest, TestCSE) { + if (!TM) + return; + + LLT s16{LLT::scalar(16)}; + LLT s32{LLT::scalar(32)}; + auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, s16, Copies[0]); + auto MIBInput1 = B.buildInstr(TargetOpcode::G_TRUNC, s16, Copies[1]); + auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, s16, MIBInput, MIBInput); + SmallVector UnmergeRegs; + for (unsigned i = 0; i < 2; ++i) + UnmergeRegs.push_back(MRI->createGenericVirtualRegister(s32)); + GISelCSEInfo CSEInfo; + CSEInfo.analyze(*MF); + B.setCSEInfo(&CSEInfo); + CSEMIRBuilder CSEB(B.getState()); + CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); + unsigned AddReg = MRI->createGenericVirtualRegister(s16); + auto MIBAddCopy = + CSEB.buildInstr(TargetOpcode::G_ADD, AddReg, MIBInput, MIBInput); + ASSERT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY); + auto MIBAdd2 = CSEB.buildInstr(TargetOpcode::G_ADD, s16, MIBInput, MIBInput); + ASSERT_TRUE(&*MIBAdd == &*MIBAdd2); + auto MIBAdd4 = CSEB.buildInstr(TargetOpcode::G_ADD, s16, MIBInput, MIBInput); + ASSERT_TRUE(&*MIBAdd == &*MIBAdd4); + auto MIBAdd5 = CSEB.buildInstr(TargetOpcode::G_ADD, s16, MIBInput, MIBInput1); + ASSERT_TRUE(&*MIBAdd != &*MIBAdd5); + auto MIBCst = CSEB.buildConstant(s32, 0); + auto MIBCst1 = CSEB.buildConstant(s32, 0); + ASSERT_TRUE(&*MIBCst == &*MIBCst1); + // Try the CFing aspect. + auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, s32, MIBCst, MIBCst); + ASSERT_TRUE(&*MIBCF1 == &*MIBCst); + + // Try out building FCONSTANTs. + auto MIBFP0 = CSEB.buildFConstant(s32, 1.0); + auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0); + ASSERT_TRUE(&*MIBFP0 == &*MIBFP0_1); + CSEInfo.print(); + + // Check G_UNMERGE_VALUES + auto MIBUnmerge = CSEB.buildUnmerge(UnmergeRegs, Copies[0]); + auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]); + ASSERT_TRUE(&*MIBUnmerge == &*MIBUnmerge2); +} +} // namespace Index: unittests/CodeGen/GlobalISel/GISelMITest.h =================================================================== --- unittests/CodeGen/GlobalISel/GISelMITest.h +++ unittests/CodeGen/GlobalISel/GISelMITest.h @@ -1,4 +1,4 @@ -//===- LegalizerHelperTest.h +//===- GISelMITest.h //-----------------------------------------------===// // // The LLVM Compiler Infrastructure @@ -7,6 +7,8 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#ifndef LLVM_UNITTEST_CODEGEN_GLOBALISEL_GISELMI_H +#define LLVM_UNITTEST_CODEGEN_GLOBALISEL_GISELMI_H #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" @@ -31,7 +33,7 @@ using namespace llvm; using namespace MIPatternMatch; -void initLLVM() { +static inline void initLLVM() { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); @@ -44,7 +46,7 @@ /// Create a TargetMachine. As we lack a dedicated always available target for /// unittests, we go for "AArch64". -std::unique_ptr createTargetMachine() { +static std::unique_ptr createTargetMachine() { Triple TargetTriple("aarch64--"); std::string Error; const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); @@ -56,10 +58,11 @@ "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive)); } -std::unique_ptr parseMIR(LLVMContext &Context, - std::unique_ptr &MIR, - const TargetMachine &TM, StringRef MIRCode, - const char *FuncName, MachineModuleInfo &MMI) { +static std::unique_ptr parseMIR(LLVMContext &Context, + std::unique_ptr &MIR, + const TargetMachine &TM, + StringRef MIRCode, const char *FuncName, + MachineModuleInfo &MMI) { SMDiagnostic Diagnostic; std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode); MIR = createMIRParser(std::move(MBuffer), Context); @@ -78,7 +81,7 @@ return M; } -std::pair, std::unique_ptr> +static std::pair, std::unique_ptr> createDummyModule(LLVMContext &Context, const TargetMachine &TM, StringRef MIRFunc) { SmallString<512> S; @@ -121,9 +124,9 @@ } } -class LegalizerHelperTest : public ::testing::Test { +class GISelMITest : public ::testing::Test { protected: - LegalizerHelperTest() : ::testing::Test() { + GISelMITest() : ::testing::Test(), B(State) { TM = createTargetMachine(); if (!TM) return; @@ -142,6 +145,7 @@ ModuleMMIPair; SmallVector Copies; MachineBasicBlock *EntryMBB; + MachineIRBuilderState State; MachineIRBuilder B; MachineRegisterInfo *MRI; }; @@ -166,8 +170,8 @@ } \ }; -static bool CheckMachineFunction(const MachineFunction &MF, - StringRef CheckStr) { +static inline bool CheckMachineFunction(const MachineFunction &MF, + StringRef CheckStr) { SmallString<512> Msg; raw_svector_ostream OS(Msg); MF.print(OS); @@ -188,3 +192,4 @@ SM.AddNewSourceBuffer(std::move(OutputBuf), SMLoc()); return FC.CheckInput(SM, OutBuffer, CheckStrings); } +#endif Index: unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -1,4 +1,5 @@ -//===- PatternMatchTest.cpp -----------------------------------------------===// +//===- LegalizerHelperTest.cpp +//-----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,13 +8,13 @@ // //===----------------------------------------------------------------------===// -#include "LegalizerHelperTest.h" +#include "GISelMITest.h" namespace { // Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom, // in which case it becomes CTTZ_ZERO_UNDEF with select. -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ0) { +TEST_F(GISelMITest, LowerBitCountingCTTZ0) { if (!TM) return; @@ -41,7 +42,7 @@ } // CTTZ expansion in terms of CTLZ -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ1) { +TEST_F(GISelMITest, LowerBitCountingCTTZ1) { if (!TM) return; @@ -71,7 +72,7 @@ } // CTTZ expansion in terms of CTPOP -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ2) { +TEST_F(GISelMITest, LowerBitCountingCTTZ2) { if (!TM) return; @@ -98,7 +99,7 @@ } // CTTZ_ZERO_UNDEF expansion in terms of CTTZ -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ3) { +TEST_F(GISelMITest, LowerBitCountingCTTZ3) { if (!TM) return; @@ -122,7 +123,7 @@ } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ0) { +TEST_F(GISelMITest, LowerBitCountingCTLZ0) { if (!TM) return; @@ -149,7 +150,7 @@ } // CTLZ expansion -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ1) { +TEST_F(GISelMITest, LowerBitCountingCTLZ1) { if (!TM) return; @@ -187,7 +188,7 @@ } // CTLZ widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTLZ) { +TEST_F(GISelMITest, WidenBitCountingCTLZ) { if (!TM) return; @@ -219,7 +220,7 @@ } // CTLZ_ZERO_UNDEF widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTLZZeroUndef) { +TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { if (!TM) return; @@ -251,7 +252,7 @@ } // CTPOP widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTPOP) { +TEST_F(GISelMITest, WidenBitCountingCTPOP) { if (!TM) return; @@ -281,7 +282,7 @@ } // CTTZ_ZERO_UNDEF widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ_ZERO_UNDEF) { +TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { if (!TM) return; @@ -312,7 +313,7 @@ } // CTTZ widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ) { +TEST_F(GISelMITest, WidenBitCountingCTTZ) { if (!TM) return; @@ -343,7 +344,7 @@ ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } // UADDO widening. -TEST_F(LegalizerHelperTest, WidenUADDO) { +TEST_F(GISelMITest, WidenUADDO) { if (!TM) return; @@ -381,7 +382,7 @@ } // USUBO widening. -TEST_F(LegalizerHelperTest, WidenUSUBO) { +TEST_F(GISelMITest, WidenUSUBO) { if (!TM) return; Index: unittests/CodeGen/GlobalISel/PatternMatchTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/PatternMatchTest.cpp +++ unittests/CodeGen/GlobalISel/PatternMatchTest.cpp @@ -131,7 +131,8 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); - MachineIRBuilder B(*MF); + MachineIRBuilderState State; + MachineIRBuilder B(*MF, State); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); auto MIBCst = B.buildConstant(LLT::scalar(64), 42); @@ -152,7 +153,8 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); - MachineIRBuilder B(*MF); + MachineIRBuilderState State; + MachineIRBuilder B(*MF, State); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); LLT s64 = LLT::scalar(64); @@ -257,7 +259,7 @@ // Try one of the other constructors of MachineIRBuilder to make sure it's // compatible. - ConstantFoldingMIRBuilder CFB1(*MF); + ConstantFoldingMIRBuilder CFB1(*MF, State); CFB1.setInsertPt(*EntryMBB, EntryMBB->end()); auto MIBCSub = CFB1.buildInstr(TargetOpcode::G_SUB, s32, CFB1.buildConstant(s32, 1), @@ -279,7 +281,8 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); - MachineIRBuilder B(*MF); + MachineIRBuilderState State; + MachineIRBuilder B(*MF, State); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); @@ -350,7 +353,8 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); - MachineIRBuilder B(*MF); + MachineIRBuilderState State; + MachineIRBuilder B(*MF, State); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); LLT s64 = LLT::scalar(64); @@ -406,7 +410,8 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); - MachineIRBuilder B(*MF); + MachineIRBuilderState State; + MachineIRBuilder B(*MF, State); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); @@ -453,7 +458,8 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); - MachineIRBuilder B(*MF); + MachineIRBuilderState State; + MachineIRBuilder B(*MF, State); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); LLT s64 = LLT::scalar(64);