10b57cec5SDimitry Andric //===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.cpp - MIBuilder--*- 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 the CSEMIRBuilder class which CSEs as it builds 100b57cec5SDimitry Andric /// instructions. 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" 15*81ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/CSEInfo.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" 17349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 18349cc55cSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 19e8d8bef9SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A, 240b57cec5SDimitry Andric MachineBasicBlock::const_iterator B) const { 250b57cec5SDimitry Andric auto MBBEnd = getMBB().end(); 260b57cec5SDimitry Andric if (B == MBBEnd) 270b57cec5SDimitry Andric return true; 280b57cec5SDimitry Andric assert(A->getParent() == B->getParent() && 290b57cec5SDimitry Andric "Iterators should be in same block"); 300b57cec5SDimitry Andric const MachineBasicBlock *BBA = A->getParent(); 310b57cec5SDimitry Andric MachineBasicBlock::const_iterator I = BBA->begin(); 320b57cec5SDimitry Andric for (; &*I != A && &*I != B; ++I) 330b57cec5SDimitry Andric ; 340b57cec5SDimitry Andric return &*I == A; 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric MachineInstrBuilder 380b57cec5SDimitry Andric CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID, 390b57cec5SDimitry Andric void *&NodeInsertPos) { 400b57cec5SDimitry Andric GISelCSEInfo *CSEInfo = getCSEInfo(); 410b57cec5SDimitry Andric assert(CSEInfo && "Can't get here without setting CSEInfo"); 420b57cec5SDimitry Andric MachineBasicBlock *CurMBB = &getMBB(); 430b57cec5SDimitry Andric MachineInstr *MI = 440b57cec5SDimitry Andric CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos); 450b57cec5SDimitry Andric if (MI) { 460b57cec5SDimitry Andric CSEInfo->countOpcodeHit(MI->getOpcode()); 470b57cec5SDimitry Andric auto CurrPos = getInsertPt(); 48e8d8bef9SDimitry Andric auto MII = MachineBasicBlock::iterator(MI); 49e8d8bef9SDimitry Andric if (MII == CurrPos) { 50e8d8bef9SDimitry Andric // Move the insert point ahead of the instruction so any future uses of 51e8d8bef9SDimitry Andric // this builder will have the def ready. 52e8d8bef9SDimitry Andric setInsertPt(*CurMBB, std::next(MII)); 53e8d8bef9SDimitry Andric } else if (!dominates(MI, CurrPos)) { 540b57cec5SDimitry Andric CurMBB->splice(CurrPos, CurMBB, MI); 55e8d8bef9SDimitry Andric } 560b57cec5SDimitry Andric return MachineInstrBuilder(getMF(), MI); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric return MachineInstrBuilder(); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const { 620b57cec5SDimitry Andric const GISelCSEInfo *CSEInfo = getCSEInfo(); 630b57cec5SDimitry Andric if (!CSEInfo || !CSEInfo->shouldCSE(Opc)) 640b57cec5SDimitry Andric return false; 650b57cec5SDimitry Andric return true; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric void CSEMIRBuilder::profileDstOp(const DstOp &Op, 690b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 700b57cec5SDimitry Andric switch (Op.getDstOpKind()) { 710b57cec5SDimitry Andric case DstOp::DstType::Ty_RC: 720b57cec5SDimitry Andric B.addNodeIDRegType(Op.getRegClass()); 730b57cec5SDimitry Andric break; 74e8d8bef9SDimitry Andric case DstOp::DstType::Ty_Reg: { 75e8d8bef9SDimitry Andric // Regs can have LLT&(RB|RC). If those exist, profile them as well. 76e8d8bef9SDimitry Andric B.addNodeIDReg(Op.getReg()); 77e8d8bef9SDimitry Andric break; 78e8d8bef9SDimitry Andric } 790b57cec5SDimitry Andric default: 800b57cec5SDimitry Andric B.addNodeIDRegType(Op.getLLTTy(*getMRI())); 810b57cec5SDimitry Andric break; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric void CSEMIRBuilder::profileSrcOp(const SrcOp &Op, 860b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 870b57cec5SDimitry Andric switch (Op.getSrcOpKind()) { 88e8d8bef9SDimitry Andric case SrcOp::SrcType::Ty_Imm: 89e8d8bef9SDimitry Andric B.addNodeIDImmediate(static_cast<int64_t>(Op.getImm())); 90e8d8bef9SDimitry Andric break; 910b57cec5SDimitry Andric case SrcOp::SrcType::Ty_Predicate: 920b57cec5SDimitry Andric B.addNodeIDImmediate(static_cast<int64_t>(Op.getPredicate())); 930b57cec5SDimitry Andric break; 940b57cec5SDimitry Andric default: 950b57cec5SDimitry Andric B.addNodeIDRegType(Op.getReg()); 960b57cec5SDimitry Andric break; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B, 1010b57cec5SDimitry Andric unsigned Opc) const { 1020b57cec5SDimitry Andric // First add the MBB (Local CSE). 1030b57cec5SDimitry Andric B.addNodeIDMBB(&getMBB()); 1040b57cec5SDimitry Andric // Then add the opcode. 1050b57cec5SDimitry Andric B.addNodeIDOpcode(Opc); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, 1090b57cec5SDimitry Andric ArrayRef<SrcOp> SrcOps, 1100b57cec5SDimitry Andric Optional<unsigned> Flags, 1110b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric profileMBBOpcode(B, Opc); 1140b57cec5SDimitry Andric // Then add the DstOps. 1150b57cec5SDimitry Andric profileDstOps(DstOps, B); 1160b57cec5SDimitry Andric // Then add the SrcOps. 1170b57cec5SDimitry Andric profileSrcOps(SrcOps, B); 1180b57cec5SDimitry Andric // Add Flags if passed in. 1190b57cec5SDimitry Andric if (Flags) 1200b57cec5SDimitry Andric B.addNodeIDFlag(*Flags); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB, 1240b57cec5SDimitry Andric void *NodeInsertPos) { 1250b57cec5SDimitry Andric assert(canPerformCSEForOpc(MIB->getOpcode()) && 1260b57cec5SDimitry Andric "Attempting to CSE illegal op"); 1270b57cec5SDimitry Andric MachineInstr *MIBInstr = MIB; 1280b57cec5SDimitry Andric getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos); 1290b57cec5SDimitry Andric return MIB; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef<DstOp> DstOps) { 1330b57cec5SDimitry Andric if (DstOps.size() == 1) 1340b57cec5SDimitry Andric return true; // always possible to emit copy to just 1 vreg. 1350b57cec5SDimitry Andric 136e8d8bef9SDimitry Andric return llvm::all_of(DstOps, [](const DstOp &Op) { 1370b57cec5SDimitry Andric DstOp::DstType DT = Op.getDstOpKind(); 1380b57cec5SDimitry Andric return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC; 1390b57cec5SDimitry Andric }); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric MachineInstrBuilder 1430b57cec5SDimitry Andric CSEMIRBuilder::generateCopiesIfRequired(ArrayRef<DstOp> DstOps, 1440b57cec5SDimitry Andric MachineInstrBuilder &MIB) { 1450b57cec5SDimitry Andric assert(checkCopyToDefsPossible(DstOps) && 1460b57cec5SDimitry Andric "Impossible return a single MIB with copies to multiple defs"); 1470b57cec5SDimitry Andric if (DstOps.size() == 1) { 1480b57cec5SDimitry Andric const DstOp &Op = DstOps[0]; 1490b57cec5SDimitry Andric if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg) 1505ffd83dbSDimitry Andric return buildCopy(Op.getReg(), MIB.getReg(0)); 1510b57cec5SDimitry Andric } 152e8d8bef9SDimitry Andric 153e8d8bef9SDimitry Andric // If we didn't generate a copy then we're re-using an existing node directly 154e8d8bef9SDimitry Andric // instead of emitting any code. Merge the debug location we wanted to emit 155e8d8bef9SDimitry Andric // into the instruction we're CSE'ing with. Debug locations arent part of the 156e8d8bef9SDimitry Andric // profile so we don't need to recompute it. 157e8d8bef9SDimitry Andric if (getDebugLoc()) { 158e8d8bef9SDimitry Andric GISelChangeObserver *Observer = getState().Observer; 159e8d8bef9SDimitry Andric if (Observer) 160e8d8bef9SDimitry Andric Observer->changingInstr(*MIB); 161e8d8bef9SDimitry Andric MIB->setDebugLoc( 162e8d8bef9SDimitry Andric DILocation::getMergedLocation(MIB->getDebugLoc(), getDebugLoc())); 163e8d8bef9SDimitry Andric if (Observer) 164e8d8bef9SDimitry Andric Observer->changedInstr(*MIB); 165e8d8bef9SDimitry Andric } 166e8d8bef9SDimitry Andric 1670b57cec5SDimitry Andric return MIB; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, 1710b57cec5SDimitry Andric ArrayRef<DstOp> DstOps, 1720b57cec5SDimitry Andric ArrayRef<SrcOp> SrcOps, 1730b57cec5SDimitry Andric Optional<unsigned> Flag) { 1740b57cec5SDimitry Andric switch (Opc) { 1750b57cec5SDimitry Andric default: 1760b57cec5SDimitry Andric break; 1770b57cec5SDimitry Andric case TargetOpcode::G_ADD: 178*81ad6265SDimitry Andric case TargetOpcode::G_PTR_ADD: 1790b57cec5SDimitry Andric case TargetOpcode::G_AND: 1800b57cec5SDimitry Andric case TargetOpcode::G_ASHR: 1810b57cec5SDimitry Andric case TargetOpcode::G_LSHR: 1820b57cec5SDimitry Andric case TargetOpcode::G_MUL: 1830b57cec5SDimitry Andric case TargetOpcode::G_OR: 1840b57cec5SDimitry Andric case TargetOpcode::G_SHL: 1850b57cec5SDimitry Andric case TargetOpcode::G_SUB: 1860b57cec5SDimitry Andric case TargetOpcode::G_XOR: 1870b57cec5SDimitry Andric case TargetOpcode::G_UDIV: 1880b57cec5SDimitry Andric case TargetOpcode::G_SDIV: 1890b57cec5SDimitry Andric case TargetOpcode::G_UREM: 190*81ad6265SDimitry Andric case TargetOpcode::G_SREM: 191*81ad6265SDimitry Andric case TargetOpcode::G_SMIN: 192*81ad6265SDimitry Andric case TargetOpcode::G_SMAX: 193*81ad6265SDimitry Andric case TargetOpcode::G_UMIN: 194*81ad6265SDimitry Andric case TargetOpcode::G_UMAX: { 1950b57cec5SDimitry Andric // Try to constant fold these. 1960b57cec5SDimitry Andric assert(SrcOps.size() == 2 && "Invalid sources"); 1970b57cec5SDimitry Andric assert(DstOps.size() == 1 && "Invalid dsts"); 198*81ad6265SDimitry Andric LLT SrcTy = SrcOps[0].getLLTTy(*getMRI()); 199*81ad6265SDimitry Andric 200*81ad6265SDimitry Andric if (Opc == TargetOpcode::G_PTR_ADD && 201*81ad6265SDimitry Andric getDataLayout().isNonIntegralAddressSpace(SrcTy.getAddressSpace())) 202*81ad6265SDimitry Andric break; 203*81ad6265SDimitry Andric 204*81ad6265SDimitry Andric if (SrcTy.isVector()) { 205349cc55cSDimitry Andric // Try to constant fold vector constants. 206*81ad6265SDimitry Andric SmallVector<APInt> VecCst = ConstantFoldVectorBinop( 207*81ad6265SDimitry Andric Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI()); 208*81ad6265SDimitry Andric if (!VecCst.empty()) 209*81ad6265SDimitry Andric return buildBuildVectorConstant(DstOps[0], VecCst); 210349cc55cSDimitry Andric break; 211349cc55cSDimitry Andric } 212*81ad6265SDimitry Andric 2130b57cec5SDimitry Andric if (Optional<APInt> Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(), 2140b57cec5SDimitry Andric SrcOps[1].getReg(), *getMRI())) 215fe6060f1SDimitry Andric return buildConstant(DstOps[0], *Cst); 2160b57cec5SDimitry Andric break; 2170b57cec5SDimitry Andric } 218*81ad6265SDimitry Andric case TargetOpcode::G_FADD: 219*81ad6265SDimitry Andric case TargetOpcode::G_FSUB: 220*81ad6265SDimitry Andric case TargetOpcode::G_FMUL: 221*81ad6265SDimitry Andric case TargetOpcode::G_FDIV: 222*81ad6265SDimitry Andric case TargetOpcode::G_FREM: 223*81ad6265SDimitry Andric case TargetOpcode::G_FMINNUM: 224*81ad6265SDimitry Andric case TargetOpcode::G_FMAXNUM: 225*81ad6265SDimitry Andric case TargetOpcode::G_FMINNUM_IEEE: 226*81ad6265SDimitry Andric case TargetOpcode::G_FMAXNUM_IEEE: 227*81ad6265SDimitry Andric case TargetOpcode::G_FMINIMUM: 228*81ad6265SDimitry Andric case TargetOpcode::G_FMAXIMUM: 229*81ad6265SDimitry Andric case TargetOpcode::G_FCOPYSIGN: { 230*81ad6265SDimitry Andric // Try to constant fold these. 231*81ad6265SDimitry Andric assert(SrcOps.size() == 2 && "Invalid sources"); 232*81ad6265SDimitry Andric assert(DstOps.size() == 1 && "Invalid dsts"); 233*81ad6265SDimitry Andric if (Optional<APFloat> Cst = ConstantFoldFPBinOp( 234*81ad6265SDimitry Andric Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI())) 235*81ad6265SDimitry Andric return buildFConstant(DstOps[0], *Cst); 236*81ad6265SDimitry Andric break; 237*81ad6265SDimitry Andric } 2388bcb0991SDimitry Andric case TargetOpcode::G_SEXT_INREG: { 2398bcb0991SDimitry Andric assert(DstOps.size() == 1 && "Invalid dst ops"); 2408bcb0991SDimitry Andric assert(SrcOps.size() == 2 && "Invalid src ops"); 2418bcb0991SDimitry Andric const DstOp &Dst = DstOps[0]; 2428bcb0991SDimitry Andric const SrcOp &Src0 = SrcOps[0]; 2438bcb0991SDimitry Andric const SrcOp &Src1 = SrcOps[1]; 2448bcb0991SDimitry Andric if (auto MaybeCst = 2458bcb0991SDimitry Andric ConstantFoldExtOp(Opc, Src0.getReg(), Src1.getImm(), *getMRI())) 246fe6060f1SDimitry Andric return buildConstant(Dst, *MaybeCst); 247fe6060f1SDimitry Andric break; 248fe6060f1SDimitry Andric } 249fe6060f1SDimitry Andric case TargetOpcode::G_SITOFP: 250fe6060f1SDimitry Andric case TargetOpcode::G_UITOFP: { 251fe6060f1SDimitry Andric // Try to constant fold these. 252fe6060f1SDimitry Andric assert(SrcOps.size() == 1 && "Invalid sources"); 253fe6060f1SDimitry Andric assert(DstOps.size() == 1 && "Invalid dsts"); 254fe6060f1SDimitry Andric if (Optional<APFloat> Cst = ConstantFoldIntToFloat( 255fe6060f1SDimitry Andric Opc, DstOps[0].getLLTTy(*getMRI()), SrcOps[0].getReg(), *getMRI())) 256fe6060f1SDimitry Andric return buildFConstant(DstOps[0], *Cst); 2578bcb0991SDimitry Andric break; 2588bcb0991SDimitry Andric } 259349cc55cSDimitry Andric case TargetOpcode::G_CTLZ: { 260349cc55cSDimitry Andric assert(SrcOps.size() == 1 && "Expected one source"); 261349cc55cSDimitry Andric assert(DstOps.size() == 1 && "Expected one dest"); 262349cc55cSDimitry Andric auto MaybeCsts = ConstantFoldCTLZ(SrcOps[0].getReg(), *getMRI()); 263349cc55cSDimitry Andric if (!MaybeCsts) 264349cc55cSDimitry Andric break; 265349cc55cSDimitry Andric if (MaybeCsts->size() == 1) 266349cc55cSDimitry Andric return buildConstant(DstOps[0], (*MaybeCsts)[0]); 267349cc55cSDimitry Andric // This was a vector constant. Build a G_BUILD_VECTOR for them. 268349cc55cSDimitry Andric SmallVector<Register> ConstantRegs; 269349cc55cSDimitry Andric LLT VecTy = DstOps[0].getLLTTy(*getMRI()); 270349cc55cSDimitry Andric for (unsigned Cst : *MaybeCsts) 271349cc55cSDimitry Andric ConstantRegs.emplace_back( 272349cc55cSDimitry Andric buildConstant(VecTy.getScalarType(), Cst).getReg(0)); 273349cc55cSDimitry Andric return buildBuildVector(DstOps[0], ConstantRegs); 274349cc55cSDimitry Andric } 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric bool CanCopy = checkCopyToDefsPossible(DstOps); 2770b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 2780b57cec5SDimitry Andric return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 2790b57cec5SDimitry Andric // If we can CSE this instruction, but involves generating copies to multiple 2800b57cec5SDimitry Andric // regs, give up. This frequently happens to UNMERGEs. 2810b57cec5SDimitry Andric if (!CanCopy) { 2820b57cec5SDimitry Andric auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 2830b57cec5SDimitry Andric // CSEInfo would have tracked this instruction. Remove it from the temporary 2840b57cec5SDimitry Andric // insts. 2850b57cec5SDimitry Andric getCSEInfo()->handleRemoveInst(&*MIB); 2860b57cec5SDimitry Andric return MIB; 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric FoldingSetNodeID ID; 2890b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 2900b57cec5SDimitry Andric void *InsertPos = nullptr; 2910b57cec5SDimitry Andric profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder); 2920b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 2930b57cec5SDimitry Andric if (MIB) { 2940b57cec5SDimitry Andric // Handle generating copies here. 2950b57cec5SDimitry Andric return generateCopiesIfRequired(DstOps, MIB); 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric // This instruction does not exist in the CSEInfo. Build it and CSE it. 2980b57cec5SDimitry Andric MachineInstrBuilder NewMIB = 2990b57cec5SDimitry Andric MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 3000b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res, 3040b57cec5SDimitry Andric const ConstantInt &Val) { 3050b57cec5SDimitry Andric constexpr unsigned Opc = TargetOpcode::G_CONSTANT; 3060b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 3070b57cec5SDimitry Andric return MachineIRBuilder::buildConstant(Res, Val); 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric // For vectors, CSE the element only for now. 3100b57cec5SDimitry Andric LLT Ty = Res.getLLTTy(*getMRI()); 3110b57cec5SDimitry Andric if (Ty.isVector()) 3120b57cec5SDimitry Andric return buildSplatVector(Res, buildConstant(Ty.getElementType(), Val)); 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric FoldingSetNodeID ID; 3150b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 3160b57cec5SDimitry Andric void *InsertPos = nullptr; 3170b57cec5SDimitry Andric profileMBBOpcode(ProfBuilder, Opc); 3180b57cec5SDimitry Andric profileDstOp(Res, ProfBuilder); 3190b57cec5SDimitry Andric ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val)); 3200b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 3210b57cec5SDimitry Andric if (MIB) { 3220b57cec5SDimitry Andric // Handle generating copies here. 3230b57cec5SDimitry Andric return generateCopiesIfRequired({Res}, MIB); 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val); 3270b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res, 3310b57cec5SDimitry Andric const ConstantFP &Val) { 3320b57cec5SDimitry Andric constexpr unsigned Opc = TargetOpcode::G_FCONSTANT; 3330b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 3340b57cec5SDimitry Andric return MachineIRBuilder::buildFConstant(Res, Val); 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric // For vectors, CSE the element only for now. 3370b57cec5SDimitry Andric LLT Ty = Res.getLLTTy(*getMRI()); 3380b57cec5SDimitry Andric if (Ty.isVector()) 3390b57cec5SDimitry Andric return buildSplatVector(Res, buildFConstant(Ty.getElementType(), Val)); 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric FoldingSetNodeID ID; 3420b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 3430b57cec5SDimitry Andric void *InsertPos = nullptr; 3440b57cec5SDimitry Andric profileMBBOpcode(ProfBuilder, Opc); 3450b57cec5SDimitry Andric profileDstOp(Res, ProfBuilder); 3460b57cec5SDimitry Andric ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val)); 3470b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 3480b57cec5SDimitry Andric if (MIB) { 3490b57cec5SDimitry Andric // Handle generating copies here. 3500b57cec5SDimitry Andric return generateCopiesIfRequired({Res}, MIB); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric MachineInstrBuilder NewMIB = MachineIRBuilder::buildFConstant(Res, Val); 3530b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 3540b57cec5SDimitry Andric } 355