xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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