diff options
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp | 264 | 
1 files changed, 264 insertions, 0 deletions
| diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp new file mode 100644 index 000000000000..7c4fd2d140d3 --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -0,0 +1,264 @@ +//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the InstructionSelect class. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/InstructionSelect.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/Config/config.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" + +#define DEBUG_TYPE "instruction-select" + +using namespace llvm; + +#ifdef LLVM_GISEL_COV_PREFIX +static cl::opt<std::string> +    CoveragePrefix("gisel-coverage-prefix", cl::init(LLVM_GISEL_COV_PREFIX), +                   cl::desc("Record GlobalISel rule coverage files of this " +                            "prefix if instrumentation was generated")); +#else +static const std::string CoveragePrefix = ""; +#endif + +char InstructionSelect::ID = 0; +INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE, +                      "Select target instructions out of generic instructions", +                      false, false) +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis) +INITIALIZE_PASS_END(InstructionSelect, DEBUG_TYPE, +                    "Select target instructions out of generic instructions", +                    false, false) + +InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) { } + +void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const { +  AU.addRequired<TargetPassConfig>(); +  AU.addRequired<GISelKnownBitsAnalysis>(); +  AU.addPreserved<GISelKnownBitsAnalysis>(); +  getSelectionDAGFallbackAnalysisUsage(AU); +  MachineFunctionPass::getAnalysisUsage(AU); +} + +bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { +  // If the ISel pipeline failed, do not bother running that pass. +  if (MF.getProperties().hasProperty( +          MachineFunctionProperties::Property::FailedISel)) +    return false; + +  LLVM_DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n'); +  GISelKnownBits &KB = getAnalysis<GISelKnownBitsAnalysis>().get(MF); + +  const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); +  InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector(); +  CodeGenCoverage CoverageInfo; +  assert(ISel && "Cannot work without InstructionSelector"); +  ISel->setupMF(MF, KB, CoverageInfo); + +  // An optimization remark emitter. Used to report failures. +  MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); + +  // FIXME: There are many other MF/MFI fields we need to initialize. + +  MachineRegisterInfo &MRI = MF.getRegInfo(); +#ifndef NDEBUG +  // Check that our input is fully legal: we require the function to have the +  // Legalized property, so it should be. +  // FIXME: This should be in the MachineVerifier, as the RegBankSelected +  // property check already is. +  if (!DisableGISelLegalityCheck) +    if (const MachineInstr *MI = machineFunctionIsIllegal(MF)) { +      reportGISelFailure(MF, TPC, MORE, "gisel-select", +                         "instruction is not legal", *MI); +      return false; +    } +  // FIXME: We could introduce new blocks and will need to fix the outer loop. +  // Until then, keep track of the number of blocks to assert that we don't. +  const size_t NumBlocks = MF.size(); +#endif + +  for (MachineBasicBlock *MBB : post_order(&MF)) { +    if (MBB->empty()) +      continue; + +    // Select instructions in reverse block order. We permit erasing so have +    // to resort to manually iterating and recognizing the begin (rend) case. +    bool ReachedBegin = false; +    for (auto MII = std::prev(MBB->end()), Begin = MBB->begin(); +         !ReachedBegin;) { +#ifndef NDEBUG +      // Keep track of the insertion range for debug printing. +      const auto AfterIt = std::next(MII); +#endif +      // Select this instruction. +      MachineInstr &MI = *MII; + +      // And have our iterator point to the next instruction, if there is one. +      if (MII == Begin) +        ReachedBegin = true; +      else +        --MII; + +      LLVM_DEBUG(dbgs() << "Selecting: \n  " << MI); + +      // We could have folded this instruction away already, making it dead. +      // If so, erase it. +      if (isTriviallyDead(MI, MRI)) { +        LLVM_DEBUG(dbgs() << "Is dead; erasing.\n"); +        MI.eraseFromParentAndMarkDBGValuesForRemoval(); +        continue; +      } + +      if (!ISel->select(MI)) { +        // FIXME: It would be nice to dump all inserted instructions.  It's +        // not obvious how, esp. considering select() can insert after MI. +        reportGISelFailure(MF, TPC, MORE, "gisel-select", "cannot select", MI); +        return false; +      } + +      // Dump the range of instructions that MI expanded into. +      LLVM_DEBUG({ +        auto InsertedBegin = ReachedBegin ? MBB->begin() : std::next(MII); +        dbgs() << "Into:\n"; +        for (auto &InsertedMI : make_range(InsertedBegin, AfterIt)) +          dbgs() << "  " << InsertedMI; +        dbgs() << '\n'; +      }); +    } +  } + +  for (MachineBasicBlock &MBB : MF) { +    if (MBB.empty()) +      continue; + +    // Try to find redundant copies b/w vregs of the same register class. +    bool ReachedBegin = false; +    for (auto MII = std::prev(MBB.end()), Begin = MBB.begin(); !ReachedBegin;) { +      // Select this instruction. +      MachineInstr &MI = *MII; + +      // And have our iterator point to the next instruction, if there is one. +      if (MII == Begin) +        ReachedBegin = true; +      else +        --MII; +      if (MI.getOpcode() != TargetOpcode::COPY) +        continue; +      Register SrcReg = MI.getOperand(1).getReg(); +      Register DstReg = MI.getOperand(0).getReg(); +      if (Register::isVirtualRegister(SrcReg) && +          Register::isVirtualRegister(DstReg)) { +        auto SrcRC = MRI.getRegClass(SrcReg); +        auto DstRC = MRI.getRegClass(DstReg); +        if (SrcRC == DstRC) { +          MRI.replaceRegWith(DstReg, SrcReg); +          MI.eraseFromParentAndMarkDBGValuesForRemoval(); +        } +      } +    } +  } + +#ifndef NDEBUG +  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); +  // Now that selection is complete, there are no more generic vregs.  Verify +  // that the size of the now-constrained vreg is unchanged and that it has a +  // register class. +  for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { +    unsigned VReg = Register::index2VirtReg(I); + +    MachineInstr *MI = nullptr; +    if (!MRI.def_empty(VReg)) +      MI = &*MRI.def_instr_begin(VReg); +    else if (!MRI.use_empty(VReg)) +      MI = &*MRI.use_instr_begin(VReg); +    if (!MI) +      continue; + +    const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg); +    if (!RC) { +      reportGISelFailure(MF, TPC, MORE, "gisel-select", +                         "VReg has no regclass after selection", *MI); +      return false; +    } + +    const LLT Ty = MRI.getType(VReg); +    if (Ty.isValid() && Ty.getSizeInBits() > TRI.getRegSizeInBits(*RC)) { +      reportGISelFailure( +          MF, TPC, MORE, "gisel-select", +          "VReg's low-level type and register class have different sizes", *MI); +      return false; +    } +  } + +  if (MF.size() != NumBlocks) { +    MachineOptimizationRemarkMissed R("gisel-select", "GISelFailure", +                                      MF.getFunction().getSubprogram(), +                                      /*MBB=*/nullptr); +    R << "inserting blocks is not supported yet"; +    reportGISelFailure(MF, TPC, MORE, R); +    return false; +  } +#endif +  auto &TLI = *MF.getSubtarget().getTargetLowering(); +  TLI.finalizeLowering(MF); + +  // Determine if there are any calls in this machine function. Ported from +  // SelectionDAG. +  MachineFrameInfo &MFI = MF.getFrameInfo(); +  for (const auto &MBB : MF) { +    if (MFI.hasCalls() && MF.hasInlineAsm()) +      break; + +    for (const auto &MI : MBB) { +      if ((MI.isCall() && !MI.isReturn()) || MI.isStackAligningInlineAsm()) +        MFI.setHasCalls(true); +      if (MI.isInlineAsm()) +        MF.setHasInlineAsm(true); +    } +  } + + +  LLVM_DEBUG({ +    dbgs() << "Rules covered by selecting function: " << MF.getName() << ":"; +    for (auto RuleID : CoverageInfo.covered()) +      dbgs() << " id" << RuleID; +    dbgs() << "\n\n"; +  }); +  CoverageInfo.emit(CoveragePrefix, +                    MF.getSubtarget() +                        .getTargetLowering() +                        ->getTargetMachine() +                        .getTarget() +                        .getBackendName()); + +  // If we successfully selected the function nothing is going to use the vreg +  // types after us (otherwise MIRPrinter would need them). Make sure the types +  // disappear. +  MRI.clearVirtRegTypes(); + +  // FIXME: Should we accurately track changes? +  return true; +} | 
