10b57cec5SDimitry Andric //===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.h --*- C++ -*-==// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This file implements a version of MachineIRBuilder which CSEs insts within 100b57cec5SDimitry Andric /// a MachineBasicBlock. 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric #ifndef LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H 130b57cec5SDimitry Andric #define LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric namespace llvm { 180b57cec5SDimitry Andric 1981ad6265SDimitry Andric class GISelInstProfileBuilder; 200b57cec5SDimitry Andric /// Defines a builder that does CSE of MachineInstructions using GISelCSEInfo. 210b57cec5SDimitry Andric /// Eg usage. 220b57cec5SDimitry Andric /// 230b57cec5SDimitry Andric /// 240b57cec5SDimitry Andric /// GISelCSEInfo *Info = 250b57cec5SDimitry Andric /// &getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEInfo(); CSEMIRBuilder 260b57cec5SDimitry Andric /// CB(Builder.getState()); CB.setCSEInfo(Info); auto A = CB.buildConstant(s32, 270b57cec5SDimitry Andric /// 42); auto B = CB.buildConstant(s32, 42); assert(A == B); unsigned CReg = 280b57cec5SDimitry Andric /// MRI.createGenericVirtualRegister(s32); auto C = CB.buildConstant(CReg, 42); 290b57cec5SDimitry Andric /// assert(C->getOpcode() == TargetOpcode::COPY); 300b57cec5SDimitry Andric /// Explicitly passing in a register would materialize a copy if possible. 310b57cec5SDimitry Andric /// CSEMIRBuilder also does trivial constant folding for binary ops. 320b57cec5SDimitry Andric class CSEMIRBuilder : public MachineIRBuilder { 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric /// Returns true if A dominates B (within the same basic block). 350b57cec5SDimitry Andric /// Both iterators must be in the same basic block. 360b57cec5SDimitry Andric // 370b57cec5SDimitry Andric // TODO: Another approach for checking dominance is having two iterators and 380b57cec5SDimitry Andric // making them go towards each other until they meet or reach begin/end. Which 390b57cec5SDimitry Andric // approach is better? Should this even change dynamically? For G_CONSTANTS 400b57cec5SDimitry Andric // most of which will be at the top of the BB, the top down approach would be 410b57cec5SDimitry Andric // a better choice. Does IRTranslator placing constants at the beginning still 420b57cec5SDimitry Andric // make sense? Should this change based on Opcode? 430b57cec5SDimitry Andric bool dominates(MachineBasicBlock::const_iterator A, 440b57cec5SDimitry Andric MachineBasicBlock::const_iterator B) const; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric /// For given ID, find a machineinstr in the CSE Map. If found, check if it 470b57cec5SDimitry Andric /// dominates the current insertion point and if not, move it just before the 480b57cec5SDimitry Andric /// current insertion point and return it. If not found, return Null 490b57cec5SDimitry Andric /// MachineInstrBuilder. 500b57cec5SDimitry Andric MachineInstrBuilder getDominatingInstrForID(FoldingSetNodeID &ID, 510b57cec5SDimitry Andric void *&NodeInsertPos); 520b57cec5SDimitry Andric /// Simple check if we can CSE (we have the CSEInfo) or if this Opcode is 530b57cec5SDimitry Andric /// safe to CSE. 540b57cec5SDimitry Andric bool canPerformCSEForOpc(unsigned Opc) const; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric void profileDstOp(const DstOp &Op, GISelInstProfileBuilder &B) const; 570b57cec5SDimitry Andric profileDstOps(ArrayRef<DstOp> Ops,GISelInstProfileBuilder & B)580b57cec5SDimitry Andric void profileDstOps(ArrayRef<DstOp> Ops, GISelInstProfileBuilder &B) const { 590b57cec5SDimitry Andric for (const DstOp &Op : Ops) 600b57cec5SDimitry Andric profileDstOp(Op, B); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric void profileSrcOp(const SrcOp &Op, GISelInstProfileBuilder &B) const; 640b57cec5SDimitry Andric profileSrcOps(ArrayRef<SrcOp> Ops,GISelInstProfileBuilder & B)650b57cec5SDimitry Andric void profileSrcOps(ArrayRef<SrcOp> Ops, GISelInstProfileBuilder &B) const { 660b57cec5SDimitry Andric for (const SrcOp &Op : Ops) 670b57cec5SDimitry Andric profileSrcOp(Op, B); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric void profileMBBOpcode(GISelInstProfileBuilder &B, unsigned Opc) const; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric void profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, 73bdd1243dSDimitry Andric ArrayRef<SrcOp> SrcOps, std::optional<unsigned> Flags, 740b57cec5SDimitry Andric GISelInstProfileBuilder &B) const; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric // Takes a MachineInstrBuilder and inserts it into the CSEMap using the 770b57cec5SDimitry Andric // NodeInsertPos. 780b57cec5SDimitry Andric MachineInstrBuilder memoizeMI(MachineInstrBuilder MIB, void *NodeInsertPos); 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // If we have can CSE an instruction, but still need to materialize to a VReg, 810b57cec5SDimitry Andric // we emit a copy from the CSE'd inst to the VReg. 820b57cec5SDimitry Andric MachineInstrBuilder generateCopiesIfRequired(ArrayRef<DstOp> DstOps, 830b57cec5SDimitry Andric MachineInstrBuilder &MIB); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // If we have can CSE an instruction, but still need to materialize to a VReg, 860b57cec5SDimitry Andric // check if we can generate copies. It's not possible to return a single MIB, 870b57cec5SDimitry Andric // while emitting copies to multiple vregs. 880b57cec5SDimitry Andric bool checkCopyToDefsPossible(ArrayRef<DstOp> DstOps); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric public: 910b57cec5SDimitry Andric // Pull in base class constructors. 920b57cec5SDimitry Andric using MachineIRBuilder::MachineIRBuilder; 930b57cec5SDimitry Andric // Unhide buildInstr 94bdd1243dSDimitry Andric MachineInstrBuilder 95bdd1243dSDimitry Andric buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps, ArrayRef<SrcOp> SrcOps, 96bdd1243dSDimitry Andric std::optional<unsigned> Flag = std::nullopt) override; 970b57cec5SDimitry Andric // Bring in the other overload from the base class. 980b57cec5SDimitry Andric using MachineIRBuilder::buildConstant; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric MachineInstrBuilder buildConstant(const DstOp &Res, 1010b57cec5SDimitry Andric const ConstantInt &Val) override; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Bring in the other overload from the base class. 1040b57cec5SDimitry Andric using MachineIRBuilder::buildFConstant; 1050b57cec5SDimitry Andric MachineInstrBuilder buildFConstant(const DstOp &Res, 1060b57cec5SDimitry Andric const ConstantFP &Val) override; 1070b57cec5SDimitry Andric }; 1080b57cec5SDimitry Andric } // namespace llvm 1090b57cec5SDimitry Andric #endif 110