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" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric using namespace llvm; 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A, 200b57cec5SDimitry Andric MachineBasicBlock::const_iterator B) const { 210b57cec5SDimitry Andric auto MBBEnd = getMBB().end(); 220b57cec5SDimitry Andric if (B == MBBEnd) 230b57cec5SDimitry Andric return true; 240b57cec5SDimitry Andric assert(A->getParent() == B->getParent() && 250b57cec5SDimitry Andric "Iterators should be in same block"); 260b57cec5SDimitry Andric const MachineBasicBlock *BBA = A->getParent(); 270b57cec5SDimitry Andric MachineBasicBlock::const_iterator I = BBA->begin(); 280b57cec5SDimitry Andric for (; &*I != A && &*I != B; ++I) 290b57cec5SDimitry Andric ; 300b57cec5SDimitry Andric return &*I == A; 310b57cec5SDimitry Andric } 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric MachineInstrBuilder 340b57cec5SDimitry Andric CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID, 350b57cec5SDimitry Andric void *&NodeInsertPos) { 360b57cec5SDimitry Andric GISelCSEInfo *CSEInfo = getCSEInfo(); 370b57cec5SDimitry Andric assert(CSEInfo && "Can't get here without setting CSEInfo"); 380b57cec5SDimitry Andric MachineBasicBlock *CurMBB = &getMBB(); 390b57cec5SDimitry Andric MachineInstr *MI = 400b57cec5SDimitry Andric CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos); 410b57cec5SDimitry Andric if (MI) { 420b57cec5SDimitry Andric CSEInfo->countOpcodeHit(MI->getOpcode()); 430b57cec5SDimitry Andric auto CurrPos = getInsertPt(); 440b57cec5SDimitry Andric if (!dominates(MI, CurrPos)) 450b57cec5SDimitry Andric CurMBB->splice(CurrPos, CurMBB, MI); 460b57cec5SDimitry Andric return MachineInstrBuilder(getMF(), MI); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric return MachineInstrBuilder(); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const { 520b57cec5SDimitry Andric const GISelCSEInfo *CSEInfo = getCSEInfo(); 530b57cec5SDimitry Andric if (!CSEInfo || !CSEInfo->shouldCSE(Opc)) 540b57cec5SDimitry Andric return false; 550b57cec5SDimitry Andric return true; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric void CSEMIRBuilder::profileDstOp(const DstOp &Op, 590b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 600b57cec5SDimitry Andric switch (Op.getDstOpKind()) { 610b57cec5SDimitry Andric case DstOp::DstType::Ty_RC: 620b57cec5SDimitry Andric B.addNodeIDRegType(Op.getRegClass()); 630b57cec5SDimitry Andric break; 640b57cec5SDimitry Andric default: 650b57cec5SDimitry Andric B.addNodeIDRegType(Op.getLLTTy(*getMRI())); 660b57cec5SDimitry Andric break; 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric void CSEMIRBuilder::profileSrcOp(const SrcOp &Op, 710b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 720b57cec5SDimitry Andric switch (Op.getSrcOpKind()) { 730b57cec5SDimitry Andric case SrcOp::SrcType::Ty_Predicate: 740b57cec5SDimitry Andric B.addNodeIDImmediate(static_cast<int64_t>(Op.getPredicate())); 750b57cec5SDimitry Andric break; 760b57cec5SDimitry Andric default: 770b57cec5SDimitry Andric B.addNodeIDRegType(Op.getReg()); 780b57cec5SDimitry Andric break; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B, 830b57cec5SDimitry Andric unsigned Opc) const { 840b57cec5SDimitry Andric // First add the MBB (Local CSE). 850b57cec5SDimitry Andric B.addNodeIDMBB(&getMBB()); 860b57cec5SDimitry Andric // Then add the opcode. 870b57cec5SDimitry Andric B.addNodeIDOpcode(Opc); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, 910b57cec5SDimitry Andric ArrayRef<SrcOp> SrcOps, 920b57cec5SDimitry Andric Optional<unsigned> Flags, 930b57cec5SDimitry Andric GISelInstProfileBuilder &B) const { 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric profileMBBOpcode(B, Opc); 960b57cec5SDimitry Andric // Then add the DstOps. 970b57cec5SDimitry Andric profileDstOps(DstOps, B); 980b57cec5SDimitry Andric // Then add the SrcOps. 990b57cec5SDimitry Andric profileSrcOps(SrcOps, B); 1000b57cec5SDimitry Andric // Add Flags if passed in. 1010b57cec5SDimitry Andric if (Flags) 1020b57cec5SDimitry Andric B.addNodeIDFlag(*Flags); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB, 1060b57cec5SDimitry Andric void *NodeInsertPos) { 1070b57cec5SDimitry Andric assert(canPerformCSEForOpc(MIB->getOpcode()) && 1080b57cec5SDimitry Andric "Attempting to CSE illegal op"); 1090b57cec5SDimitry Andric MachineInstr *MIBInstr = MIB; 1100b57cec5SDimitry Andric getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos); 1110b57cec5SDimitry Andric return MIB; 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef<DstOp> DstOps) { 1150b57cec5SDimitry Andric if (DstOps.size() == 1) 1160b57cec5SDimitry Andric return true; // always possible to emit copy to just 1 vreg. 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric return std::all_of(DstOps.begin(), DstOps.end(), [](const DstOp &Op) { 1190b57cec5SDimitry Andric DstOp::DstType DT = Op.getDstOpKind(); 1200b57cec5SDimitry Andric return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC; 1210b57cec5SDimitry Andric }); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric MachineInstrBuilder 1250b57cec5SDimitry Andric CSEMIRBuilder::generateCopiesIfRequired(ArrayRef<DstOp> DstOps, 1260b57cec5SDimitry Andric MachineInstrBuilder &MIB) { 1270b57cec5SDimitry Andric assert(checkCopyToDefsPossible(DstOps) && 1280b57cec5SDimitry Andric "Impossible return a single MIB with copies to multiple defs"); 1290b57cec5SDimitry Andric if (DstOps.size() == 1) { 1300b57cec5SDimitry Andric const DstOp &Op = DstOps[0]; 1310b57cec5SDimitry Andric if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg) 132*5ffd83dbSDimitry Andric return buildCopy(Op.getReg(), MIB.getReg(0)); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric return MIB; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, 1380b57cec5SDimitry Andric ArrayRef<DstOp> DstOps, 1390b57cec5SDimitry Andric ArrayRef<SrcOp> SrcOps, 1400b57cec5SDimitry Andric Optional<unsigned> Flag) { 1410b57cec5SDimitry Andric switch (Opc) { 1420b57cec5SDimitry Andric default: 1430b57cec5SDimitry Andric break; 1440b57cec5SDimitry Andric case TargetOpcode::G_ADD: 1450b57cec5SDimitry Andric case TargetOpcode::G_AND: 1460b57cec5SDimitry Andric case TargetOpcode::G_ASHR: 1470b57cec5SDimitry Andric case TargetOpcode::G_LSHR: 1480b57cec5SDimitry Andric case TargetOpcode::G_MUL: 1490b57cec5SDimitry Andric case TargetOpcode::G_OR: 1500b57cec5SDimitry Andric case TargetOpcode::G_SHL: 1510b57cec5SDimitry Andric case TargetOpcode::G_SUB: 1520b57cec5SDimitry Andric case TargetOpcode::G_XOR: 1530b57cec5SDimitry Andric case TargetOpcode::G_UDIV: 1540b57cec5SDimitry Andric case TargetOpcode::G_SDIV: 1550b57cec5SDimitry Andric case TargetOpcode::G_UREM: 1560b57cec5SDimitry Andric case TargetOpcode::G_SREM: { 1570b57cec5SDimitry Andric // Try to constant fold these. 1580b57cec5SDimitry Andric assert(SrcOps.size() == 2 && "Invalid sources"); 1590b57cec5SDimitry Andric assert(DstOps.size() == 1 && "Invalid dsts"); 1600b57cec5SDimitry Andric if (Optional<APInt> Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(), 1610b57cec5SDimitry Andric SrcOps[1].getReg(), *getMRI())) 1620b57cec5SDimitry Andric return buildConstant(DstOps[0], Cst->getSExtValue()); 1630b57cec5SDimitry Andric break; 1640b57cec5SDimitry Andric } 1658bcb0991SDimitry Andric case TargetOpcode::G_SEXT_INREG: { 1668bcb0991SDimitry Andric assert(DstOps.size() == 1 && "Invalid dst ops"); 1678bcb0991SDimitry Andric assert(SrcOps.size() == 2 && "Invalid src ops"); 1688bcb0991SDimitry Andric const DstOp &Dst = DstOps[0]; 1698bcb0991SDimitry Andric const SrcOp &Src0 = SrcOps[0]; 1708bcb0991SDimitry Andric const SrcOp &Src1 = SrcOps[1]; 1718bcb0991SDimitry Andric if (auto MaybeCst = 1728bcb0991SDimitry Andric ConstantFoldExtOp(Opc, Src0.getReg(), Src1.getImm(), *getMRI())) 1738bcb0991SDimitry Andric return buildConstant(Dst, MaybeCst->getSExtValue()); 1748bcb0991SDimitry Andric break; 1758bcb0991SDimitry Andric } 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric bool CanCopy = checkCopyToDefsPossible(DstOps); 1780b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 1790b57cec5SDimitry Andric return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 1800b57cec5SDimitry Andric // If we can CSE this instruction, but involves generating copies to multiple 1810b57cec5SDimitry Andric // regs, give up. This frequently happens to UNMERGEs. 1820b57cec5SDimitry Andric if (!CanCopy) { 1830b57cec5SDimitry Andric auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 1840b57cec5SDimitry Andric // CSEInfo would have tracked this instruction. Remove it from the temporary 1850b57cec5SDimitry Andric // insts. 1860b57cec5SDimitry Andric getCSEInfo()->handleRemoveInst(&*MIB); 1870b57cec5SDimitry Andric return MIB; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric FoldingSetNodeID ID; 1900b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 1910b57cec5SDimitry Andric void *InsertPos = nullptr; 1920b57cec5SDimitry Andric profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder); 1930b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 1940b57cec5SDimitry Andric if (MIB) { 1950b57cec5SDimitry Andric // Handle generating copies here. 1960b57cec5SDimitry Andric return generateCopiesIfRequired(DstOps, MIB); 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric // This instruction does not exist in the CSEInfo. Build it and CSE it. 1990b57cec5SDimitry Andric MachineInstrBuilder NewMIB = 2000b57cec5SDimitry Andric MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); 2010b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res, 2050b57cec5SDimitry Andric const ConstantInt &Val) { 2060b57cec5SDimitry Andric constexpr unsigned Opc = TargetOpcode::G_CONSTANT; 2070b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 2080b57cec5SDimitry Andric return MachineIRBuilder::buildConstant(Res, Val); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric // For vectors, CSE the element only for now. 2110b57cec5SDimitry Andric LLT Ty = Res.getLLTTy(*getMRI()); 2120b57cec5SDimitry Andric if (Ty.isVector()) 2130b57cec5SDimitry Andric return buildSplatVector(Res, buildConstant(Ty.getElementType(), Val)); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric FoldingSetNodeID ID; 2160b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 2170b57cec5SDimitry Andric void *InsertPos = nullptr; 2180b57cec5SDimitry Andric profileMBBOpcode(ProfBuilder, Opc); 2190b57cec5SDimitry Andric profileDstOp(Res, ProfBuilder); 2200b57cec5SDimitry Andric ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val)); 2210b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 2220b57cec5SDimitry Andric if (MIB) { 2230b57cec5SDimitry Andric // Handle generating copies here. 2240b57cec5SDimitry Andric return generateCopiesIfRequired({Res}, MIB); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val); 2280b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res, 2320b57cec5SDimitry Andric const ConstantFP &Val) { 2330b57cec5SDimitry Andric constexpr unsigned Opc = TargetOpcode::G_FCONSTANT; 2340b57cec5SDimitry Andric if (!canPerformCSEForOpc(Opc)) 2350b57cec5SDimitry Andric return MachineIRBuilder::buildFConstant(Res, Val); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // For vectors, CSE the element only for now. 2380b57cec5SDimitry Andric LLT Ty = Res.getLLTTy(*getMRI()); 2390b57cec5SDimitry Andric if (Ty.isVector()) 2400b57cec5SDimitry Andric return buildSplatVector(Res, buildFConstant(Ty.getElementType(), Val)); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric FoldingSetNodeID ID; 2430b57cec5SDimitry Andric GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); 2440b57cec5SDimitry Andric void *InsertPos = nullptr; 2450b57cec5SDimitry Andric profileMBBOpcode(ProfBuilder, Opc); 2460b57cec5SDimitry Andric profileDstOp(Res, ProfBuilder); 2470b57cec5SDimitry Andric ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val)); 2480b57cec5SDimitry Andric MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); 2490b57cec5SDimitry Andric if (MIB) { 2500b57cec5SDimitry Andric // Handle generating copies here. 2510b57cec5SDimitry Andric return generateCopiesIfRequired({Res}, MIB); 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric MachineInstrBuilder NewMIB = MachineIRBuilder::buildFConstant(Res, Val); 2540b57cec5SDimitry Andric return memoizeMI(NewMIB, InsertPos); 2550b57cec5SDimitry Andric } 256