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