Index: include/llvm/CodeGen/GlobalISel/CSEInfo.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/CSEInfo.h @@ -0,0 +1,191 @@ +//===- 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; + + 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(); +}; + +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,435 @@ +//===-- 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 { + + const MachineBasicBlock *BBA = A->getParent(); + MachineBasicBlock::const_iterator I = BBA->begin(); + unsigned count = 0; + for (; &*I != A && &*I != B; ++I, ++count) + ; + 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 ot 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); @@ -123,6 +127,7 @@ LLT DstTy = MRI.getType(DstReg); if (isInstUnsupported({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) return false; + CSEMIRBuilder Builder(BuilderState); LLVM_DEBUG(dbgs() << ".. Combine EXT(IMPLICIT_DEF) " << MI;); Builder.setInstr(MI); Builder.buildInstr(TargetOpcode::G_IMPLICIT_DEF, DstReg); @@ -150,6 +155,7 @@ if (NumDefs % NumMergeRegs != 0) return false; + MachineIRBuilder Builder(BuilderState); Builder.setInstr(MI); // Transform to UNMERGEs, for example // %1 = G_MERGE_VALUES %4, %5 @@ -172,6 +178,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 @@ -23,6 +23,7 @@ #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" #include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/RuntimeLibcalls.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; @@ -949,7 +950,7 @@ virtual bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const; + 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/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: 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,353 @@ +//===- 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(); + // Register this as the delegate for handling insertions and deletions of + // instructions. + MF.setDelegate(this); +} + +GISelCSEInfo::~GISelCSEInfo() { + if (MF) + MF->resetDelegate(this); +} + +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; + if (MF) + MF->resetDelegate(this); + 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 +} +/// ----------------------------------------- + +// ---- 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 = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 | + ((uint64_t)Ty.IsVector); + 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()); } @@ -1568,8 +1570,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,8 @@ LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n'); init(MF); const TargetPassConfig &TPC = getAnalysis(); + auto &WrapperPass = getAnalysis(); + auto &CSEInfo = WrapperPass.getCSEInfo(); MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); LegalizerHelper Helper(MF); @@ -103,7 +109,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 +119,14 @@ 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 +148,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); + 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/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: test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll +++ test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll @@ -37,6 +37,7 @@ ; ENABLED: IRTranslator ; ENABLED-NEXT: PreLegalizerCombiner +; ENABLED-NEXT: Analysis containing CSE Info ; ENABLED-NEXT: Legalizer ; ENABLED-NEXT: RegBankSelect ; ENABLED-O0-NEXT: Localizer 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-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' @@ -295,7 +296,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]] @@ -305,7 +306,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 @@ -362,14 +363,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) @@ -440,21 +441,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 @@ -541,22 +540,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: tools/llvm-exegesis/lib/Assembler.cpp =================================================================== --- tools/llvm-exegesis/lib/Assembler.cpp +++ tools/llvm-exegesis/lib/Assembler.cpp @@ -119,7 +119,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, 0); } 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,59 @@ +//===- 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()); + 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); + CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); + 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); +}} 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" @@ -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,7 +58,7 @@ "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive)); } -std::unique_ptr parseMIR(LLVMContext &Context, +static std::unique_ptr parseMIR(LLVMContext &Context, std::unique_ptr &MIR, const TargetMachine &TM, StringRef MIRCode, const char *FuncName, MachineModuleInfo &MMI) { @@ -78,7 +80,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 +123,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 +144,7 @@ ModuleMMIPair; SmallVector Copies; MachineBasicBlock *EntryMBB; + MachineIRBuilderState State; MachineIRBuilder B; MachineRegisterInfo *MRI; }; @@ -166,7 +169,7 @@ } \ }; -static bool CheckMachineFunction(const MachineFunction &MF, +static inline bool CheckMachineFunction(const MachineFunction &MF, StringRef CheckStr) { SmallString<512> Msg; raw_svector_ostream OS(Msg); @@ -188,3 +191,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,4 @@ -//===- PatternMatchTest.cpp -----------------------------------------------===// +//===- LegalizerHelperTest.cpp -----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,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 +41,7 @@ } // CTTZ expansion in terms of CTLZ -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ1) { +TEST_F(GISelMITest, LowerBitCountingCTTZ1) { if (!TM) return; @@ -71,7 +71,7 @@ } // CTTZ expansion in terms of CTPOP -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ2) { +TEST_F(GISelMITest, LowerBitCountingCTTZ2) { if (!TM) return; @@ -98,7 +98,7 @@ } // CTTZ_ZERO_UNDEF expansion in terms of CTTZ -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ3) { +TEST_F(GISelMITest, LowerBitCountingCTTZ3) { if (!TM) return; @@ -122,7 +122,7 @@ } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ0) { +TEST_F(GISelMITest, LowerBitCountingCTLZ0) { if (!TM) return; @@ -149,7 +149,7 @@ } // CTLZ expansion -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ1) { +TEST_F(GISelMITest, LowerBitCountingCTLZ1) { if (!TM) return; @@ -187,7 +187,7 @@ } // CTLZ widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTLZ) { +TEST_F(GISelMITest, WidenBitCountingCTLZ) { if (!TM) return; @@ -219,7 +219,7 @@ } // CTLZ_ZERO_UNDEF widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTLZZeroUndef) { +TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { if (!TM) return; @@ -251,7 +251,7 @@ } // CTPOP widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTPOP) { +TEST_F(GISelMITest, WidenBitCountingCTPOP) { if (!TM) return; @@ -281,7 +281,7 @@ } // CTTZ_ZERO_UNDEF widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ_ZERO_UNDEF) { +TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { if (!TM) return; @@ -312,7 +312,7 @@ } // CTTZ widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ) { +TEST_F(GISelMITest, WidenBitCountingCTTZ) { if (!TM) return; @@ -343,7 +343,7 @@ ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } // UADDO widening. -TEST_F(LegalizerHelperTest, WidenUADDO) { +TEST_F(GISelMITest, WidenUADDO) { if (!TM) return; @@ -381,7 +381,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);