1 //===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.h --*- C++ -*-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// This file implements a version of MachineIRBuilder which CSEs insts within 10 /// a MachineBasicBlock. 11 //===----------------------------------------------------------------------===// 12 #ifndef LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H 13 #define LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H 14 15 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 16 17 namespace llvm { 18 19 class GISelInstProfileBuilder; 20 /// Defines a builder that does CSE of MachineInstructions using GISelCSEInfo. 21 /// Eg usage. 22 /// 23 /// \code 24 /// GISelCSEInfo *Info = 25 /// &getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEInfo(); 26 /// CSEMIRBuilder CB(Builder.getState()); 27 /// CB.setCSEInfo(Info); 28 /// auto A = CB.buildConstant(s32, 42); 29 /// auto B = CB.buildConstant(s32, 42); 30 /// assert(A == B); 31 /// unsigned CReg = MRI.createGenericVirtualRegister(s32); 32 /// auto C = CB.buildConstant(CReg, 42); 33 /// assert(C->getOpcode() == TargetOpcode::COPY); 34 /// \endcode 35 /// 36 /// Explicitly passing in a register would materialize a copy if possible. 37 /// CSEMIRBuilder also does trivial constant folding for binary ops. 38 class CSEMIRBuilder : public MachineIRBuilder { 39 40 /// Returns true if A dominates B (within the same basic block). 41 /// Both iterators must be in the same basic block. 42 // 43 // TODO: Another approach for checking dominance is having two iterators and 44 // making them go towards each other until they meet or reach begin/end. Which 45 // approach is better? Should this even change dynamically? For G_CONSTANTS 46 // most of which will be at the top of the BB, the top down approach would be 47 // a better choice. Does IRTranslator placing constants at the beginning still 48 // make sense? Should this change based on Opcode? 49 bool dominates(MachineBasicBlock::const_iterator A, 50 MachineBasicBlock::const_iterator B) const; 51 52 /// For given ID, find a machineinstr in the CSE Map. If found, check if it 53 /// dominates the current insertion point and if not, move it just before the 54 /// current insertion point and return it. If not found, return Null 55 /// MachineInstrBuilder. 56 MachineInstrBuilder getDominatingInstrForID(FoldingSetNodeID &ID, 57 void *&NodeInsertPos); 58 /// Simple check if we can CSE (we have the CSEInfo) or if this Opcode is 59 /// safe to CSE. 60 bool canPerformCSEForOpc(unsigned Opc) const; 61 62 void profileDstOp(const DstOp &Op, GISelInstProfileBuilder &B) const; 63 64 void profileDstOps(ArrayRef<DstOp> Ops, GISelInstProfileBuilder &B) const { 65 for (const DstOp &Op : Ops) 66 profileDstOp(Op, B); 67 } 68 69 void profileSrcOp(const SrcOp &Op, GISelInstProfileBuilder &B) const; 70 71 void profileSrcOps(ArrayRef<SrcOp> Ops, GISelInstProfileBuilder &B) const { 72 for (const SrcOp &Op : Ops) 73 profileSrcOp(Op, B); 74 } 75 76 void profileMBBOpcode(GISelInstProfileBuilder &B, unsigned Opc) const; 77 78 void profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, 79 ArrayRef<SrcOp> SrcOps, std::optional<unsigned> Flags, 80 GISelInstProfileBuilder &B) const; 81 82 // Takes a MachineInstrBuilder and inserts it into the CSEMap using the 83 // NodeInsertPos. 84 MachineInstrBuilder memoizeMI(MachineInstrBuilder MIB, void *NodeInsertPos); 85 86 // If we have can CSE an instruction, but still need to materialize to a VReg, 87 // we emit a copy from the CSE'd inst to the VReg. 88 MachineInstrBuilder generateCopiesIfRequired(ArrayRef<DstOp> DstOps, 89 MachineInstrBuilder &MIB); 90 91 // If we have can CSE an instruction, but still need to materialize to a VReg, 92 // check if we can generate copies. It's not possible to return a single MIB, 93 // while emitting copies to multiple vregs. 94 bool checkCopyToDefsPossible(ArrayRef<DstOp> DstOps); 95 96 public: 97 // Pull in base class constructors. 98 using MachineIRBuilder::MachineIRBuilder; 99 // Unhide buildInstr 100 MachineInstrBuilder 101 buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps, ArrayRef<SrcOp> SrcOps, 102 std::optional<unsigned> Flag = std::nullopt) override; 103 // Bring in the other overload from the base class. 104 using MachineIRBuilder::buildConstant; 105 106 MachineInstrBuilder buildConstant(const DstOp &Res, 107 const ConstantInt &Val) override; 108 109 // Bring in the other overload from the base class. 110 using MachineIRBuilder::buildFConstant; 111 MachineInstrBuilder buildFConstant(const DstOp &Res, 112 const ConstantFP &Val) override; 113 }; 114 } // namespace llvm 115 #endif 116