10b57cec5SDimitry Andric //===-- llvm/CodeGen/GlobalISel/Legalizer.cpp -----------------------------===// 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 // 90b57cec5SDimitry Andric /// \file This file implements the LegalizerHelper class to legalize individual 100b57cec5SDimitry Andric /// instructions and the LegalizePass wrapper pass for the primary 110b57cec5SDimitry Andric /// legalization. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h" 160b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 170b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CSEInfo.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 24*5ffd83dbSDimitry Andric #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 30480093f4SDimitry Andric #include "llvm/InitializePasses.h" 310b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 32*5ffd83dbSDimitry Andric #include "llvm/Support/Error.h" 330b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric #include <iterator> 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric #define DEBUG_TYPE "legalizer" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric using namespace llvm; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric static cl::opt<bool> 420b57cec5SDimitry Andric EnableCSEInLegalizer("enable-cse-in-legalizer", 430b57cec5SDimitry Andric cl::desc("Should enable CSE in Legalizer"), 440b57cec5SDimitry Andric cl::Optional, cl::init(false)); 450b57cec5SDimitry Andric 46*5ffd83dbSDimitry Andric enum class DebugLocVerifyLevel { 47*5ffd83dbSDimitry Andric None, 48*5ffd83dbSDimitry Andric Legalizations, 49*5ffd83dbSDimitry Andric LegalizationsAndArtifactCombiners, 50*5ffd83dbSDimitry Andric }; 51*5ffd83dbSDimitry Andric #ifndef NDEBUG 52*5ffd83dbSDimitry Andric static cl::opt<DebugLocVerifyLevel> VerifyDebugLocs( 53*5ffd83dbSDimitry Andric "verify-legalizer-debug-locs", 54*5ffd83dbSDimitry Andric cl::desc("Verify that debug locations are handled"), 55*5ffd83dbSDimitry Andric cl::values( 56*5ffd83dbSDimitry Andric clEnumValN(DebugLocVerifyLevel::None, "none", "No verification"), 57*5ffd83dbSDimitry Andric clEnumValN(DebugLocVerifyLevel::Legalizations, "legalizations", 58*5ffd83dbSDimitry Andric "Verify legalizations"), 59*5ffd83dbSDimitry Andric clEnumValN(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners, 60*5ffd83dbSDimitry Andric "legalizations+artifactcombiners", 61*5ffd83dbSDimitry Andric "Verify legalizations and artifact combines")), 62*5ffd83dbSDimitry Andric cl::init(DebugLocVerifyLevel::Legalizations)); 63*5ffd83dbSDimitry Andric #else 64*5ffd83dbSDimitry Andric // Always disable it for release builds by preventing the observer from being 65*5ffd83dbSDimitry Andric // installed. 66*5ffd83dbSDimitry Andric static const DebugLocVerifyLevel VerifyDebugLocs = DebugLocVerifyLevel::None; 67*5ffd83dbSDimitry Andric #endif 68*5ffd83dbSDimitry Andric 690b57cec5SDimitry Andric char Legalizer::ID = 0; 700b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE, 710b57cec5SDimitry Andric "Legalize the Machine IR a function's Machine IR", false, 720b57cec5SDimitry Andric false) 730b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 740b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass) 750b57cec5SDimitry Andric INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE, 760b57cec5SDimitry Andric "Legalize the Machine IR a function's Machine IR", false, 770b57cec5SDimitry Andric false) 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric Legalizer::Legalizer() : MachineFunctionPass(ID) { } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { 820b57cec5SDimitry Andric AU.addRequired<TargetPassConfig>(); 830b57cec5SDimitry Andric AU.addRequired<GISelCSEAnalysisWrapperPass>(); 840b57cec5SDimitry Andric AU.addPreserved<GISelCSEAnalysisWrapperPass>(); 850b57cec5SDimitry Andric getSelectionDAGFallbackAnalysisUsage(AU); 860b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric void Legalizer::init(MachineFunction &MF) { 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric static bool isArtifact(const MachineInstr &MI) { 930b57cec5SDimitry Andric switch (MI.getOpcode()) { 940b57cec5SDimitry Andric default: 950b57cec5SDimitry Andric return false; 960b57cec5SDimitry Andric case TargetOpcode::G_TRUNC: 970b57cec5SDimitry Andric case TargetOpcode::G_ZEXT: 980b57cec5SDimitry Andric case TargetOpcode::G_ANYEXT: 990b57cec5SDimitry Andric case TargetOpcode::G_SEXT: 1000b57cec5SDimitry Andric case TargetOpcode::G_MERGE_VALUES: 1010b57cec5SDimitry Andric case TargetOpcode::G_UNMERGE_VALUES: 1020b57cec5SDimitry Andric case TargetOpcode::G_CONCAT_VECTORS: 1030b57cec5SDimitry Andric case TargetOpcode::G_BUILD_VECTOR: 1040b57cec5SDimitry Andric case TargetOpcode::G_EXTRACT: 1050b57cec5SDimitry Andric return true; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric using InstListTy = GISelWorkList<256>; 1090b57cec5SDimitry Andric using ArtifactListTy = GISelWorkList<128>; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric namespace { 1120b57cec5SDimitry Andric class LegalizerWorkListManager : public GISelChangeObserver { 1130b57cec5SDimitry Andric InstListTy &InstList; 1140b57cec5SDimitry Andric ArtifactListTy &ArtifactList; 1150b57cec5SDimitry Andric #ifndef NDEBUG 1160b57cec5SDimitry Andric SmallVector<MachineInstr *, 4> NewMIs; 1170b57cec5SDimitry Andric #endif 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric public: 1200b57cec5SDimitry Andric LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts) 1210b57cec5SDimitry Andric : InstList(Insts), ArtifactList(Arts) {} 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric void createdOrChangedInstr(MachineInstr &MI) { 1240b57cec5SDimitry Andric // Only legalize pre-isel generic instructions. 1250b57cec5SDimitry Andric // Legalization process could generate Target specific pseudo 1260b57cec5SDimitry Andric // instructions with generic types. Don't record them 1270b57cec5SDimitry Andric if (isPreISelGenericOpcode(MI.getOpcode())) { 1280b57cec5SDimitry Andric if (isArtifact(MI)) 1290b57cec5SDimitry Andric ArtifactList.insert(&MI); 1300b57cec5SDimitry Andric else 1310b57cec5SDimitry Andric InstList.insert(&MI); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric void createdInstr(MachineInstr &MI) override { 1360b57cec5SDimitry Andric LLVM_DEBUG(NewMIs.push_back(&MI)); 1370b57cec5SDimitry Andric createdOrChangedInstr(MI); 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric void printNewInstrs() { 1410b57cec5SDimitry Andric LLVM_DEBUG({ 1420b57cec5SDimitry Andric for (const auto *MI : NewMIs) 1430b57cec5SDimitry Andric dbgs() << ".. .. New MI: " << *MI; 1440b57cec5SDimitry Andric NewMIs.clear(); 1450b57cec5SDimitry Andric }); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric void erasingInstr(MachineInstr &MI) override { 1490b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI); 1500b57cec5SDimitry Andric InstList.remove(&MI); 1510b57cec5SDimitry Andric ArtifactList.remove(&MI); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric void changingInstr(MachineInstr &MI) override { 1550b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric void changedInstr(MachineInstr &MI) override { 1590b57cec5SDimitry Andric // When insts change, we want to revisit them to legalize them again. 1600b57cec5SDimitry Andric // We'll consider them the same as created. 1610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI); 1620b57cec5SDimitry Andric createdOrChangedInstr(MI); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric }; 1650b57cec5SDimitry Andric } // namespace 1660b57cec5SDimitry Andric 167480093f4SDimitry Andric Legalizer::MFResult 168480093f4SDimitry Andric Legalizer::legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI, 169480093f4SDimitry Andric ArrayRef<GISelChangeObserver *> AuxObservers, 170*5ffd83dbSDimitry Andric LostDebugLocObserver &LocObserver, 171480093f4SDimitry Andric MachineIRBuilder &MIRBuilder) { 172*5ffd83dbSDimitry Andric MIRBuilder.setMF(MF); 1730b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 1740b57cec5SDimitry Andric 175480093f4SDimitry Andric // Populate worklists. 1760b57cec5SDimitry Andric InstListTy InstList; 1770b57cec5SDimitry Andric ArtifactListTy ArtifactList; 1780b57cec5SDimitry Andric ReversePostOrderTraversal<MachineFunction *> RPOT(&MF); 1790b57cec5SDimitry Andric // Perform legalization bottom up so we can DCE as we legalize. 1800b57cec5SDimitry Andric // Traverse BB in RPOT and within each basic block, add insts top down, 1810b57cec5SDimitry Andric // so when we pop_back_val in the legalization process, we traverse bottom-up. 1820b57cec5SDimitry Andric for (auto *MBB : RPOT) { 1830b57cec5SDimitry Andric if (MBB->empty()) 1840b57cec5SDimitry Andric continue; 1850b57cec5SDimitry Andric for (MachineInstr &MI : *MBB) { 1860b57cec5SDimitry Andric // Only legalize pre-isel generic instructions: others don't have types 1870b57cec5SDimitry Andric // and are assumed to be legal. 1880b57cec5SDimitry Andric if (!isPreISelGenericOpcode(MI.getOpcode())) 1890b57cec5SDimitry Andric continue; 1900b57cec5SDimitry Andric if (isArtifact(MI)) 1910b57cec5SDimitry Andric ArtifactList.deferred_insert(&MI); 1920b57cec5SDimitry Andric else 1930b57cec5SDimitry Andric InstList.deferred_insert(&MI); 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric ArtifactList.finalize(); 1970b57cec5SDimitry Andric InstList.finalize(); 1980b57cec5SDimitry Andric 199480093f4SDimitry Andric // This observer keeps the worklists updated. 2000b57cec5SDimitry Andric LegalizerWorkListManager WorkListObserver(InstList, ArtifactList); 201480093f4SDimitry Andric // We want both WorkListObserver as well as all the auxiliary observers (e.g. 202480093f4SDimitry Andric // CSEInfo) to observe all changes. Use the wrapper observer. 2030b57cec5SDimitry Andric GISelObserverWrapper WrapperObserver(&WorkListObserver); 204480093f4SDimitry Andric for (GISelChangeObserver *Observer : AuxObservers) 205480093f4SDimitry Andric WrapperObserver.addObserver(Observer); 206480093f4SDimitry Andric 2070b57cec5SDimitry Andric // Now install the observer as the delegate to MF. 2080b57cec5SDimitry Andric // This will keep all the observers notified about new insertions/deletions. 209*5ffd83dbSDimitry Andric RAIIMFObsDelInstaller Installer(MF, WrapperObserver); 210480093f4SDimitry Andric LegalizerHelper Helper(MF, LI, WrapperObserver, MIRBuilder); 211480093f4SDimitry Andric LegalizationArtifactCombiner ArtCombiner(MIRBuilder, MRI, LI); 2120b57cec5SDimitry Andric auto RemoveDeadInstFromLists = [&WrapperObserver](MachineInstr *DeadMI) { 2130b57cec5SDimitry Andric WrapperObserver.erasingInstr(*DeadMI); 2140b57cec5SDimitry Andric }; 2150b57cec5SDimitry Andric bool Changed = false; 2168bcb0991SDimitry Andric SmallVector<MachineInstr *, 128> RetryList; 2170b57cec5SDimitry Andric do { 218480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "=== New Iteration ===\n"); 2198bcb0991SDimitry Andric assert(RetryList.empty() && "Expected no instructions in RetryList"); 2208bcb0991SDimitry Andric unsigned NumArtifacts = ArtifactList.size(); 2210b57cec5SDimitry Andric while (!InstList.empty()) { 2220b57cec5SDimitry Andric MachineInstr &MI = *InstList.pop_back_val(); 223480093f4SDimitry Andric assert(isPreISelGenericOpcode(MI.getOpcode()) && 224480093f4SDimitry Andric "Expecting generic opcode"); 2250b57cec5SDimitry Andric if (isTriviallyDead(MI, MRI)) { 2260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << MI << "Is dead; erasing.\n"); 2270b57cec5SDimitry Andric MI.eraseFromParentAndMarkDBGValuesForRemoval(); 228*5ffd83dbSDimitry Andric LocObserver.checkpoint(false); 2290b57cec5SDimitry Andric continue; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // Do the legalization for this instruction. 2330b57cec5SDimitry Andric auto Res = Helper.legalizeInstrStep(MI); 2340b57cec5SDimitry Andric // Error out if we couldn't legalize this instruction. We may want to 2350b57cec5SDimitry Andric // fall back to DAG ISel instead in the future. 2360b57cec5SDimitry Andric if (Res == LegalizerHelper::UnableToLegalize) { 2378bcb0991SDimitry Andric // Move illegal artifacts to RetryList instead of aborting because 2388bcb0991SDimitry Andric // legalizing InstList may generate artifacts that allow 2398bcb0991SDimitry Andric // ArtifactCombiner to combine away them. 2408bcb0991SDimitry Andric if (isArtifact(MI)) { 241480093f4SDimitry Andric LLVM_DEBUG(dbgs() << ".. Not legalized, moving to artifacts retry\n"); 242480093f4SDimitry Andric assert(NumArtifacts == 0 && 243480093f4SDimitry Andric "Artifacts are only expected in instruction list starting the " 244480093f4SDimitry Andric "second iteration, but each iteration starting second must " 245480093f4SDimitry Andric "start with an empty artifacts list"); 246480093f4SDimitry Andric (void)NumArtifacts; 2478bcb0991SDimitry Andric RetryList.push_back(&MI); 2488bcb0991SDimitry Andric continue; 2498bcb0991SDimitry Andric } 250480093f4SDimitry Andric Helper.MIRBuilder.stopObservingChanges(); 251480093f4SDimitry Andric return {Changed, &MI}; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric WorkListObserver.printNewInstrs(); 254*5ffd83dbSDimitry Andric LocObserver.checkpoint(); 2550b57cec5SDimitry Andric Changed |= Res == LegalizerHelper::Legalized; 2560b57cec5SDimitry Andric } 2578bcb0991SDimitry Andric // Try to combine the instructions in RetryList again if there 2588bcb0991SDimitry Andric // are new artifacts. If not, stop legalizing. 2598bcb0991SDimitry Andric if (!RetryList.empty()) { 260480093f4SDimitry Andric if (!ArtifactList.empty()) { 2618bcb0991SDimitry Andric while (!RetryList.empty()) 2628bcb0991SDimitry Andric ArtifactList.insert(RetryList.pop_back_val()); 2638bcb0991SDimitry Andric } else { 264480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "No new artifacts created, not retrying!\n"); 265480093f4SDimitry Andric Helper.MIRBuilder.stopObservingChanges(); 266480093f4SDimitry Andric return {Changed, RetryList.front()}; 2678bcb0991SDimitry Andric } 2688bcb0991SDimitry Andric } 269*5ffd83dbSDimitry Andric LocObserver.checkpoint(); 2700b57cec5SDimitry Andric while (!ArtifactList.empty()) { 2710b57cec5SDimitry Andric MachineInstr &MI = *ArtifactList.pop_back_val(); 272480093f4SDimitry Andric assert(isPreISelGenericOpcode(MI.getOpcode()) && 273480093f4SDimitry Andric "Expecting generic opcode"); 2740b57cec5SDimitry Andric if (isTriviallyDead(MI, MRI)) { 2750b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << MI << "Is dead\n"); 2760b57cec5SDimitry Andric RemoveDeadInstFromLists(&MI); 2770b57cec5SDimitry Andric MI.eraseFromParentAndMarkDBGValuesForRemoval(); 278*5ffd83dbSDimitry Andric LocObserver.checkpoint(false); 2790b57cec5SDimitry Andric continue; 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric SmallVector<MachineInstr *, 4> DeadInstructions; 282480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "Trying to combine: " << MI); 2830b57cec5SDimitry Andric if (ArtCombiner.tryCombineInstruction(MI, DeadInstructions, 2840b57cec5SDimitry Andric WrapperObserver)) { 2850b57cec5SDimitry Andric WorkListObserver.printNewInstrs(); 2860b57cec5SDimitry Andric for (auto *DeadMI : DeadInstructions) { 2870b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << *DeadMI << "Is dead\n"); 2880b57cec5SDimitry Andric RemoveDeadInstFromLists(DeadMI); 2890b57cec5SDimitry Andric DeadMI->eraseFromParentAndMarkDBGValuesForRemoval(); 2900b57cec5SDimitry Andric } 291*5ffd83dbSDimitry Andric LocObserver.checkpoint( 292*5ffd83dbSDimitry Andric VerifyDebugLocs == 293*5ffd83dbSDimitry Andric DebugLocVerifyLevel::LegalizationsAndArtifactCombiners); 2940b57cec5SDimitry Andric Changed = true; 2950b57cec5SDimitry Andric continue; 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric // If this was not an artifact (that could be combined away), this might 2980b57cec5SDimitry Andric // need special handling. Add it to InstList, so when it's processed 2990b57cec5SDimitry Andric // there, it has to be legal or specially handled. 300480093f4SDimitry Andric else { 301480093f4SDimitry Andric LLVM_DEBUG(dbgs() << ".. Not combined, moving to instructions list\n"); 3020b57cec5SDimitry Andric InstList.insert(&MI); 3030b57cec5SDimitry Andric } 304480093f4SDimitry Andric } 3050b57cec5SDimitry Andric } while (!InstList.empty()); 3060b57cec5SDimitry Andric 307480093f4SDimitry Andric return {Changed, /*FailedOn*/ nullptr}; 308480093f4SDimitry Andric } 309480093f4SDimitry Andric 310480093f4SDimitry Andric bool Legalizer::runOnMachineFunction(MachineFunction &MF) { 311480093f4SDimitry Andric // If the ISel pipeline failed, do not bother running that pass. 312480093f4SDimitry Andric if (MF.getProperties().hasProperty( 313480093f4SDimitry Andric MachineFunctionProperties::Property::FailedISel)) 314480093f4SDimitry Andric return false; 315480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n'); 316480093f4SDimitry Andric init(MF); 317480093f4SDimitry Andric const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); 318480093f4SDimitry Andric GISelCSEAnalysisWrapper &Wrapper = 319480093f4SDimitry Andric getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper(); 320480093f4SDimitry Andric MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); 321480093f4SDimitry Andric 322480093f4SDimitry Andric const size_t NumBlocks = MF.size(); 323480093f4SDimitry Andric 324480093f4SDimitry Andric std::unique_ptr<MachineIRBuilder> MIRBuilder; 325480093f4SDimitry Andric GISelCSEInfo *CSEInfo = nullptr; 326480093f4SDimitry Andric bool EnableCSE = EnableCSEInLegalizer.getNumOccurrences() 327480093f4SDimitry Andric ? EnableCSEInLegalizer 328480093f4SDimitry Andric : TPC.isGISelCSEEnabled(); 329480093f4SDimitry Andric if (EnableCSE) { 330480093f4SDimitry Andric MIRBuilder = std::make_unique<CSEMIRBuilder>(); 331480093f4SDimitry Andric CSEInfo = &Wrapper.get(TPC.getCSEConfig()); 332480093f4SDimitry Andric MIRBuilder->setCSEInfo(CSEInfo); 333480093f4SDimitry Andric } else 334480093f4SDimitry Andric MIRBuilder = std::make_unique<MachineIRBuilder>(); 335480093f4SDimitry Andric 336480093f4SDimitry Andric SmallVector<GISelChangeObserver *, 1> AuxObservers; 337480093f4SDimitry Andric if (EnableCSE && CSEInfo) { 338480093f4SDimitry Andric // We want CSEInfo in addition to WorkListObserver to observe all changes. 339480093f4SDimitry Andric AuxObservers.push_back(CSEInfo); 340480093f4SDimitry Andric } 341*5ffd83dbSDimitry Andric assert(!CSEInfo || !errorToBool(CSEInfo->verify())); 342*5ffd83dbSDimitry Andric LostDebugLocObserver LocObserver(DEBUG_TYPE); 343*5ffd83dbSDimitry Andric if (VerifyDebugLocs > DebugLocVerifyLevel::None) 344*5ffd83dbSDimitry Andric AuxObservers.push_back(&LocObserver); 345480093f4SDimitry Andric 346480093f4SDimitry Andric const LegalizerInfo &LI = *MF.getSubtarget().getLegalizerInfo(); 347*5ffd83dbSDimitry Andric MFResult Result = 348*5ffd83dbSDimitry Andric legalizeMachineFunction(MF, LI, AuxObservers, LocObserver, *MIRBuilder); 349480093f4SDimitry Andric 350480093f4SDimitry Andric if (Result.FailedOn) { 351480093f4SDimitry Andric reportGISelFailure(MF, TPC, MORE, "gisel-legalize", 352480093f4SDimitry Andric "unable to legalize instruction", *Result.FailedOn); 353480093f4SDimitry Andric return false; 354480093f4SDimitry Andric } 3550b57cec5SDimitry Andric // For now don't support if new blocks are inserted - we would need to fix the 3560b57cec5SDimitry Andric // outer loop for that. 3570b57cec5SDimitry Andric if (MF.size() != NumBlocks) { 3580b57cec5SDimitry Andric MachineOptimizationRemarkMissed R("gisel-legalize", "GISelFailure", 3590b57cec5SDimitry Andric MF.getFunction().getSubprogram(), 3600b57cec5SDimitry Andric /*MBB=*/nullptr); 3610b57cec5SDimitry Andric R << "inserting blocks is not supported yet"; 3620b57cec5SDimitry Andric reportGISelFailure(MF, TPC, MORE, R); 3630b57cec5SDimitry Andric return false; 3640b57cec5SDimitry Andric } 365*5ffd83dbSDimitry Andric 366*5ffd83dbSDimitry Andric if (LocObserver.getNumLostDebugLocs()) { 367*5ffd83dbSDimitry Andric MachineOptimizationRemarkMissed R("gisel-legalize", "LostDebugLoc", 368*5ffd83dbSDimitry Andric MF.getFunction().getSubprogram(), 369*5ffd83dbSDimitry Andric /*MBB=*/&*MF.begin()); 370*5ffd83dbSDimitry Andric R << "lost " 371*5ffd83dbSDimitry Andric << ore::NV("NumLostDebugLocs", LocObserver.getNumLostDebugLocs()) 372*5ffd83dbSDimitry Andric << " debug locations during pass"; 373*5ffd83dbSDimitry Andric reportGISelWarning(MF, TPC, MORE, R); 374*5ffd83dbSDimitry Andric // Example remark: 375*5ffd83dbSDimitry Andric // --- !Missed 376*5ffd83dbSDimitry Andric // Pass: gisel-legalize 377*5ffd83dbSDimitry Andric // Name: GISelFailure 378*5ffd83dbSDimitry Andric // DebugLoc: { File: '.../legalize-urem.mir', Line: 1, Column: 0 } 379*5ffd83dbSDimitry Andric // Function: test_urem_s32 380*5ffd83dbSDimitry Andric // Args: 381*5ffd83dbSDimitry Andric // - String: 'lost ' 382*5ffd83dbSDimitry Andric // - NumLostDebugLocs: '1' 383*5ffd83dbSDimitry Andric // - String: ' debug locations during pass' 384*5ffd83dbSDimitry Andric // ... 385*5ffd83dbSDimitry Andric } 386*5ffd83dbSDimitry Andric 387*5ffd83dbSDimitry Andric // If for some reason CSE was not enabled, make sure that we invalidate the 388*5ffd83dbSDimitry Andric // CSEInfo object (as we currently declare that the analysis is preserved). 389*5ffd83dbSDimitry Andric // The next time get on the wrapper is called, it will force it to recompute 390*5ffd83dbSDimitry Andric // the analysis. 391*5ffd83dbSDimitry Andric if (!EnableCSE) 392*5ffd83dbSDimitry Andric Wrapper.setComputed(false); 393480093f4SDimitry Andric return Result.Changed; 3940b57cec5SDimitry Andric } 395