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" 150b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" 16*e8d8bef9SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace llvm; 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A, 210b57cec5SDimitry Andric MachineBasicBlock::const_iterator B) const { 220b57cec5SDimitry Andric auto MBBEnd = getMBB().end(); 230b57cec5SDimitry Andric if (B == MBBEnd) 240b57cec5SDimitry Andric return true; 250b57cec5SDimitry Andric assert(A->getParent() == B->getParent() && 260b57cec5SDimitry Andric "Iterators should be in same block"); 270b57cec5SDimitry Andric const MachineBasicBlock *BBA = A->getParent(); 280b57cec5SDimitry Andric MachineBasicBlock::const_iterator I = BBA->begin(); 290b57cec5SDimitry Andric for (; &*I != A && &*I != B; ++I) 300b57cec5SDimitry Andric ; 310b57cec5SDimitry Andric return &*I == A; 320b57cec5SDimitry Andric } 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric MachineInstrBuilder 350b57cec5SDimitry Andric CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID, 360b57cec5SDimitry Andric void *&NodeInsertPos) { 370b57cec5SDimitry Andric GISelCSEInfo *CSEInfo = getCSEInfo(); 380b57cec5SDimitry Andric assert(CSEInfo && "Can't get here without setting CSEInfo"); 390b57cec5SDimitry Andric MachineBasicBlock *CurMBB = &getMBB(); 400b57cec5SDimitry Andric MachineInstr *MI = 410b57cec5SDimitry Andric CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos); 420b57cec5SDimitry Andric if (MI) { 430b57cec5SDimitry Andric CSEInfo->countOpcodeHit(MI->getOpcode()); 440b57cec5SDimitry Andric auto CurrPos = getInsertPt(); 45*e8d8bef9SDimitry Andric auto MII = MachineBasicBlock::iterator(MI); 46*e8d8bef9SDimitry Andric if (MII == CurrPos) { 47*e8d8bef9SDimitry Andric // Move the insert point ahead of the instruction so any future uses of 48*e8d8bef9SDimitry Andric // this builder will have the def ready. 49*e8d8bef9SDimitry Andric setInsertPt(*CurMBB, std::next(MII)); 50*e8d8bef9SDimitry Andric } else if (!dominates(MI, CurrPos)) { 510b57cec5SDimitry Andric CurMBB->splice(CurrPos, CurMBB, MI); 52*e8d8bef9SDimitry Andric } 530b57cec5SDimitry Andric return MachineInstrBuilder(getMF(), MI); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric return MachineInstrBuilder(); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const { 590b57cec5SDimitry Andric const GISelCSEInfo *CSEInfo = getCSEInfo(); 600b57cec5SDimitry Andric if (!CSEInfo || !CSEInfo->shouldCSE(Opc)) 610b57cec5SDimitry Andric return false; 620b57cec5SDimitry Andric return true; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric void CSEMIRBuilder::profileDstOp(const DstOp &Op, 660b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 670b57cec5SDimitry Andric switch (Op.getDstOpKind()) { 680b57cec5SDimitry Andric case DstOp::DstType::Ty_RC: 690b57cec5SDimitry Andric B.addNodeIDRegType(Op.getRegClass()); 700b57cec5SDimitry Andric break; 71*e8d8bef9SDimitry Andric case DstOp::DstType::Ty_Reg: { 72*e8d8bef9SDimitry Andric // Regs can have LLT&(RB|RC). If those exist, profile them as well. 73*e8d8bef9SDimitry Andric B.addNodeIDReg(Op.getReg()); 74*e8d8bef9SDimitry Andric break; 75*e8d8bef9SDimitry Andric } 760b57cec5SDimitry Andric default: 770b57cec5SDimitry Andric B.addNodeIDRegType(Op.getLLTTy(*getMRI())); 780b57cec5SDimitry Andric break; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void CSEMIRBuilder::profileSrcOp(const SrcOp &Op, 830b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 840b57cec5SDimitry Andric switch (Op.getSrcOpKind()) { 85*e8d8bef9SDimitry Andric case SrcOp::SrcType::Ty_Imm: 86*e8d8bef9SDimitry Andric B.addNodeIDImmediate(static_cast<int64_t>(Op.getImm())); 87*e8d8bef9SDimitry Andric break; 880b57cec5SDimitry Andric case SrcOp::SrcType::Ty_Predicate: 890b57cec5SDimitry Andric B.addNodeIDImmediate(static_cast<int64_t>(Op.getPredicate())); 900b57cec5SDimitry Andric break; 910b57cec5SDimitry Andric default: 920b57cec5SDimitry Andric B.addNodeIDRegType(Op.getReg()); 930b57cec5SDimitry Andric break; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B, 980b57cec5SDimitry Andric unsigned Opc) const { 990b57cec5SDimitry Andric // First add the MBB (Local CSE). 1000b57cec5SDimitry Andric B.addNodeIDMBB(&getMBB()); 1010b57cec5SDimitry Andric // Then add the opcode. 1020b57cec5SDimitry Andric B.addNodeIDOpcode(Opc); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, 1060b57cec5SDimitry Andric ArrayRef<SrcOp> SrcOps, 1070b57cec5SDimitry Andric Optional<unsigned> Flags, 1080b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric profileMBBOpcode(B, Opc); 1110b57cec5SDimitry Andric // Then add the DstOps. 1120b57cec5SDimitry Andric profileDstOps(DstOps, B); 1130b57cec5SDimitry Andric // Then add the SrcOps. 1140b57cec5SDimitry Andric profileSrcOps(SrcOps, B); 1150b57cec5SDimitry Andric // Add Flags if passed in. 1160b57cec5SDimitry Andric if (Flags) 1170b57cec5SDimitry Andric B.addNodeIDFlag(*Flags); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB, 1210b57cec5SDimitry Andric void *NodeInsertPos) { 1220b57cec5SDimitry Andric assert(canPerformCSEForOpc(MIB->getOpcode()) && 1230b57cec5SDimitry Andric "Attempting to CSE illegal op"); 1240b57cec5SDimitry Andric MachineInstr *MIBInstr = MIB; 1250b57cec5SDimitry Andric getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos); 1260b57cec5SDimitry Andric return MIB; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef<DstOp> DstOps) { 1300b57cec5SDimitry Andric if (DstOps.size() == 1) 1310b57cec5SDimitry Andric return true; // always possible to emit copy to just 1 vreg. 1320b57cec5SDimitry Andric 133*e8d8bef9SDimitry Andric return llvm::all_of(DstOps, [](const DstOp &Op) { 1340b57cec5SDimitry Andric DstOp::DstType DT = Op.getDstOpKind(); 1350b57cec5SDimitry Andric return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC; 1360b57cec5SDimitry Andric }); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric MachineInstrBuilder 1400b57cec5SDimitry Andric CSEMIRBuilder::generateCopiesIfRequired(ArrayRef<DstOp> DstOps, 1410b57cec5SDimitry Andric MachineInstrBuilder &MIB) { 1420b57cec5SDimitry Andric assert(checkCopyToDefsPossible(DstOps) && 1430b57cec5SDimitry Andric "Impossible return a single MIB with copies to multiple defs"); 1440b57cec5SDimitry Andric if (DstOps.size() == 1) { 1450b57cec5SDimitry Andric const DstOp &Op = DstOps[0]; 1460b57cec5SDimitry Andric if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg) 1475ffd83dbSDimitry Andric return buildCopy(Op.getReg(), MIB.getReg(0)); 1480b57cec5SDimitry Andric } 149*e8d8bef9SDimitry Andric 150*e8d8bef9SDimitry Andric // If we didn't generate a copy then we're re-using an existing node directly 151*e8d8bef9SDimitry Andric // instead of emitting any code. Merge the debug location we wanted to emit 152*e8d8bef9SDimitry Andric // into the instruction we're CSE'ing with. Debug locations arent part of the 153*e8d8bef9SDimitry Andric // profile so we don't need to recompute it. 154*e8d8bef9SDimitry Andric if (getDebugLoc()) { 155*e8d8bef9SDimitry Andric GISelChangeObserver *Observer = getState().Observer; 156*e8d8bef9SDimitry Andric if (Observer) 157*e8d8bef9SDimitry Andric Observer->changingInstr(*MIB); 158*e8d8bef9SDimitry Andric MIB->setDebugLoc( 159*e8d8bef9SDimitry Andric DILocation::getMergedLocation(MIB->getDebugLoc(), getDebugLoc())); 160*e8d8bef9SDimitry Andric if (Observer) 161*e8d8bef9SDimitry Andric Observer->changedInstr(*MIB); 162*e8d8bef9SDimitry Andric } 163*e8d8bef9SDimitry Andric 1640b57cec5SDimitry Andric return MIB; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, 1680b57cec5SDimitry Andric ArrayRef<DstOp> DstOps, 1690b57cec5SDimitry Andric ArrayRef<SrcOp> SrcOps, 1700b57cec5SDimitry Andric Optional<unsigned> Flag) { 1710b57cec5SDimitry Andric switch (Opc) { 1720b57cec5SDimitry Andric default: 1730b57cec5SDimitry Andric break; 1740b57cec5SDimitry Andric case TargetOpcode::G_ADD: 1750b57cec5SDimitry Andric case TargetOpcode::G_AND: 1760b57cec5SDimitry Andric case TargetOpcode::G_ASHR: 1770b57cec5SDimitry Andric case TargetOpcode::G_LSHR: 1780b57cec5SDimitry Andric case TargetOpcode::G_MUL: 1790b57cec5SDimitry Andric case TargetOpcode::G_OR: 1800b57cec5SDimitry Andric case TargetOpcode::G_SHL: 1810b57cec5SDimitry Andric case TargetOpcode::G_SUB: 1820b57cec5SDimitry Andric case TargetOpcode::G_XOR: 1830b57cec5SDimitry Andric case TargetOpcode::G_UDIV: 1840b57cec5SDimitry Andric case TargetOpcode::G_SDIV: 1850b57cec5SDimitry Andric case TargetOpcode::G_UREM: 1860b57cec5SDimitry Andric case TargetOpcode::G_SREM: { 1870b57cec5SDimitry Andric // Try to constant fold these. 1880b57cec5SDimitry Andric assert(SrcOps.size() == 2 && "Invalid sources"); 1890b57cec5SDimitry Andric assert(DstOps.size() == 1 && "Invalid dsts"); 1900b57cec5SDimitry Andric if (Optional<APInt> Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(), 1910b57cec5SDimitry Andric SrcOps[1].getReg(), *getMRI())) 1920b57cec5SDimitry Andric return buildConstant(DstOps[0], Cst->getSExtValue()); 1930b57cec5SDimitry Andric break; 1940b57cec5SDimitry Andric } 1958bcb0991SDimitry Andric case TargetOpcode::G_SEXT_INREG: { 1968bcb0991SDimitry Andric assert(DstOps.size() == 1 && "Invalid dst ops"); 1978bcb0991SDimitry Andric assert(SrcOps.size() == 2 && "Invalid src ops"); 1988bcb0991SDimitry Andric const DstOp &Dst = DstOps[0]; 1998bcb0991SDimitry Andric const SrcOp &Src0 = SrcOps[0]; 2008bcb0991SDimitry Andric const SrcOp &Src1 = SrcOps[1]; 2018bcb0991SDimitry Andric if (auto MaybeCst = 2028bcb0991SDimitry Andric ConstantFoldExtOp(Opc, Src0.getReg(), Src1.getImm(), *getMRI())) 2038bcb0991SDimitry Andric return buildConstant(Dst, MaybeCst->getSExtValue()); 2048bcb0991SDimitry Andric break; 2058bcb0991SDimitry Andric } 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric bool CanCopy = checkCopyToDefsPossible(DstOps); 2080b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 2090b57cec5SDimitry Andric return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 2100b57cec5SDimitry Andric // If we can CSE this instruction, but involves generating copies to multiple 2110b57cec5SDimitry Andric // regs, give up. This frequently happens to UNMERGEs. 2120b57cec5SDimitry Andric if (!CanCopy) { 2130b57cec5SDimitry Andric auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 2140b57cec5SDimitry Andric // CSEInfo would have tracked this instruction. Remove it from the temporary 2150b57cec5SDimitry Andric // insts. 2160b57cec5SDimitry Andric getCSEInfo()->handleRemoveInst(&*MIB); 2170b57cec5SDimitry Andric return MIB; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric FoldingSetNodeID ID; 2200b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 2210b57cec5SDimitry Andric void *InsertPos = nullptr; 2220b57cec5SDimitry Andric profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder); 2230b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 2240b57cec5SDimitry Andric if (MIB) { 2250b57cec5SDimitry Andric // Handle generating copies here. 2260b57cec5SDimitry Andric return generateCopiesIfRequired(DstOps, MIB); 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric // This instruction does not exist in the CSEInfo. Build it and CSE it. 2290b57cec5SDimitry Andric MachineInstrBuilder NewMIB = 2300b57cec5SDimitry Andric MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 2310b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res, 2350b57cec5SDimitry Andric const ConstantInt &Val) { 2360b57cec5SDimitry Andric constexpr unsigned Opc = TargetOpcode::G_CONSTANT; 2370b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 2380b57cec5SDimitry Andric return MachineIRBuilder::buildConstant(Res, Val); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric // For vectors, CSE the element only for now. 2410b57cec5SDimitry Andric LLT Ty = Res.getLLTTy(*getMRI()); 2420b57cec5SDimitry Andric if (Ty.isVector()) 2430b57cec5SDimitry Andric return buildSplatVector(Res, buildConstant(Ty.getElementType(), Val)); 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric FoldingSetNodeID ID; 2460b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 2470b57cec5SDimitry Andric void *InsertPos = nullptr; 2480b57cec5SDimitry Andric profileMBBOpcode(ProfBuilder, Opc); 2490b57cec5SDimitry Andric profileDstOp(Res, ProfBuilder); 2500b57cec5SDimitry Andric ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val)); 2510b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 2520b57cec5SDimitry Andric if (MIB) { 2530b57cec5SDimitry Andric // Handle generating copies here. 2540b57cec5SDimitry Andric return generateCopiesIfRequired({Res}, MIB); 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val); 2580b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res, 2620b57cec5SDimitry Andric const ConstantFP &Val) { 2630b57cec5SDimitry Andric constexpr unsigned Opc = TargetOpcode::G_FCONSTANT; 2640b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 2650b57cec5SDimitry Andric return MachineIRBuilder::buildFConstant(Res, Val); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric // For vectors, CSE the element only for now. 2680b57cec5SDimitry Andric LLT Ty = Res.getLLTTy(*getMRI()); 2690b57cec5SDimitry Andric if (Ty.isVector()) 2700b57cec5SDimitry Andric return buildSplatVector(Res, buildFConstant(Ty.getElementType(), Val)); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric FoldingSetNodeID ID; 2730b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 2740b57cec5SDimitry Andric void *InsertPos = nullptr; 2750b57cec5SDimitry Andric profileMBBOpcode(ProfBuilder, Opc); 2760b57cec5SDimitry Andric profileDstOp(Res, ProfBuilder); 2770b57cec5SDimitry Andric ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val)); 2780b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 2790b57cec5SDimitry Andric if (MIB) { 2800b57cec5SDimitry Andric // Handle generating copies here. 2810b57cec5SDimitry Andric return generateCopiesIfRequired({Res}, MIB); 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric MachineInstrBuilder NewMIB = MachineIRBuilder::buildFConstant(Res, Val); 2840b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 2850b57cec5SDimitry Andric } 286