Index: include/llvm/CodeGen/GlobalISel/CSEInfo.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/CSEInfo.h @@ -0,0 +1,199 @@ +//===- 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/GISelChangeObserver.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 GISelChangeObserver { + // 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); + + /// 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) const; + + void analyze(MachineFunction &MF); + + void countOpcodeHit(unsigned Opc); + + void print(); + + // Observer API + void erasingInstr(MachineInstr &MI) override; + void createdInstr(MachineInstr &MI) override; + void changingInstr(MachineInstr &MI) override; + void changedInstr(MachineInstr &MI) override; +}; + +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 &addNodeIDFlag(unsigned Flag) 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,113 @@ +//===-- 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()); +/// CB.setCSEInfo(Info); +/// 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); +/// assert(C->getOpcode() == TargetOpcode::COPY); +/// Explicitly passing in a register would materialize a copy if possible. +/// CSEMIRBuilder also does trivial constant folding for binary ops. +class CSEMIRBuilder : public MachineIRBuilder { + + /// 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; + + /// 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. + MachineInstrBuilder getDominatingInstrForID(FoldingSetNodeID &ID, + void *&NodeInsertPos); + /// Simple check if we can CSE (we have the CSEInfo) or if this Opcode is + /// safe to CSE. + bool canPerformCSEForOpc(unsigned Opc) const; + + void profileDstOp(const DstOp &Op, GISelInstProfileBuilder &B) const; + + void profileDstOps(ArrayRef Ops, GISelInstProfileBuilder &B) const { + for (const DstOp &Op : Ops) + profileDstOp(Op, B); + } + + void profileSrcOp(const SrcOp &Op, GISelInstProfileBuilder &B) const; + + void profileSrcOps(ArrayRef Ops, GISelInstProfileBuilder &B) const { + for (const SrcOp &Op : Ops) + profileSrcOp(Op, B); + } + + void profileMBBOpcode(GISelInstProfileBuilder &B, unsigned Opc) const; + + void profileEverything(unsigned Opc, ArrayRef DstOps, + ArrayRef SrcOps, Optional Flags, + GISelInstProfileBuilder &B) const; + + // Takes a MachineInstrBuilder and inserts it into the CSEMap using the + // NodeInsertPos. + MachineInstrBuilder memoizeMI(MachineInstrBuilder MIB, void *NodeInsertPos); + + // If we have can CSE an instruction, but still need to materialize to a VReg, + // we emit a copy from the CSE'd inst to the VReg. + MachineInstrBuilder generateCopiesIfRequired(ArrayRef DstOps, + MachineInstrBuilder &MIB); + + // If we have can CSE an instruction, but still need to materialize to a VReg, + // check if we can generate copies. It's not possible to return a single MIB, + // while emitting copies to multiple vregs. + bool checkCopyToDefsPossible(ArrayRef DstOps); + +public: + // Pull in base class constructors. + using MachineIRBuilder::MachineIRBuilder; + // Unhide buildInstr + MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef DstOps, + ArrayRef SrcOps, + Optional Flag = None) override; + // Bring in the other overload from the base class. + using MachineIRBuilder::buildConstant; + + MachineInstrBuilder buildConstant(const DstOp &Res, + const ConstantInt &Val) override; + + // Bring in the other overload from the base class. + using MachineIRBuilder::buildFConstant; + MachineInstrBuilder buildFConstant(const DstOp &Res, + const ConstantFP &Val) override; +}; +} // 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; @@ -28,7 +29,7 @@ public: Combiner(CombinerInfo &CombinerInfo, const TargetPassConfig *TPC); - bool combineMachineInstrs(MachineFunction &MF); + bool combineMachineInstrs(MachineFunction &MF, GISelCSEInfo *); protected: CombinerInfo &CInfo; 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 : public MachineIRBuilder { Index: include/llvm/CodeGen/GlobalISel/GISelChangeObserver.h =================================================================== --- include/llvm/CodeGen/GlobalISel/GISelChangeObserver.h +++ include/llvm/CodeGen/GlobalISel/GISelChangeObserver.h @@ -15,6 +15,7 @@ #define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/CodeGen/MachineFunction.h" namespace llvm { class MachineInstr; @@ -32,13 +33,13 @@ virtual ~GISelChangeObserver() {} /// An instruction is about to be erased. - virtual void erasingInstr(const MachineInstr &MI) = 0; + virtual void erasingInstr(MachineInstr &MI) = 0; /// An instruction was created and inserted into the function. - virtual void createdInstr(const MachineInstr &MI) = 0; + virtual void createdInstr(MachineInstr &MI) = 0; /// This instruction is about to be mutated in some way. - virtual void changingInstr(const MachineInstr &MI) = 0; + virtual void changingInstr(MachineInstr &MI) = 0; /// This instruction was mutated in some way. - virtual void changedInstr(const MachineInstr &MI) = 0; + virtual void changedInstr(MachineInstr &MI) = 0; /// All the instructions using the given register are being changed. /// For convenience, finishedChangingAllUsesOfReg() will report the completion @@ -51,5 +52,60 @@ }; +/// Simple wrapper observer that takes several observers, and calls +/// each one for each event. If there are multiple observers (say CSE, +/// Legalizer, Combiner), it's sufficient to register this to the machine +/// function as the delegate. +class GISelObserverWrapper : public MachineFunction::Delegate, + public GISelChangeObserver { + SmallVector Observers; + +public: + GISelObserverWrapper() = default; + GISelObserverWrapper(ArrayRef Obs) + : Observers(Obs.begin(), Obs.end()) {} + // Adds an observer. + void addObserver(GISelChangeObserver *O) { Observers.push_back(O); } + // Removes an observer from the list and does nothing if observer is not + // present. + void removeObserver(GISelChangeObserver *O) { + auto It = std::find(Observers.begin(), Observers.end(), O); + if (It != Observers.end()) + Observers.erase(It); + } + // API for Observer. + void erasingInstr(MachineInstr &MI) override { + for (auto &O : Observers) + O->erasingInstr(MI); + } + void createdInstr(MachineInstr &MI) override { + for (auto &O : Observers) + O->createdInstr(MI); + } + void changingInstr(MachineInstr &MI) override { + for (auto &O : Observers) + O->changingInstr(MI); + } + void changedInstr(MachineInstr &MI) override { + for (auto &O : Observers) + O->changedInstr(MI); + } + // API for MachineFunction::Delegate + void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); } + void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); } +}; + +/// 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(); +}; + } // namespace llvm #endif Index: include/llvm/CodeGen/GlobalISel/GISelWorkList.h =================================================================== --- include/llvm/CodeGen/GlobalISel/GISelWorkList.h +++ include/llvm/CodeGen/GlobalISel/GISelWorkList.h @@ -18,6 +18,7 @@ namespace llvm { +class MachineInstr; class MachineFunction; // Worklist which mostly works similar to InstCombineWorkList, but on @@ -25,23 +26,15 @@ // erasing an element doesn't move all elements over one place - instead just // nulls out the element of the vector. // -// This worklist operates on instructions within a particular function. This is -// important for acquiring the rights to modify/replace instructions a -// GISelChangeObserver reports as the observer doesn't have the right to make -// changes to the instructions it sees so we use our access to the -// MachineFunction to establish that it's ok to add a given instruction to the -// worklist. -// // FIXME: Does it make sense to factor out common code with the // instcombinerWorkList? template class GISelWorkList { - MachineFunction *MF; SmallVector Worklist; DenseMap WorklistMap; public: - GISelWorkList(MachineFunction *MF) : MF(MF) {} + GISelWorkList() {} bool empty() const { return WorklistMap.empty(); } @@ -49,27 +42,8 @@ /// Add the specified instruction to the worklist if it isn't already in it. void insert(MachineInstr *I) { - // It would be safe to add this instruction to the worklist regardless but - // for consistency with the const version, check that the instruction we're - // adding would have been accepted if we were given a const pointer instead. - insert(const_cast(I)); - } - - void insert(const MachineInstr *I) { - // Confirm we'd be able to find the non-const pointer we want to schedule if - // we wanted to. We have the right to schedule work that may modify any - // instruction in MF. - assert(I->getParent() && "Expected parent BB"); - assert(I->getParent()->getParent() && "Expected parent function"); - assert((!MF || I->getParent()->getParent() == MF) && - "Expected parent function to be current function or not given"); - - // But don't actually do the search since we can derive it from the const - // pointer. - MachineInstr *NonConstI = const_cast(I); - if (WorklistMap.try_emplace(NonConstI, Worklist.size()).second) { - Worklist.push_back(NonConstI); - } + if (WorklistMap.try_emplace(I, Worklist.size()).second) + Worklist.push_back(I); } /// Remove I from the worklist if it exists. @@ -83,6 +57,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 @@ -21,11 +21,11 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Types.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Support/Allocator.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/Support/Allocator.h" #include #include @@ -444,11 +444,13 @@ // 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. - MachineIRBuilder CurBuilder; + // CSEMIRBuilder CurBuilder; + std::unique_ptr CurBuilder; // Builder set to the entry block (just after ABI lowering instructions). Used // as a convenient location for Constants. - MachineIRBuilder EntryBuilder; + // CSEMIRBuilder EntryBuilder; + std::unique_ptr EntryBuilder; // The MachineFunction currently being translated. MachineFunction *MF; Index: include/llvm/CodeGen/GlobalISel/LegalizerHelper.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -49,9 +49,10 @@ UnableToLegalize, }; - LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer); + LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer, + MachineIRBuilder &B); LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI, - GISelChangeObserver &Observer); + GISelChangeObserver &Observer, MachineIRBuilder &B); /// Replace \p MI by a sequence of legal instructions that can implement the /// same operation. Note that this means \p MI may be deleted, so any iterator @@ -90,7 +91,7 @@ /// Expose MIRBuilder so clients can set their own RecordInsertInstruction /// functions - MachineIRBuilder MIRBuilder; + MachineIRBuilder &MIRBuilder; /// Expose LegalizerInfo so the clients can re-use. const LegalizerInfo &getLegalizerInfo() const { return LI; } 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" @@ -52,6 +53,8 @@ /// @} GISelChangeObserver *Observer; + + GISelCSEInfo *CSEInfo; }; class DstOp { @@ -81,8 +84,6 @@ } } - DstType getType() const { return Ty; } - LLT getLLTTy(const MachineRegisterInfo &MRI) const { switch (Ty) { case DstType::Ty_RC: @@ -95,6 +96,20 @@ llvm_unreachable("Unrecognised DstOp::DstType enum"); } + unsigned getReg() const { + assert(Ty == DstType::Ty_Reg && "Not a register"); + return Reg; + } + + const TargetRegisterClass *getRegClass() const { + switch (Ty) { + case DstType::Ty_RC: + return RC; + default: + llvm_unreachable("Not a RC Operand"); + } + } + DstType getDstOpKind() const { return Ty; } private: @@ -220,16 +235,25 @@ /// Getter for MRI MachineRegisterInfo *getMRI() { return State.MRI; } + const MachineRegisterInfo *getMRI() const { return State.MRI; } /// Getter for the State MachineIRBuilderState &getState() { return State; } /// Getter for the basic block we currently build. - MachineBasicBlock &getMBB() { + const MachineBasicBlock &getMBB() const { assert(State.MBB && "MachineBasicBlock is not set"); return *State.MBB; } + MachineBasicBlock &getMBB() { + return const_cast( + const_cast(this)->getMBB()); + } + + GISelCSEInfo *getCSEInfo() { return State.CSEInfo; } + const GISelCSEInfo *getCSEInfo() const { return State.CSEInfo; } + /// Current insertion point for new instructions. MachineBasicBlock::iterator getInsertPt() { return State.II; } @@ -239,10 +263,12 @@ void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II); /// @} + void setCSEInfo(GISelCSEInfo *Info); + /// \name Setters for the insertion point. /// @{ /// Set the MachineFunction where to build instructions. - void setMF(MachineFunction &); + void setMF(MachineFunction &MF); /// Set the insertion point to the end of \p MBB. /// \pre \p MBB must be contained by getMF(). @@ -534,7 +560,8 @@ /// type. /// /// \return The newly created instruction. - MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val); + virtual MachineInstrBuilder buildConstant(const DstOp &Res, + const ConstantInt &Val); /// Build and insert \p Res = G_CONSTANT \p Val /// @@ -555,7 +582,8 @@ /// \pre \p Res must be a generic virtual register with scalar type. /// /// \return The newly created instruction. - MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val); + virtual MachineInstrBuilder buildFConstant(const DstOp &Res, + const ConstantFP &Val); MachineInstrBuilder buildFConstant(const DstOp &Res, double Val); 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/MachineFunction.h =================================================================== --- include/llvm/CodeGen/MachineFunction.h +++ include/llvm/CodeGen/MachineFunction.h @@ -372,16 +372,18 @@ public: virtual ~Delegate() = default; - virtual void MF_HandleInsertion(const MachineInstr &MI) = 0; - virtual void MF_HandleRemoval(const MachineInstr &MI) = 0; + /// Callback after an insertion. This should not modify the MI directly. + virtual void MF_HandleInsertion(MachineInstr &MI) = 0; + /// Callback before a removal. This should not modify the MI directly. + virtual void MF_HandleRemoval(MachineInstr &MI) = 0; }; private: Delegate *TheDelegate = nullptr; // Callbacks for insertion and removal. - void handleInsertion(const MachineInstr &MI); - void handleRemoval(const MachineInstr &MI); + void handleInsertion(MachineInstr &MI); + void handleRemoval(MachineInstr &MI); friend struct ilist_traits; public: Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -199,6 +199,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/CodeGen/GlobalISel/CMakeLists.txt =================================================================== --- lib/CodeGen/GlobalISel/CMakeLists.txt +++ lib/CodeGen/GlobalISel/CMakeLists.txt @@ -1,4 +1,6 @@ add_llvm_library(LLVMGlobalISel + CSEInfo.cpp + CSEMIRBuilder.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) const { + // 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::erasingInstr(MachineInstr &MI) { handleRemoveInst(&MI); } +void GISelCSEInfo::createdInstr(MachineInstr &MI) { recordNewInstruction(&MI); } +void GISelCSEInfo::changingInstr(MachineInstr &MI) { + // For now, perform erase, followed by insert. + erasingInstr(MI); + createdInstr(MI); +} +void GISelCSEInfo::changedInstr(MachineInstr &MI) { changingInstr(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 +} +/// ----------------------------------------- +// ---- 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); + addNodeIDFlag(MI->getFlags()); + 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::addNodeIDFlag(unsigned Flag) const { + if (Flag) + ID.AddInteger(Flag); + 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/CSEMIRBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp @@ -0,0 +1,231 @@ +//===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.cpp - MIBuilder--*- 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 the CSEMIRBuilder class which CSEs as it builds +/// instructions. +//===----------------------------------------------------------------------===// +// + +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" + +using namespace llvm; + +bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A, + MachineBasicBlock::const_iterator B) const { + auto MBBEnd = getMBB().end(); + if (B == MBBEnd) + return true; + 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; +} + +MachineInstrBuilder +CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID, + void *&NodeInsertPos) { + GISelCSEInfo *CSEInfo = getCSEInfo(); + assert(CSEInfo && "Can't get here without setting CSEInfo"); + MachineBasicBlock *CurMBB = &getMBB(); + MachineInstr *MI = + CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos); + if (MI) { + auto CurrPos = getInsertPt(); + if (!dominates(MI, CurrPos)) + CurMBB->splice(CurrPos, CurMBB, MI); + return MachineInstrBuilder(getMF(), MI); + } + return MachineInstrBuilder(); +} + +bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const { + const GISelCSEInfo *CSEInfo = getCSEInfo(); + if (!CSEInfo || !CSEInfo->shouldCSE(Opc)) + return false; + return true; +} + +void CSEMIRBuilder::profileDstOp(const DstOp &Op, + GISelInstProfileBuilder &B) const { + switch (Op.getDstOpKind()) { + case DstOp::DstType::Ty_RC: + B.addNodeIDRegType(Op.getRegClass()); + break; + default: + B.addNodeIDRegType(Op.getLLTTy(*getMRI())); + break; + } +} + +void CSEMIRBuilder::profileSrcOp(const SrcOp &Op, + GISelInstProfileBuilder &B) const { + switch (Op.getSrcOpKind()) { + case SrcOp::SrcType::Ty_Predicate: + B.addNodeIDImmediate(static_cast(Op.getPredicate())); + break; + default: + B.addNodeIDRegType(Op.getReg()); + break; + } +} + +void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B, + unsigned Opc) const { + // First add the MBB (Local CSE). + B.addNodeIDMBB(&getMBB()); + // Then add the opcode. + B.addNodeIDOpcode(Opc); +} + +void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef DstOps, + ArrayRef SrcOps, + Optional Flags, + GISelInstProfileBuilder &B) const { + + profileMBBOpcode(B, Opc); + // Then add the DstOps. + profileDstOps(DstOps, B); + // Then add the SrcOps. + profileSrcOps(SrcOps, B); + // Add Flags if passed in. + if (Flags) + B.addNodeIDFlag(*Flags); +} + +MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB, + void *NodeInsertPos) { + assert(canPerformCSEForOpc(MIB->getOpcode()) && + "Attempting to CSE illegal op"); + MachineInstr *MIBInstr = MIB; + getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos); + return MIB; +} + +bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef DstOps) { + if (DstOps.size() == 1) + return true; // always possible to emit copy to just 1 vreg. + + return std::all_of(DstOps.begin(), DstOps.end(), [](const DstOp &Op) { + DstOp::DstType DT = Op.getDstOpKind(); + return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC; + }); +} + +MachineInstrBuilder +CSEMIRBuilder::generateCopiesIfRequired(ArrayRef DstOps, + MachineInstrBuilder &MIB) { + assert(checkCopyToDefsPossible(DstOps) && + "Impossible return a single MIB with copies to multiple defs"); + if (DstOps.size() == 1) { + const DstOp &Op = DstOps[0]; + if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg) + return buildCopy(Op.getReg(), MIB->getOperand(0).getReg()); + } + return MIB; +} + +MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, + ArrayRef DstOps, + ArrayRef SrcOps, + Optional Flag) { + 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: { + // Try to constant fold these. + assert(SrcOps.size() == 2 && "Invalid sources"); + assert(DstOps.size() == 1 && "Invalid dsts"); + if (Optional Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(), + SrcOps[1].getReg(), *getMRI())) + return buildConstant(DstOps[0], Cst->getSExtValue()); + break; + } + } + bool CanCopy = checkCopyToDefsPossible(DstOps); + if (!canPerformCSEForOpc(Opc)) + return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); + // If we can CSE this instruction, but involves generating copies to multiple + // regs, give up. This frequently happens to UNMERGEs. + if (!CanCopy) { + auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); + // CSEInfo would have tracked this instruction. Remove it from the temporary + // insts. + getCSEInfo()->handleRemoveInst(&*MIB); + return MIB; + } + FoldingSetNodeID ID; + GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); + void *InsertPos = nullptr; + profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder); + MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); + if (MIB) { + // Handle generating copies here. + return generateCopiesIfRequired(DstOps, MIB); + } + // This instruction does not exist in the CSEInfo. Build it and CSE it. + MachineInstrBuilder NewMIB = + MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); + return memoizeMI(NewMIB, InsertPos); +} + +MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res, + const ConstantInt &Val) { + constexpr unsigned Opc = TargetOpcode::G_CONSTANT; + if (!canPerformCSEForOpc(Opc)) + return MachineIRBuilder::buildConstant(Res, Val); + FoldingSetNodeID ID; + GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); + void *InsertPos = nullptr; + profileMBBOpcode(ProfBuilder, Opc); + profileDstOp(Res, ProfBuilder); + ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val)); + MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); + if (MIB) { + // Handle generating copies here. + return generateCopiesIfRequired({Res}, MIB); + } + MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val); + return memoizeMI(NewMIB, InsertPos); +} + +MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res, + const ConstantFP &Val) { + constexpr unsigned Opc = TargetOpcode::G_FCONSTANT; + if (!canPerformCSEForOpc(Opc)) + return MachineIRBuilder::buildFConstant(Res, Val); + FoldingSetNodeID ID; + GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); + void *InsertPos = nullptr; + profileMBBOpcode(ProfBuilder, Opc); + profileDstOp(Res, ProfBuilder); + ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val)); + MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); + if (MIB) { + // Handle generating copies here. + return generateCopiesIfRequired({Res}, MIB); + } + MachineInstrBuilder NewMIB = MachineIRBuilder::buildFConstant(Res, Val); + return memoizeMI(NewMIB, InsertPos); +} Index: lib/CodeGen/GlobalISel/Combiner.cpp =================================================================== --- lib/CodeGen/GlobalISel/Combiner.cpp +++ lib/CodeGen/GlobalISel/Combiner.cpp @@ -13,6 +13,7 @@ #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/GISelChangeObserver.h" #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" @@ -38,35 +39,31 @@ class WorkListMaintainer : public GISelChangeObserver, public MachineFunction::Delegate { using WorkListTy = GISelWorkList<512>; - MachineFunction &MF; WorkListTy &WorkList; /// The instructions that have been created but we want to report once they /// have their operands. This is only maintained if debug output is requested. SmallPtrSet CreatedInstrs; public: - WorkListMaintainer(MachineFunction &MF, WorkListTy &WorkList) - : GISelChangeObserver(), MF(MF), WorkList(WorkList) { - MF.setDelegate(this); - } + WorkListMaintainer(WorkListTy &WorkList) + : GISelChangeObserver(), WorkList(WorkList) {} virtual ~WorkListMaintainer() { - MF.resetDelegate(this); } - void erasingInstr(const MachineInstr &MI) override { + void erasingInstr(MachineInstr &MI) override { LLVM_DEBUG(dbgs() << "Erased: " << MI << "\n"); WorkList.remove(&MI); } - void createdInstr(const MachineInstr &MI) override { + void createdInstr(MachineInstr &MI) override { LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n"); WorkList.insert(&MI); LLVM_DEBUG(CreatedInstrs.insert(&MI)); } - void changingInstr(const MachineInstr &MI) override { + void changingInstr(MachineInstr &MI) override { LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n"); WorkList.insert(&MI); } - void changedInstr(const MachineInstr &MI) override { + void changedInstr(MachineInstr &MI) override { LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n"); WorkList.insert(&MI); } @@ -80,12 +77,8 @@ LLVM_DEBUG(CreatedInstrs.clear()); } - void MF_HandleInsertion(const MachineInstr &MI) override { - createdInstr(MI); - } - void MF_HandleRemoval(const MachineInstr &MI) override { - erasingInstr(MI); - } + void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); } + void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); } }; } @@ -94,7 +87,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( @@ -103,6 +97,7 @@ MRI = &MF.getRegInfo(); Builder.setMF(MF); + Builder.setCSEInfo(CSEInfo); LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); @@ -116,8 +111,9 @@ // insert with list bottom up, so while we pop_back_val, we'll traverse top // down RPOT. Changed = false; - GISelWorkList<512> WorkList(&MF); - WorkListMaintainer Observer(MF, WorkList); + GISelWorkList<512> WorkList; + WorkListMaintainer Observer(WorkList); + RAIIDelegateInstaller DelInstall(MF, &Observer); for (MachineBasicBlock *MBB : post_order(&MF)) { if (MBB->empty()) continue; Index: lib/CodeGen/GlobalISel/GISelChangeObserver.cpp =================================================================== --- lib/CodeGen/GlobalISel/GISelChangeObserver.cpp +++ lib/CodeGen/GlobalISel/GISelChangeObserver.cpp @@ -29,3 +29,12 @@ changedInstr(*ChangedMI); } +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); } Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -19,6 +19,7 @@ #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" #include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -75,11 +76,16 @@ using namespace llvm; +static cl::opt + EnableCSEInIRTranslator("enable-cse-in-irtranslator", + cl::desc("Should enable CSE in irtranslator"), + cl::Optional, cl::init(true)); char IRTranslator::ID = 0; INITIALIZE_PASS_BEGIN(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI", false, false) INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass) INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI", false, false) @@ -107,18 +113,21 @@ #ifndef NDEBUG /// Verify that every instruction created has the same DILocation as the /// instruction being translated. -class DILocationVerifier : MachineFunction::Delegate { - MachineFunction &MF; +class DILocationVerifier : public GISelChangeObserver { const Instruction *CurrInst = nullptr; public: - DILocationVerifier(MachineFunction &MF) : MF(MF) { MF.setDelegate(this); } - ~DILocationVerifier() { MF.resetDelegate(this); } + DILocationVerifier() = default; + ~DILocationVerifier() = default; const Instruction *getCurrentInst() const { return CurrInst; } void setCurrentInst(const Instruction *Inst) { CurrInst = Inst; } - void MF_HandleInsertion(const MachineInstr &MI) override { + void erasingInstr(MachineInstr &MI) override {} + void changingInstr(MachineInstr &MI) override {} + void changedInstr(MachineInstr &MI) override {} + + void createdInstr(MachineInstr &MI) override { assert(getCurrentInst() && "Inserted instruction without a current MI"); // Only print the check message if we're actually checking it. @@ -129,7 +138,6 @@ assert(CurrInst->getDebugLoc() == MI.getDebugLoc() && "Line info was not transferred to all instructions"); } - void MF_HandleRemoval(const MachineInstr &MI) override {} }; #endif // ifndef NDEBUG @@ -137,6 +145,7 @@ void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); + AU.addRequired(); getSelectionDAGFallbackAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU); } @@ -1551,12 +1560,14 @@ void IRTranslator::finishPendingPhis() { #ifndef NDEBUG - DILocationVerifier Verifier(*MF); + DILocationVerifier Verifier; + GISelObserverWrapper WrapperObserver(&Verifier); + RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver); #endif // ifndef NDEBUG for (auto &Phi : PendingPHIs) { const PHINode *PI = Phi.first; ArrayRef ComponentPHIs = Phi.second; - EntryBuilder.setDebugLoc(PI->getDebugLoc()); + EntryBuilder->setDebugLoc(PI->getDebugLoc()); #ifndef NDEBUG Verifier.setCurrentInst(PI); #endif // ifndef NDEBUG @@ -1597,11 +1608,12 @@ } bool IRTranslator::translate(const Instruction &Inst) { - CurBuilder.setDebugLoc(Inst.getDebugLoc()); - EntryBuilder.setDebugLoc(Inst.getDebugLoc()); + CurBuilder->setDebugLoc(Inst.getDebugLoc()); + EntryBuilder->setDebugLoc(Inst.getDebugLoc()); switch(Inst.getOpcode()) { -#define HANDLE_INST(NUM, OPCODE, CLASS) \ - case Instruction::OPCODE: return translate##OPCODE(Inst, CurBuilder); +#define HANDLE_INST(NUM, OPCODE, CLASS) \ + case Instruction::OPCODE: \ + return translate##OPCODE(Inst, *CurBuilder.get()); #include "llvm/IR/Instruction.def" default: return false; @@ -1610,11 +1622,11 @@ bool IRTranslator::translate(const Constant &C, unsigned Reg) { if (auto CI = dyn_cast(&C)) - EntryBuilder.buildConstant(Reg, *CI); + EntryBuilder->buildConstant(Reg, *CI); else if (auto CF = dyn_cast(&C)) - EntryBuilder.buildFConstant(Reg, *CF); + EntryBuilder->buildFConstant(Reg, *CF); else if (isa(C)) - EntryBuilder.buildUndef(Reg); + EntryBuilder->buildUndef(Reg); else if (isa(C)) { // As we are trying to build a constant val of 0 into a pointer, // insert a cast to make them correct with respect to types. @@ -1622,9 +1634,9 @@ auto *ZeroTy = Type::getIntNTy(C.getContext(), NullSize); auto *ZeroVal = ConstantInt::get(ZeroTy, 0); unsigned ZeroReg = getOrCreateVReg(*ZeroVal); - EntryBuilder.buildCast(Reg, ZeroReg); + EntryBuilder->buildCast(Reg, ZeroReg); } else if (auto GV = dyn_cast(&C)) - EntryBuilder.buildGlobalValue(Reg, GV); + EntryBuilder->buildGlobalValue(Reg, GV); else if (auto CAZ = dyn_cast(&C)) { if (!CAZ->getType()->isVectorTy()) return false; @@ -1636,7 +1648,7 @@ Constant &Elt = *CAZ->getElementValue(i); Ops.push_back(getOrCreateVReg(Elt)); } - EntryBuilder.buildBuildVector(Reg, Ops); + EntryBuilder->buildBuildVector(Reg, Ops); } else if (auto CV = dyn_cast(&C)) { // Return the scalar if it is a <1 x Ty> vector. if (CV->getNumElements() == 1) @@ -1646,11 +1658,12 @@ Constant &Elt = *CV->getElementAsConstant(i); Ops.push_back(getOrCreateVReg(Elt)); } - EntryBuilder.buildBuildVector(Reg, Ops); + EntryBuilder->buildBuildVector(Reg, Ops); } else if (auto CE = dyn_cast(&C)) { switch(CE->getOpcode()) { -#define HANDLE_INST(NUM, OPCODE, CLASS) \ - case Instruction::OPCODE: return translate##OPCODE(*CE, EntryBuilder); +#define HANDLE_INST(NUM, OPCODE, CLASS) \ + case Instruction::OPCODE: \ + return translate##OPCODE(*CE, *EntryBuilder.get()); #include "llvm/IR/Instruction.def" default: return false; @@ -1662,9 +1675,9 @@ for (unsigned i = 0; i < CV->getNumOperands(); ++i) { Ops.push_back(getOrCreateVReg(*CV->getOperand(i))); } - EntryBuilder.buildBuildVector(Reg, Ops); + EntryBuilder->buildBuildVector(Reg, Ops); } else if (auto *BA = dyn_cast(&C)) { - EntryBuilder.buildBlockAddress(Reg, BA); + EntryBuilder->buildBlockAddress(Reg, BA); } else return false; @@ -1681,8 +1694,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(); + EntryBuilder.reset(); + CurBuilder.reset(); } bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { @@ -1690,9 +1703,20 @@ const Function &F = MF->getFunction(); if (F.empty()) return false; + auto &WrapperPass = getAnalysis(); + auto &CSEInfo = WrapperPass.getCSEInfo(); + if (EnableCSEInIRTranslator) { + EntryBuilder = make_unique(CurMF); + EntryBuilder->setCSEInfo(&CSEInfo); + CurBuilder = make_unique(CurMF); + CurBuilder->setCSEInfo(&CSEInfo); + } else { + EntryBuilder = make_unique(); + CurBuilder = make_unique(); + } CLI = MF->getSubtarget().getCallLowering(); - CurBuilder.setMF(*MF); - EntryBuilder.setMF(*MF); + CurBuilder->setMF(*MF); + EntryBuilder->setMF(*MF); MRI = &MF->getRegInfo(); DL = &F.getParent()->getDataLayout(); TPC = &getAnalysis(); @@ -1714,7 +1738,7 @@ // Setup a separate basic-block for the arguments and constants MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock(); MF->push_back(EntryBB); - EntryBuilder.setMBB(*EntryBB); + EntryBuilder->setMBB(*EntryBB); // Create all blocks, in IR order, to preserve the layout. for (const BasicBlock &BB: F) { @@ -1751,7 +1775,7 @@ } } - if (!CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs)) { + if (!CLI->lowerFormalArguments(*EntryBuilder.get(), F, VRegArgs)) { OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", F.getSubprogram(), &F.getEntryBlock()); R << "unable to lower arguments: " << ore::NV("Prototype", F.getType()); @@ -1768,22 +1792,27 @@ assert(VRegs.empty() && "VRegs already populated?"); VRegs.push_back(VArg); } else { - unpackRegs(*ArgIt, VArg, EntryBuilder); + unpackRegs(*ArgIt, VArg, *EntryBuilder.get()); } ArgIt++; } // Need to visit defs before uses when translating instructions. + GISelObserverWrapper WrapperObserver; + if (EnableCSEInIRTranslator) + WrapperObserver.addObserver(&CSEInfo); { ReversePostOrderTraversal RPOT(&F); #ifndef NDEBUG - DILocationVerifier Verifier(*MF); + DILocationVerifier Verifier; + WrapperObserver.addObserver(&Verifier); #endif // ifndef NDEBUG + RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver); for (const BasicBlock *BB : RPOT) { MachineBasicBlock &MBB = getMBB(*BB); // Set the insertion point of all the following translations to // the end of this basic block. - CurBuilder.setMBB(MBB); + CurBuilder->setMBB(MBB); for (const Instruction &Inst : *BB) { #ifndef NDEBUG @@ -1808,6 +1837,9 @@ return false; } } +#ifndef NDEBUG + WrapperObserver.removeObserver(&Verifier); +#endif } finishPendingPhis(); Index: lib/CodeGen/GlobalISel/Legalizer.cpp =================================================================== --- lib/CodeGen/GlobalISel/Legalizer.cpp +++ lib/CodeGen/GlobalISel/Legalizer.cpp @@ -16,6 +16,8 @@ #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/CSEMIRBuilder.h" #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" @@ -33,11 +35,17 @@ using namespace llvm; +static cl::opt + EnableCSEInLegalizer("enable-cse-in-legalizer", + cl::desc("Should enable CSE in Legalizer"), + cl::Optional, cl::init(true)); + char Legalizer::ID = 0; INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE, "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) @@ -48,6 +56,8 @@ void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); getSelectionDAGFallbackAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU); } @@ -81,7 +91,7 @@ LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts) : InstList(Insts), ArtifactList(Arts) {} - void createdInstr(const MachineInstr &MI) override { + void createdInstr(MachineInstr &MI) override { // Only legalize pre-isel generic instructions. // Legalization process could generate Target specific pseudo // instructions with generic types. Don't record them @@ -94,17 +104,17 @@ LLVM_DEBUG(dbgs() << ".. .. New MI: " << MI); } - void erasingInstr(const MachineInstr &MI) override { + void erasingInstr(MachineInstr &MI) override { LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI); InstList.remove(&MI); ArtifactList.remove(&MI); } - void changingInstr(const MachineInstr &MI) override { + void changingInstr(MachineInstr &MI) override { LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI); } - void changedInstr(const MachineInstr &MI) override { + void changedInstr(MachineInstr &MI) override { // When insts change, we want to revisit them to legalize them again. // We'll consider them the same as created. LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI); @@ -120,14 +130,16 @@ 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); const size_t NumBlocks = MF.size(); MachineRegisterInfo &MRI = MF.getRegInfo(); // Populate Insts - InstListTy InstList(&MF); - ArtifactListTy ArtifactList(&MF); + InstListTy InstList; + ArtifactListTy ArtifactList; ReversePostOrderTraversal RPOT(&MF); // Perform legalization bottom up so we can DCE as we legalize. // Traverse BB in RPOT and within each basic block, add insts top down, @@ -146,12 +158,28 @@ InstList.insert(&MI); } } + std::unique_ptr MIRBuilder; + if (EnableCSEInLegalizer) { + MIRBuilder = make_unique(); + MIRBuilder->setCSEInfo(&CSEInfo); + } else + MIRBuilder = make_unique(); + // This observer keeps the worklist updated. LegalizerWorkListManager WorkListObserver(InstList, ArtifactList); - LegalizerHelper Helper(MF, WorkListObserver); + // We want both WorkListObserver as well as CSEInfo to observe all changes. + // Use the wrapper observer. + GISelObserverWrapper WrapperObserver(&WorkListObserver); + if (EnableCSEInLegalizer) + WrapperObserver.addObserver(&CSEInfo); + // Now install the observer as the delegate to MF. + // This will keep all the observers notified about new insertions/deletions. + RAIIDelegateInstaller DelInstall(MF, &WrapperObserver); + LegalizerHelper Helper(MF, WrapperObserver, *MIRBuilder.get()); const LegalizerInfo &LInfo(Helper.getLegalizerInfo()); - LegalizationArtifactCombiner ArtCombiner(Helper.MIRBuilder, MF.getRegInfo(), LInfo); - auto RemoveDeadInstFromLists = [&WorkListObserver](MachineInstr *DeadMI) { - WorkListObserver.erasingInstr(*DeadMI); + LegalizationArtifactCombiner ArtCombiner(*MIRBuilder.get(), MF.getRegInfo(), + LInfo); + auto RemoveDeadInstFromLists = [&WrapperObserver](MachineInstr *DeadMI) { + WrapperObserver.erasingInstr(*DeadMI); }; bool Changed = false; do { Index: lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -31,16 +31,18 @@ using namespace LegalizeActions; LegalizerHelper::LegalizerHelper(MachineFunction &MF, - GISelChangeObserver &Observer) - : MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()), - Observer(Observer) { + GISelChangeObserver &Observer, + MachineIRBuilder &Builder) + : MIRBuilder(Builder), MRI(MF.getRegInfo()), + LI(*MF.getSubtarget().getLegalizerInfo()), Observer(Observer) { MIRBuilder.setMF(MF); MIRBuilder.setChangeObserver(Observer); } LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI, - GISelChangeObserver &Observer) - : MRI(MF.getRegInfo()), LI(LI), Observer(Observer) { + GISelChangeObserver &Observer, + MachineIRBuilder &B) + : MIRBuilder(B), MRI(MF.getRegInfo()), LI(LI), Observer(Observer) { MIRBuilder.setMF(MF); MIRBuilder.setChangeObserver(Observer); } Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -46,6 +46,8 @@ State.II = MI.getIterator(); } +void MachineIRBuilder::setCSEInfo(GISelCSEInfo *Info) { State.CSEInfo = Info; } + void MachineIRBuilder::setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II) { assert(MBB.getParent() == &getMF() && 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/CodeGen/MachineFunction.cpp =================================================================== --- lib/CodeGen/MachineFunction.cpp +++ lib/CodeGen/MachineFunction.cpp @@ -139,12 +139,12 @@ init(); } -void MachineFunction::handleInsertion(const MachineInstr &MI) { +void MachineFunction::handleInsertion(MachineInstr &MI) { if (TheDelegate) TheDelegate->MF_HandleInsertion(MI); } -void MachineFunction::handleRemoval(const MachineInstr &MI) { +void MachineFunction::handleRemoval(MachineInstr &MI) { if (TheDelegate) TheDelegate->MF_HandleRemoval(MI); } Index: lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp =================================================================== --- lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp +++ lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp @@ -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: test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -726,8 +726,8 @@ ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST1]](s64) ; CHECK: [[VAL2:%[0-9]+]]:_(s32) = G_LOAD [[GEP1]](p0) :: (load 4 from %ir.addr + 4) ; CHECK: G_STORE [[VAL1]](s8), [[ADDR]](p0) :: (store 1 into %ir.addr, align 4) -; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4 -; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST2]](s64) +; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY [[CST1]] +; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[COPY]](s64) ; CHECK: G_STORE [[VAL2]](s32), [[GEP2]](p0) :: (store 4 into %ir.addr + 4) define void @test_struct_memops({ i8, i32 }* %addr) { %val = load { i8, i32 }, { i8, i32 }* %addr @@ -954,7 +954,7 @@ ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP %0, [[CST3]](s64) ; CHECK: [[LD4:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load 4 from %ir.addr + 12) ; CHECK: G_STORE [[LD2]](s8), %1(p0) :: (store 1 into %ir.addr2, align 4) -; CHECK: [[CST4:%[0-9]+]]:_(s64) = G_CONSTANT i64 4 +; CHECK: [[CST4:%[0-9]+]]:_(s64) = COPY [[CST1]] ; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_GEP %1, [[CST4]](s64) ; CHECK: G_STORE [[LD3]](s32), [[GEP4]](p0) :: (store 4 into %ir.addr2 + 4) define void @test_extractvalue_agg(%struct.nested* %addr, {i8, i32}* %addr2) { @@ -978,13 +978,13 @@ ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP %0, [[CST3]](s64) ; CHECK: [[LD4:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load 4 from %ir.addr + 12) ; CHECK: G_STORE [[LD1]](s8), %0(p0) :: (store 1 into %ir.addr, align 4) -; CHECK: [[CST4:%[0-9]+]]:_(s64) = G_CONSTANT i64 4 +; CHECK: [[CST4:%[0-9]+]]:_(s64) = COPY [[CST1]] ; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_GEP %0, [[CST4]](s64) ; CHECK: G_STORE [[LD2]](s8), [[GEP4]](p0) :: (store 1 into %ir.addr + 4, align 4) -; CHECK: [[CST5:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 +; CHECK: [[CST5:%[0-9]+]]:_(s64) = COPY [[CST2]] ; CHECK: [[GEP5:%[0-9]+]]:_(p0) = G_GEP %0, [[CST5]](s64) ; CHECK: G_STORE %1(s32), [[GEP5]](p0) :: (store 4 into %ir.addr + 8) -; CHECK: [[CST6:%[0-9]+]]:_(s64) = G_CONSTANT i64 12 +; CHECK: [[CST6:%[0-9]+]]:_(s64) = COPY [[CST3]] ; CHECK: [[GEP6:%[0-9]+]]:_(p0) = G_GEP %0, [[CST6]](s64) ; CHECK: G_STORE [[LD4]](s32), [[GEP6]](p0) :: (store 4 into %ir.addr + 12) define void @test_insertvalue(%struct.nested* %addr, i32 %val) { @@ -1020,7 +1020,7 @@ ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP %1, [[CST1]](s64) ; CHECK: [[LD2:%[0-9]+]]:_(s32) = G_LOAD [[GEP1]](p0) :: (load 4 from %ir.addr2 + 4) ; CHECK: [[LD3:%[0-9]+]]:_(s8) = G_LOAD %0(p0) :: (load 1 from %ir.addr, align 4) -; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4 +; CHECK: [[CST2:%[0-9]+]]:_(s64) = COPY [[CST1]] ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP %0, [[CST2]](s64) ; CHECK: [[LD4:%[0-9]+]]:_(s8) = G_LOAD [[GEP2]](p0) :: (load 1 from %ir.addr + 4, align 4) ; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 @@ -1030,13 +1030,13 @@ ; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_GEP %0, [[CST4]](s64) ; CHECK: [[LD6:%[0-9]+]]:_(s32) = G_LOAD [[GEP4]](p0) :: (load 4 from %ir.addr + 12) ; CHECK: G_STORE [[LD3]](s8), %0(p0) :: (store 1 into %ir.addr, align 4) -; CHECK: [[CST5:%[0-9]+]]:_(s64) = G_CONSTANT i64 4 +; CHECK: [[CST5:%[0-9]+]]:_(s64) = COPY [[CST1]] ; CHECK: [[GEP5:%[0-9]+]]:_(p0) = G_GEP %0, [[CST5]](s64) ; CHECK: G_STORE [[LD1]](s8), [[GEP5]](p0) :: (store 1 into %ir.addr + 4, align 4) -; CHECK: [[CST6:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 +; CHECK: [[CST6:%[0-9]+]]:_(s64) = COPY [[CST3]] ; CHECK: [[GEP6:%[0-9]+]]:_(p0) = G_GEP %0, [[CST6]](s64) ; CHECK: G_STORE [[LD2]](s32), [[GEP6]](p0) :: (store 4 into %ir.addr + 8) -; CHECK: [[CST7:%[0-9]+]]:_(s64) = G_CONSTANT i64 12 +; CHECK: [[CST7:%[0-9]+]]:_(s64) = COPY [[CST4]] ; CHECK: [[GEP7:%[0-9]+]]:_(p0) = G_GEP %0, [[CST7]](s64) ; CHECK: G_STORE [[LD6]](s32), [[GEP7]](p0) :: (store 4 into %ir.addr + 12) define void @test_insertvalue_agg(%struct.nested* %addr, {i8, i32}* %addr2) { Index: test/CodeGen/AArch64/GlobalISel/call-translator-ios.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/call-translator-ios.ll +++ test/CodeGen/AArch64/GlobalISel/call-translator-ios.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple=aarch64-apple-ios -O0 -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s +; RUN: llc -mtriple=aarch64-apple-ios -O0 -stop-after=irtranslator -enable-cse-in-irtranslator=0 -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s ; CHECK-LABEL: name: test_stack_slots Index: test/CodeGen/AArch64/GlobalISel/call-translator.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/call-translator.ll +++ test/CodeGen/AArch64/GlobalISel/call-translator.ll @@ -282,7 +282,7 @@ ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST2]](s64) ; CHECK: G_STORE [[EXTLO]](s64), [[GEP2]](p0) :: (store 8 into stack, align 0) ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp -; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 +; CHECK: [[CST3:%[0-9]+]]:_(s64) = COPY [[CST]] ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST3]](s64) ; CHECK: G_STORE [[EXTHI]](s64), [[GEP3]](p0) :: (store 8 into stack + 8, align 0) define void @test_split_struct([2 x i64]* %ptr) { 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-cmp.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-cmp.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-cmp.mir @@ -13,9 +13,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 @@ -11,19 +11,15 @@ ; 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: [[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: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC3]], [[C3]] + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 + ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC]], [[C1]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC1]], [[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 @@ -7,62 +7,56 @@ ; CHECK-LABEL: name: test_ext ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: $w0 = COPY [[COPY1]](s32) + ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: $w0 = COPY [[COPY2]](s32) + ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: $w0 = COPY [[COPY3]](s32) ; CHECK: $w0 = COPY [[TRUNC]](s32) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC1]](s32) - ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC2]](s32) - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC3]](s32) - ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) - ; CHECK: $x0 = COPY [[COPY1]](s64) + ; CHECK: [[COPY4:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) + ; CHECK: $x0 = COPY [[COPY4]](s64) ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 255 - ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) - ; CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[C]] + ; CHECK: [[COPY5:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) + ; CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY5]], [[C]] ; CHECK: $x0 = COPY [[AND]](s64) - ; CHECK: [[COPY3:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) - ; CHECK: $x0 = COPY [[COPY3]](s64) + ; CHECK: [[COPY6:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) + ; CHECK: $x0 = COPY [[COPY6]](s64) ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 32 - ; CHECK: [[COPY4:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) - ; CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[COPY4]], [[C1]] + ; CHECK: [[COPY7:%[0-9]+]]:_(s64) = COPY [[COPY]](s64) + ; CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[COPY7]], [[C1]] ; CHECK: [[ASHR:%[0-9]+]]:_(s64) = G_ASHR [[SHL]], [[C1]] ; CHECK: $x0 = COPY [[ASHR]](s64) ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 31 - ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC4]], [[C2]] + ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC]], [[C2]] ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C2]] ; CHECK: $w0 = COPY [[ASHR1]](s32) ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 - ; CHECK: [[TRUNC5:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC5]], [[C3]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC]], [[C3]] ; CHECK: $w0 = COPY [[AND1]](s32) - ; CHECK: [[TRUNC6:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC6]](s32) + ; CHECK: [[COPY8:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: $w0 = COPY [[COPY8]](s32) ; CHECK: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 - ; CHECK: [[TRUNC7:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[AND2:%[0-9]+]]:_(s32) = G_AND [[TRUNC7]], [[C4]] + ; CHECK: [[AND2:%[0-9]+]]:_(s32) = G_AND [[TRUNC]], [[C4]] ; CHECK: $w0 = COPY [[AND2]](s32) - ; CHECK: [[TRUNC8:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC8]](s32) + ; CHECK: [[COPY9:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: $w0 = COPY [[COPY9]](s32) ; CHECK: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 - ; CHECK: [[TRUNC9:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[TRUNC9]], [[C5]] + ; CHECK: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[TRUNC]], [[C5]] ; CHECK: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C5]] ; CHECK: $w0 = COPY [[ASHR2]](s32) - ; CHECK: [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 - ; CHECK: [[TRUNC10:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[AND3:%[0-9]+]]:_(s32) = G_AND [[TRUNC10]], [[C6]] - ; CHECK: $w0 = COPY [[AND3]](s32) - ; CHECK: [[TRUNC11:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC11]](s32) - ; CHECK: [[TRUNC12:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: $w0 = COPY [[TRUNC12]](s32) - ; CHECK: [[FPEXT:%[0-9]+]]:_(s64) = G_FPEXT [[TRUNC12]](s32) + ; CHECK: [[COPY10:%[0-9]+]]:_(s32) = COPY [[AND2]](s32) + ; CHECK: $w0 = COPY [[COPY10]](s32) + ; CHECK: [[COPY11:%[0-9]+]]:_(s32) = COPY [[COPY2]](s32) + ; CHECK: $w0 = COPY [[COPY11]](s32) + ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK: $w0 = COPY [[TRUNC1]](s32) + ; CHECK: [[FPEXT:%[0-9]+]]:_(s64) = G_FPEXT [[TRUNC1]](s32) ; CHECK: $x0 = COPY [[FPEXT]](s64) - ; CHECK: [[C7:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 - ; CHECK: $w0 = COPY [[C7]](s32) - ; CHECK: [[C8:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 - ; CHECK: $w0 = COPY [[C8]](s32) + ; CHECK: [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; CHECK: [[COPY12:%[0-9]+]]:_(s32) = COPY [[C6]](s32) + ; CHECK: $w0 = COPY [[COPY12]](s32) + ; CHECK: $w0 = COPY [[C6]](s32) ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF ; CHECK: $w0 = COPY [[DEF]](s32) %0:_(s64) = COPY $x0 Index: test/CodeGen/AArch64/GlobalISel/legalize-load-store-fewerElts.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-load-store-fewerElts.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-load-store-fewerElts.mir @@ -14,11 +14,11 @@ ; CHECK: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1 ; CHECK: [[LOAD:%[0-9]+]]:_(<2 x s32>) = G_LOAD [[COPY]](p0) :: (load 8, align 16) ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s64) + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[COPY2]](s64) ; CHECK: [[LOAD1:%[0-9]+]]:_(<2 x s32>) = G_LOAD [[GEP]](p0) :: (load 8) ; CHECK: G_STORE [[LOAD]](<2 x s32>), [[COPY1]](p0) :: (store 8, align 16) - ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C1]](s64) + ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C]](s64) ; CHECK: G_STORE [[LOAD1]](<2 x s32>), [[GEP1]](p0) :: (store 8) %0:_(p0) = COPY $x0 %1:_(p0) = COPY $x1 @@ -40,11 +40,11 @@ ; CHECK: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1 ; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 8, align 16) ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s64) + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[COPY2]](s64) ; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8) ; CHECK: G_STORE [[LOAD]](s64), [[COPY1]](p0) :: (store 8, align 16) - ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C1]](s64) + ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C]](s64) ; CHECK: G_STORE [[LOAD1]](s64), [[GEP1]](p0) :: (store 8) %0:_(p0) = COPY $x0 %1:_(p0) = COPY $x1 Index: test/CodeGen/AArch64/GlobalISel/legalize-load-store-s128-unaligned.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-load-store-s128-unaligned.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-load-store-s128-unaligned.mir @@ -15,11 +15,11 @@ ; CHECK: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1 ; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 8, align 4) ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s64) + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[COPY2]](s64) ; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8, align 4) ; CHECK: G_STORE [[LOAD]](s64), [[COPY1]](p0) :: (store 8, align 4) - ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C1]](s64) + ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C]](s64) ; CHECK: G_STORE [[LOAD1]](s64), [[GEP1]](p0) :: (store 8, align 4) ; CHECK: RET_ReallyLR %0:_(p0) = COPY $x0 Index: test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir @@ -69,13 +69,13 @@ ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[C]](s32) ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[COPY3]] - ; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[AND]](s32) - ; CHECK: G_STORE [[TRUNC]](s8), [[COPY]](p0) :: (store 1) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[AND]](s32) ; CHECK: G_STORE [[TRUNC1]](s8), [[COPY]](p0) :: (store 1) + ; CHECK: G_STORE [[TRUNC]](s8), [[COPY]](p0) :: (store 1) ; CHECK: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) ; CHECK: G_STORE [[TRUNC2]](s16), [[COPY]](p0) :: (store 2) ; CHECK: G_STORE [[COPY1]](s32), [[COPY]](p0) :: (store 4) 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 @@ -49,19 +49,18 @@ ; 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) - ; CHECK: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY2]], [[TRUNC2]] - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[MUL]](s32) - ; CHECK: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[TRUNC3]], [[COPY3]] - ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) - ; CHECK: $w0 = COPY [[COPY4]](s32) + ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[TRUNC1]](s32) + ; CHECK: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY2]], [[COPY3]] + ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: [[COPY5:%[0-9]+]]:_(s32) = COPY [[MUL]](s32) + ; CHECK: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY4]], [[COPY5]] + ; CHECK: [[COPY6:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; CHECK: $w0 = COPY [[COPY6]](s32) %0:_(s64) = COPY $x0 %1:_(s64) = COPY $x1 %2:_(s8) = G_TRUNC %0(s64) Index: test/CodeGen/AArch64/GlobalISel/legalize-shift.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-shift.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-shift.mir @@ -17,22 +17,14 @@ ; 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 [[TRUNC]], [[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: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SHL1]](s32) - ; CHECK: $w0 = COPY [[COPY4]](s32) + ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[TRUNC]](s32) + ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[AND]] + ; CHECK: [[COPY5:%[0-9]+]]:_(s32) = COPY [[SHL1]](s32) + ; CHECK: $w0 = COPY [[COPY5]](s32) %0:_(s64) = COPY $x0 %1:_(s64) = COPY $x1 %2:_(s8) = G_TRUNC %0(s64) Index: test/CodeGen/AArch64/GlobalISel/legalize-simple.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-simple.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-simple.mir @@ -15,20 +15,17 @@ ; CHECK: G_BRCOND [[TRUNC]](s1), %bb.1 ; CHECK: bb.1: ; 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: [[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: [[COPY3:%[0-9]+]]:_(s32) = COPY [[SELECT2]](s32) + ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[TRUNC2]](s32) + ; CHECK: [[SELECT1:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[COPY2]], [[COPY2]] + ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[SELECT1]](s32) ; CHECK: $w0 = COPY [[COPY3]](s32) + ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[TRUNC2]](s32) + ; CHECK: [[SELECT2:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[COPY4]], [[COPY4]] + ; CHECK: [[COPY5:%[0-9]+]]:_(s32) = COPY [[SELECT2]](s32) + ; CHECK: $w0 = COPY [[COPY5]](s32) ; CHECK: [[SELECT3:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[TRUNC1]], [[TRUNC1]] ; CHECK: [[SELECT4:%[0-9]+]]:_(s64) = G_SELECT [[TRUNC]](s1), [[COPY]], [[COPY]] ; CHECK: $x0 = COPY [[SELECT4]](s64) Index: test/CodeGen/AArch64/GlobalISel/legalize-vaarg.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-vaarg.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-vaarg.mir @@ -15,18 +15,18 @@ ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 ; CHECK: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[COPY]](p0) :: (load 8) ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[LOAD]], [[C]](s64) + ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[LOAD]], [[COPY1]](s64) ; CHECK: G_STORE [[GEP]](p0), [[COPY]](p0) :: (store 8) ; CHECK: [[LOAD1:%[0-9]+]]:_(p0) = G_LOAD [[COPY]](p0) :: (load 8) - ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[LOAD1]], [[C1]](s64) + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[LOAD1]], [[COPY2]](s64) ; CHECK: G_STORE [[GEP1]](p0), [[COPY]](p0) :: (store 8) ; CHECK: [[LOAD2:%[0-9]+]]:_(p0) = G_LOAD [[COPY]](p0) :: (load 8) - ; CHECK: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 15 - ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[LOAD2]], [[C2]](s64) + ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 15 + ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[LOAD2]], [[C1]](s64) ; CHECK: [[PTR_MASK:%[0-9]+]]:_(p0) = G_PTR_MASK [[GEP2]], 4 - ; CHECK: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 - ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[PTR_MASK]], [[C3]](s64) + ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[PTR_MASK]], [[C]](s64) ; CHECK: G_STORE [[GEP3]](p0), [[COPY]](p0) :: (store 8) %0:_(p0) = COPY $x0 Index: test/CodeGen/AArch64/GlobalISel/translate-constant-dag.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/translate-constant-dag.ll +++ test/CodeGen/AArch64/GlobalISel/translate-constant-dag.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -; RUN: llc -mtriple aarch64 -O0 -stop-after=instruction-select -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s +; RUN: llc -mtriple aarch64 -O0 -stop-after=instruction-select -global-isel -verify-machineinstrs %s -o - 2>&1 -enable-cse-in-irtranslator=0 | FileCheck %s %dag = type { { { i8, { i8 } }, { { i8, { i8 } }, { i8 } } }, { { i8, { i8 } }, { i8 } } } Index: test/CodeGen/AArch64/O0-pipeline.ll =================================================================== --- test/CodeGen/AArch64/O0-pipeline.ll +++ test/CodeGen/AArch64/O0-pipeline.ll @@ -32,8 +32,10 @@ ; CHECK-NEXT: Safe Stack instrumentation pass ; CHECK-NEXT: Insert stack protectors ; CHECK-NEXT: Module Verifier +; CHECK-NEXT: Analysis containing CSE Info ; CHECK-NEXT: IRTranslator ; CHECK-NEXT: AArch64PreLegalizerCombiner +; CHECK-NEXT: Analysis containing CSE Info ; CHECK-NEXT: Legalizer ; CHECK-NEXT: RegBankSelect ; CHECK-NEXT: Localizer Index: test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir =================================================================== --- test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir +++ test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir @@ -1,5 +1,5 @@ -# RUN: llc -mtriple arm-linux-gnueabi -mattr=+v5t -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,CLZ -# RUN: llc -mtriple arm-linux-gnueabi -mattr=-v5t -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,LIBCALLS +# RUN: llc -mtriple arm-linux-gnueabi -mattr=+v5t -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=CHECK,CLZ +# RUN: llc -mtriple arm-linux-gnueabi -mattr=-v5t -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=CHECK,LIBCALLS --- | define void @test_ctlz_s32() { ret void } define void @test_ctlz_zero_undef_s32() { ret void } Index: test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir =================================================================== --- test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir +++ test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir @@ -1,7 +1,7 @@ -# RUN: llc -mtriple arm-linux-gnueabi -mattr=+hwdiv-arm -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV -# RUN: llc -mtriple arm-linux-gnueabi -mattr=-hwdiv-arm -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT,SOFT-AEABI -# RUN: llc -mtriple arm-linux-gnu -mattr=+hwdiv-arm -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV -# RUN: llc -mtriple arm-linux-gnu -mattr=-hwdiv-arm -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT,SOFT-DEFAULT +# RUN: llc -mtriple arm-linux-gnueabi -mattr=+hwdiv-arm -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=CHECK,HWDIV +# RUN: llc -mtriple arm-linux-gnueabi -mattr=-hwdiv-arm -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=CHECK,SOFT,SOFT-AEABI +# RUN: llc -mtriple arm-linux-gnu -mattr=+hwdiv-arm -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=CHECK,HWDIV +# RUN: llc -mtriple arm-linux-gnu -mattr=-hwdiv-arm -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=CHECK,SOFT,SOFT-DEFAULT --- | define void @test_sdiv_i32() { ret void } define void @test_udiv_i32() { ret void } Index: test/CodeGen/ARM/GlobalISel/arm-legalize-fp.mir =================================================================== --- test/CodeGen/ARM/GlobalISel/arm-legalize-fp.mir +++ test/CodeGen/ARM/GlobalISel/arm-legalize-fp.mir @@ -1,6 +1,6 @@ -# RUN: llc -mtriple arm-linux-gnueabihf -mattr=+vfp2 -float-abi=hard -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix HARD -# RUN: llc -mtriple arm-linux-gnueabi -mattr=+vfp2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-AEABI -# RUN: llc -mtriple arm-linux-gnu -mattr=+soft-float -float-abi=soft -run-pass=legalizer %s -o - | FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-DEFAULT +# RUN: llc -mtriple arm-linux-gnueabihf -mattr=+vfp2 -float-abi=hard -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefix CHECK -check-prefix HARD +# RUN: llc -mtriple arm-linux-gnueabi -mattr=+vfp2,+soft-float -float-abi=soft -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-AEABI +# RUN: llc -mtriple arm-linux-gnu -mattr=+soft-float -float-abi=soft -run-pass=legalizer %s -o - -enable-cse-in-legalizer=0| FileCheck %s -check-prefix CHECK -check-prefix SOFT -check-prefix SOFT-DEFAULT --- | define void @test_frem_float() { ret void } define void @test_frem_double() { ret void } Index: test/CodeGen/ARM/GlobalISel/arm-param-lowering.ll =================================================================== --- test/CodeGen/ARM/GlobalISel/arm-param-lowering.ll +++ test/CodeGen/ARM/GlobalISel/arm-param-lowering.ll @@ -1,7 +1,7 @@ -; RUN: llc -mtriple arm-unknown -mattr=+vfp2,+v4t -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=ARM -check-prefix=LITTLE -; RUN: llc -mtriple armeb-unknown -mattr=+vfp2,+v4t -global-isel -global-isel-abort=0 -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=ARM -check-prefix=BIG +; RUN: llc -mtriple arm-unknown -mattr=+vfp2,+v4t -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - -enable-cse-in-irtranslator=0| FileCheck %s -check-prefix=CHECK -check-prefix=ARM -check-prefix=LITTLE +; RUN: llc -mtriple armeb-unknown -mattr=+vfp2,+v4t -global-isel -global-isel-abort=0 -stop-after=irtranslator -verify-machineinstrs %s -o - -enable-cse-in-irtranslator=0| FileCheck %s -check-prefix=CHECK -check-prefix=ARM -check-prefix=BIG ; XFAIL: armeb -; RUN: llc -mtriple thumb-unknown -mattr=+vfp2,+v6t2 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=LITTLE -check-prefix=THUMB +; RUN: llc -mtriple thumb-unknown -mattr=+vfp2,+v6t2 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - -enable-cse-in-irtranslator=0| FileCheck %s -check-prefix=CHECK -check-prefix=LITTLE -check-prefix=THUMB declare arm_aapcscc i32* @simple_reg_params_target(i32, i32*) Index: test/CodeGen/Mips/GlobalISel/legalizer/add.mir =================================================================== --- test/CodeGen/Mips/GlobalISel/legalizer/add.mir +++ test/CodeGen/Mips/GlobalISel/legalizer/add.mir @@ -235,9 +235,8 @@ ; MIPS32: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[AND]] ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD1]](s32), [[COPY3]] ; MIPS32: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[COPY2]], [[COPY]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[COPY5:%[0-9]+]]:_(s32) = COPY [[ICMP]](s32) - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY5]], [[C2]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY5]], [[C1]] ; MIPS32: [[ADD3:%[0-9]+]]:_(s32) = G_ADD [[ADD2]], [[AND1]] ; MIPS32: $v0 = COPY [[ADD3]](s32) ; MIPS32: $v1 = COPY [[ADD1]](s32) @@ -290,21 +289,18 @@ ; MIPS32: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[AND]] ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD1]](s32), [[LOAD]] ; MIPS32: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[LOAD1]], [[COPY1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[COPY5:%[0-9]+]]:_(s32) = COPY [[ICMP]](s32) - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY5]], [[C2]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY5]], [[C1]] ; MIPS32: [[ADD3:%[0-9]+]]:_(s32) = G_ADD [[ADD2]], [[AND1]] ; MIPS32: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD3]](s32), [[LOAD1]] ; MIPS32: [[ADD4:%[0-9]+]]:_(s32) = G_ADD [[LOAD2]], [[COPY2]] - ; MIPS32: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[COPY6:%[0-9]+]]:_(s32) = COPY [[ICMP1]](s32) - ; MIPS32: [[AND2:%[0-9]+]]:_(s32) = G_AND [[COPY6]], [[C3]] + ; MIPS32: [[AND2:%[0-9]+]]:_(s32) = G_AND [[COPY6]], [[C1]] ; MIPS32: [[ADD5:%[0-9]+]]:_(s32) = G_ADD [[ADD4]], [[AND2]] ; MIPS32: [[ICMP2:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD5]](s32), [[LOAD2]] ; MIPS32: [[ADD6:%[0-9]+]]:_(s32) = G_ADD [[LOAD3]], [[COPY3]] - ; MIPS32: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[COPY7:%[0-9]+]]:_(s32) = COPY [[ICMP2]](s32) - ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[COPY7]], [[C4]] + ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[COPY7]], [[C1]] ; MIPS32: [[ADD7:%[0-9]+]]:_(s32) = G_ADD [[ADD6]], [[AND3]] ; MIPS32: $v0 = COPY [[ADD1]](s32) ; MIPS32: $v1 = COPY [[ADD3]](s32) Index: test/CodeGen/Mips/GlobalISel/legalizer/rem_and_div.mir =================================================================== --- test/CodeGen/Mips/GlobalISel/legalizer/rem_and_div.mir +++ test/CodeGen/Mips/GlobalISel/legalizer/rem_and_div.mir @@ -36,15 +36,13 @@ ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY2]], [[C]] ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C1]] - ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] + ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C]] + ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]] ; MIPS32: [[SDIV:%[0-9]+]]:_(s32) = G_SDIV [[ASHR]], [[ASHR1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SDIV]](s32) - ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C2]] + ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C]] + ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C]] ; MIPS32: $v0 = COPY [[ASHR2]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -73,15 +71,13 @@ ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY2]], [[C]] ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C1]] - ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] + ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C]] + ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]] ; MIPS32: [[SDIV:%[0-9]+]]:_(s32) = G_SDIV [[ASHR]], [[ASHR1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SDIV]](s32) - ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C2]] + ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C]] + ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C]] ; MIPS32: $v0 = COPY [[ASHR2]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -171,15 +167,13 @@ ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY2]], [[C]] ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C1]] - ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] + ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C]] + ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]] ; MIPS32: [[SREM:%[0-9]+]]:_(s32) = G_SREM [[ASHR]], [[ASHR1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SREM]](s32) - ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C2]] + ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C]] + ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C]] ; MIPS32: $v0 = COPY [[ASHR2]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -208,15 +202,13 @@ ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY2]], [[C]] ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C1]] - ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] + ; MIPS32: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY3]], [[C]] + ; MIPS32: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]] ; MIPS32: [[SREM:%[0-9]+]]:_(s32) = G_SREM [[ASHR]], [[ASHR1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SREM]](s32) - ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C2]] + ; MIPS32: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C]] + ; MIPS32: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C]] ; MIPS32: $v0 = COPY [[ASHR2]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -305,14 +297,13 @@ ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C1]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C]] ; MIPS32: [[UDIV:%[0-9]+]]:_(s32) = G_UDIV [[AND]], [[AND1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[UDIV]](s32) - ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C2]] + ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C1]] + ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C1]] ; MIPS32: $v0 = COPY [[ASHR]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -340,14 +331,13 @@ ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 65535 ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 65535 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C1]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C]] ; MIPS32: [[UDIV:%[0-9]+]]:_(s32) = G_UDIV [[AND]], [[AND1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[UDIV]](s32) - ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C2]] + ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C1]] + ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C1]] ; MIPS32: $v0 = COPY [[ASHR]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -436,14 +426,13 @@ ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C1]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C]] ; MIPS32: [[UREM:%[0-9]+]]:_(s32) = G_UREM [[AND]], [[AND1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[UREM]](s32) - ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C2]] + ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C1]] + ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C1]] ; MIPS32: $v0 = COPY [[ASHR]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 @@ -471,14 +460,13 @@ ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 65535 ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C]] - ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 65535 ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C1]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY3]], [[C]] ; MIPS32: [[UREM:%[0-9]+]]:_(s32) = G_UREM [[AND]], [[AND1]] - ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[UREM]](s32) - ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C2]] - ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C2]] + ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C1]] + ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C1]] ; MIPS32: $v0 = COPY [[ASHR]](s32) ; MIPS32: RetRA implicit $v0 %2:_(s32) = COPY $a0 Index: test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll =================================================================== --- test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll +++ test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o - -enable-cse-in-irtranslator=0 -enable-cse-in-legalizer=0 | FileCheck %s -check-prefixes=MIPS32 define i32 @add_i32(i32 %x, i32 %y) { ; MIPS32-LABEL: add_i32: ; MIPS32: # %bb.0: # %entry Index: test/CodeGen/Mips/GlobalISel/llvm-ir/rem_and_div.ll =================================================================== --- test/CodeGen/Mips/GlobalISel/llvm-ir/rem_and_div.ll +++ test/CodeGen/Mips/GlobalISel/llvm-ir/rem_and_div.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o - -enable-cse-in-irtranslator=0 -enable-cse-in-legalizer=0| FileCheck %s -check-prefixes=MIPS32 ; sdiv define signext i8 @sdiv_i8(i8 signext %a, i8 signext %b) { Index: test/CodeGen/X86/GlobalISel/callingconv.ll =================================================================== --- test/CodeGen/X86/GlobalISel/callingconv.ll +++ test/CodeGen/X86/GlobalISel/callingconv.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32 -; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 +; RUN: llc -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -verify-machineinstrs < %s -o - -enable-cse-in-legalizer=0 -enable-cse-in-irtranslator=0| FileCheck %s --check-prefix=ALL --check-prefix=X32 +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - -enable-cse-in-legalizer=0 -enable-cse-in-irtranslator=0| FileCheck %s --check-prefix=ALL --check-prefix=X64 define i32 @test_ret_i32() { ; X32-LABEL: test_ret_i32: Index: test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll =================================================================== --- test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll +++ test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll @@ -577,7 +577,7 @@ ; X32: ADJCALLSTACKUP32 4, 0, implicit-def $esp, implicit-def $eflags, implicit-def $ssp, implicit $esp, implicit $ssp ; X32: ADJCALLSTACKDOWN32 4, 0, 0, implicit-def $esp, implicit-def $eflags, implicit-def $ssp, implicit $esp, implicit $ssp ; X32: [[COPY1:%[0-9]+]]:_(p0) = COPY $esp - ; X32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; X32: [[C1:%[0-9]+]]:_(s32) = COPY [[C]] ; X32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C1]](s32) ; X32: [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[LOAD1]](s8) ; X32: G_STORE [[SEXT]](s32), [[GEP1]](p0) :: (store 4 into stack, align 0) @@ -585,7 +585,7 @@ ; X32: ADJCALLSTACKUP32 4, 0, implicit-def $esp, implicit-def $eflags, implicit-def $ssp, implicit $esp, implicit $ssp ; X32: ADJCALLSTACKDOWN32 4, 0, 0, implicit-def $esp, implicit-def $eflags, implicit-def $ssp, implicit $esp, implicit $ssp ; X32: [[COPY2:%[0-9]+]]:_(p0) = COPY $esp - ; X32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; X32: [[C2:%[0-9]+]]:_(s32) = COPY [[C]] ; X32: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[COPY2]], [[C2]](s32) ; X32: [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[LOAD1]](s8) ; X32: G_STORE [[ZEXT]](s32), [[GEP2]](p0) :: (store 4 into stack, align 0) 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-memop-scalar.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-memop-scalar.mir +++ test/CodeGen/X86/GlobalISel/legalize-memop-scalar.mir @@ -98,11 +98,11 @@ ; X32: [[DEF:%[0-9]+]]:_(p0) = IMPLICIT_DEF ; X32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[DEF]](p0) :: (load 4, align 8) ; X32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 - ; X32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[C]](s32) + ; X32: [[COPY:%[0-9]+]]:_(s32) = COPY [[C]](s32) + ; X32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[COPY]](s32) ; X32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[GEP]](p0) :: (load 4) ; X32: G_STORE [[LOAD]](s32), [[DEF]](p0) :: (store 4, align 8) - ; X32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 - ; X32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[C1]](s32) + ; X32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[C]](s32) ; X32: G_STORE [[LOAD1]](s32), [[GEP1]](p0) :: (store 4) %0(p0) = IMPLICIT_DEF %1(s64) = G_LOAD %0(p0) :: (load 8) 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-trunc.mir =================================================================== --- test/CodeGen/X86/GlobalISel/legalize-trunc.mir +++ test/CodeGen/X86/GlobalISel/legalize-trunc.mir @@ -23,10 +23,9 @@ ; X32: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[DEF]](s32) ; X32: [[AND:%[0-9]+]]:_(s8) = G_AND [[TRUNC]], [[C]] ; X32: G_STORE [[AND]](s8), [[DEF1]](p0) :: (store 1) - ; X32: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[DEF]](s32) - ; X32: G_STORE [[TRUNC1]](s8), [[DEF1]](p0) :: (store 8) - ; X32: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[DEF]](s32) - ; X32: G_STORE [[TRUNC2]](s16), [[DEF1]](p0) :: (store 16) + ; X32: G_STORE [[TRUNC]](s8), [[DEF1]](p0) :: (store 8) + ; X32: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[DEF]](s32) + ; X32: G_STORE [[TRUNC1]](s16), [[DEF1]](p0) :: (store 16) ; X32: RET 0 ; X64-LABEL: name: trunc_check ; X64: [[DEF:%[0-9]+]]:_(s32) = IMPLICIT_DEF @@ -35,10 +34,9 @@ ; X64: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[DEF]](s32) ; X64: [[AND:%[0-9]+]]:_(s8) = G_AND [[TRUNC]], [[C]] ; X64: G_STORE [[AND]](s8), [[DEF1]](p0) :: (store 1) - ; X64: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[DEF]](s32) - ; X64: G_STORE [[TRUNC1]](s8), [[DEF1]](p0) :: (store 8) - ; X64: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[DEF]](s32) - ; X64: G_STORE [[TRUNC2]](s16), [[DEF1]](p0) :: (store 16) + ; X64: G_STORE [[TRUNC]](s8), [[DEF1]](p0) :: (store 8) + ; X64: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[DEF]](s32) + ; X64: G_STORE [[TRUNC1]](s16), [[DEF1]](p0) :: (store 16) ; X64: RET 0 %0(s32) = IMPLICIT_DEF %1(s1) = G_TRUNC %0(s32) 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: 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,62 @@ +//===- 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}); + 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); + + // Try building G_CONSTANTS. + auto MIBCst = CSEB.buildConstant(s32, 0); + auto MIBCst1 = CSEB.buildConstant(s32, 0); + ASSERT_TRUE(&*MIBCst == &*MIBCst1); + // Try the CFing of BinaryOps. + 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({s32, s32}, 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/GISelChangeObserver.h" #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" @@ -32,7 +34,7 @@ using namespace llvm; using namespace MIPatternMatch; -void initLLVM() { +static inline void initLLVM() { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); @@ -45,7 +47,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); @@ -53,15 +55,16 @@ return nullptr; TargetOptions Options; - return std::unique_ptr(static_cast( - T->createTargetMachine("AArch64", "", "", Options, None, None, - CodeGenOpt::Aggressive))); + return std::unique_ptr( + static_cast(T->createTargetMachine( + "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); @@ -80,7 +83,7 @@ return M; } -std::pair, std::unique_ptr> +static std::pair, std::unique_ptr> createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM, StringRef MIRFunc) { SmallString<512> S; @@ -123,9 +126,9 @@ } } -class LegalizerHelperTest : public ::testing::Test { +class GISelMITest : public ::testing::Test { protected: - LegalizerHelperTest() : ::testing::Test() { + GISelMITest() : ::testing::Test() { TM = createTargetMachine(); if (!TM) return; @@ -168,8 +171,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); @@ -190,3 +193,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,21 +8,21 @@ // //===----------------------------------------------------------------------===// -#include "LegalizerHelperTest.h" +#include "GISelMITest.h" namespace { class DummyGISelObserver : public GISelChangeObserver { public: - void changingInstr(const MachineInstr &MI) override {} - void changedInstr(const MachineInstr &MI) override {} - void createdInstr(const MachineInstr &MI) override {} - void erasingInstr(const MachineInstr &MI) override {} + void changingInstr(MachineInstr &MI) override {} + void changedInstr(MachineInstr &MI) override {} + void createdInstr(MachineInstr &MI) override {} + void erasingInstr(MachineInstr &MI) override {} }; // 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; @@ -33,7 +34,7 @@ B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); @@ -51,7 +52,7 @@ } // CTTZ expansion in terms of CTLZ -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ1) { +TEST_F(GISelMITest, LowerBitCountingCTTZ1) { if (!TM) return; @@ -63,7 +64,7 @@ B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); @@ -83,7 +84,7 @@ } // CTTZ expansion in terms of CTPOP -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ2) { +TEST_F(GISelMITest, LowerBitCountingCTTZ2) { if (!TM) return; @@ -95,7 +96,7 @@ B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); @@ -112,7 +113,7 @@ } // CTTZ_ZERO_UNDEF expansion in terms of CTTZ -TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ3) { +TEST_F(GISelMITest, LowerBitCountingCTTZ3) { if (!TM) return; @@ -124,7 +125,7 @@ {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); @@ -137,7 +138,7 @@ } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ0) { +TEST_F(GISelMITest, LowerBitCountingCTLZ0) { if (!TM) return; @@ -149,7 +150,7 @@ B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); @@ -166,7 +167,7 @@ } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF if the latter is a libcall -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZLibcall) { +TEST_F(GISelMITest, LowerBitCountingCTLZLibcall) { if (!TM) return; @@ -178,7 +179,7 @@ B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); @@ -195,7 +196,7 @@ } // CTLZ expansion -TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ1) { +TEST_F(GISelMITest, LowerBitCountingCTLZ1) { if (!TM) return; @@ -209,7 +210,7 @@ auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, s8) == LegalizerHelper::LegalizeResult::Legalized); @@ -234,7 +235,7 @@ } // CTLZ widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTLZ) { +TEST_F(GISelMITest, WidenBitCountingCTLZ) { if (!TM) return; @@ -249,7 +250,7 @@ auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBCTLZ, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); @@ -267,7 +268,7 @@ } // CTLZ_ZERO_UNDEF widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTLZZeroUndef) { +TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { if (!TM) return; @@ -283,7 +284,7 @@ B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBCTLZ_ZU, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); @@ -301,7 +302,7 @@ } // CTPOP widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTPOP) { +TEST_F(GISelMITest, WidenBitCountingCTPOP) { if (!TM) return; @@ -316,7 +317,7 @@ auto MIBCTPOP = B.buildInstr(TargetOpcode::G_CTPOP, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBCTPOP, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); @@ -332,7 +333,7 @@ } // CTTZ_ZERO_UNDEF widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ_ZERO_UNDEF) { +TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { if (!TM) return; @@ -348,7 +349,7 @@ B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBCTTZ_ZERO_UNDEF, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); @@ -364,7 +365,7 @@ } // CTTZ widening. -TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ) { +TEST_F(GISelMITest, WidenBitCountingCTTZ) { if (!TM) return; @@ -379,7 +380,7 @@ auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBCTTZ, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); @@ -396,7 +397,7 @@ ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } // UADDO widening. -TEST_F(LegalizerHelperTest, WidenUADDO) { +TEST_F(GISelMITest, WidenUADDO) { if (!TM) return; @@ -413,7 +414,7 @@ B.buildInstr(TargetOpcode::G_UADDO, {s8, CarryReg}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBUAddO, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); @@ -433,7 +434,7 @@ } // USUBO widening. -TEST_F(LegalizerHelperTest, WidenUSUBO) { +TEST_F(GISelMITest, WidenUSUBO) { if (!TM) return; @@ -450,7 +451,7 @@ B.buildInstr(TargetOpcode::G_USUBO, {s8, CarryReg}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; - LegalizerHelper Helper(*MF, Info, Observer); + LegalizerHelper Helper(*MF, Info, Observer, B); ASSERT_TRUE(Helper.widenScalar(*MIBUSUBO, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); Index: unittests/CodeGen/GlobalISel/PatternMatchTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/PatternMatchTest.cpp +++ unittests/CodeGen/GlobalISel/PatternMatchTest.cpp @@ -132,6 +132,7 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); + MachineIRBuilderState State; MachineIRBuilder B(*MF); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); @@ -153,6 +154,7 @@ SmallVector Copies; collectCopies(Copies, MF); MachineBasicBlock *EntryMBB = &*MF->begin(); + MachineIRBuilderState State; MachineIRBuilder B(*MF); MachineRegisterInfo &MRI = MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end());