diff options
Diffstat (limited to 'lib/CodeGen/GlobalISel')
| -rw-r--r-- | lib/CodeGen/GlobalISel/CMakeLists.txt | 42 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/CallLowering.cpp | 11 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/GlobalISel.cpp | 8 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/IRTranslator.cpp | 87 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/InstructionSelect.cpp | 27 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/InstructionSelector.cpp | 34 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/Legalizer.cpp | 247 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 230 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/LegalizerInfo.cpp | 397 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/Localizer.cpp | 5 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 92 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/RegBankSelect.cpp | 19 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/RegisterBank.cpp | 2 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/RegisterBankInfo.cpp | 55 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalISel/Utils.cpp | 25 |
15 files changed, 836 insertions, 445 deletions
diff --git a/lib/CodeGen/GlobalISel/CMakeLists.txt b/lib/CodeGen/GlobalISel/CMakeLists.txt index eba7ea8132e3..2db90f8888cb 100644 --- a/lib/CodeGen/GlobalISel/CMakeLists.txt +++ b/lib/CodeGen/GlobalISel/CMakeLists.txt @@ -1,34 +1,18 @@ -# List of all GlobalISel files. -set(GLOBAL_ISEL_FILES - CallLowering.cpp - IRTranslator.cpp - InstructionSelect.cpp - InstructionSelector.cpp - MachineIRBuilder.cpp - LegalizerHelper.cpp - Legalizer.cpp - LegalizerInfo.cpp - Localizer.cpp - RegBankSelect.cpp - RegisterBank.cpp - RegisterBankInfo.cpp - Utils.cpp - ) - -# Add GlobalISel files to the dependencies if the user wants to build it. -if(LLVM_BUILD_GLOBAL_ISEL) - set(GLOBAL_ISEL_BUILD_FILES ${GLOBAL_ISEL_FILES}) -else() - set(GLOBAL_ISEL_BUILD_FILES"") - set(LLVM_OPTIONAL_SOURCES LLVMGlobalISel ${GLOBAL_ISEL_FILES}) -endif() - -# In LLVMBuild.txt files, it is not possible to mark a dependency to a -# library as optional. So instead, generate an empty library if we did -# not ask for it. add_llvm_library(LLVMGlobalISel - ${GLOBAL_ISEL_BUILD_FILES} + CallLowering.cpp GlobalISel.cpp + IRTranslator.cpp + InstructionSelect.cpp + InstructionSelector.cpp + LegalizerHelper.cpp + Legalizer.cpp + LegalizerInfo.cpp + Localizer.cpp + MachineIRBuilder.cpp + RegBankSelect.cpp + RegisterBank.cpp + RegisterBankInfo.cpp + Utils.cpp DEPENDS intrinsics_gen diff --git a/lib/CodeGen/GlobalISel/CallLowering.cpp b/lib/CodeGen/GlobalISel/CallLowering.cpp index be0c5c2bb70e..114c068749eb 100644 --- a/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -16,10 +16,10 @@ #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLowering.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" -#include "llvm/Target/TargetLowering.h" using namespace llvm; @@ -108,7 +108,7 @@ bool CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args, ValueHandler &Handler) const { MachineFunction &MF = MIRBuilder.getMF(); - const Function &F = *MF.getFunction(); + const Function &F = MF.getFunction(); const DataLayout &DL = F.getParent()->getDataLayout(); SmallVector<CCValAssign, 16> ArgLocs; @@ -160,10 +160,11 @@ unsigned CallLowering::ValueHandler::extendRegister(unsigned ValReg, // FIXME: bitconverting between vector types may or may not be a // nop in big-endian situations. return ValReg; - case CCValAssign::AExt: + case CCValAssign::AExt: { assert(!VA.getLocVT().isVector() && "unexpected vector extend"); - // Otherwise, it's a nop. - return ValReg; + auto MIB = MIRBuilder.buildAnyExt(LocTy, ValReg); + return MIB->getOperand(0).getReg(); + } case CCValAssign::SExt: { unsigned NewReg = MRI.createGenericVirtualRegister(LocTy); MIRBuilder.buildSExt(NewReg, ValReg); diff --git a/lib/CodeGen/GlobalISel/GlobalISel.cpp b/lib/CodeGen/GlobalISel/GlobalISel.cpp index 29d1209bb02a..00c6a9d63158 100644 --- a/lib/CodeGen/GlobalISel/GlobalISel.cpp +++ b/lib/CodeGen/GlobalISel/GlobalISel.cpp @@ -16,13 +16,6 @@ using namespace llvm; -#ifndef LLVM_BUILD_GLOBAL_ISEL - -void llvm::initializeGlobalISel(PassRegistry &Registry) { -} - -#else - void llvm::initializeGlobalISel(PassRegistry &Registry) { initializeIRTranslatorPass(Registry); initializeLegalizerPass(Registry); @@ -30,4 +23,3 @@ void llvm::initializeGlobalISel(PassRegistry &Registry) { initializeRegBankSelectPass(Registry); initializeInstructionSelectPass(Registry); } -#endif // LLVM_BUILD_GLOBAL_ISEL diff --git a/lib/CodeGen/GlobalISel/IRTranslator.cpp b/lib/CodeGen/GlobalISel/IRTranslator.cpp index ed1bd995e60b..433f99b0113b 100644 --- a/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -15,7 +15,7 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Analysis/OptimizationDiagnosticInfo.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/LowLevelType.h" @@ -26,7 +26,11 @@ #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" @@ -54,12 +58,8 @@ #include "llvm/Support/LowLevelTypeImpl.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetIntrinsicInfo.h" -#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetSubtargetInfo.h" #include <algorithm> #include <cassert> #include <cstdint> @@ -124,8 +124,8 @@ unsigned IRTranslator::getOrCreateVReg(const Value &Val) { bool Success = translate(*CV, VReg); if (!Success) { OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", - MF->getFunction()->getSubprogram(), - &MF->getFunction()->getEntryBlock()); + MF->getFunction().getSubprogram(), + &MF->getFunction().getEntryBlock()); R << "unable to translate constant: " << ore::NV("Type", Val.getType()); reportTranslationError(*MF, *TPC, *ORE, R); return VReg; @@ -238,6 +238,8 @@ bool IRTranslator::translateCompare(const User &U, bool IRTranslator::translateRet(const User &U, MachineIRBuilder &MIRBuilder) { const ReturnInst &RI = cast<ReturnInst>(U); const Value *Ret = RI.getReturnValue(); + if (Ret && DL->getTypeStoreSize(Ret->getType()) == 0) + Ret = nullptr; // The target may mess up with the insertion point, but // this is not important as a return is the last instruction // of the block anyway. @@ -337,6 +339,9 @@ bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { : MachineMemOperand::MONone; Flags |= MachineMemOperand::MOLoad; + if (DL->getTypeStoreSize(LI.getType()) == 0) + return true; + unsigned Res = getOrCreateVReg(LI); unsigned Addr = getOrCreateVReg(*LI.getPointerOperand()); @@ -355,6 +360,9 @@ bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) { : MachineMemOperand::MONone; Flags |= MachineMemOperand::MOStore; + if (DL->getTypeStoreSize(SI.getValueOperand()->getType()) == 0) + return true; + unsigned Val = getOrCreateVReg(*SI.getValueOperand()); unsigned Addr = getOrCreateVReg(*SI.getPointerOperand()); @@ -583,7 +591,7 @@ void IRTranslator::getStackGuard(unsigned DstReg, MIB.addDef(DstReg); auto &TLI = *MF->getSubtarget().getTargetLowering(); - Value *Global = TLI.getSDagStackGuard(*MF->getFunction()->getParent()); + Value *Global = TLI.getSDagStackGuard(*MF->getFunction().getParent()); if (!Global) return; @@ -593,7 +601,7 @@ void IRTranslator::getStackGuard(unsigned DstReg, MachineMemOperand::MODereferenceable; *MemRefs = MF->getMachineMemOperand(MPInfo, Flags, DL->getPointerSizeInBits() / 8, - DL->getPointerABIAlignment()); + DL->getPointerABIAlignment(0)); MIB.setMemRefs(MemRefs, MemRefs + 1); } @@ -682,23 +690,16 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, if (!V) { // Currently the optimizer can produce this; insert an undef to // help debugging. Probably the optimizer should not do this. - MIRBuilder.buildIndirectDbgValue(0, DI.getOffset(), DI.getVariable(), - DI.getExpression()); + MIRBuilder.buildIndirectDbgValue(0, DI.getVariable(), DI.getExpression()); } else if (const auto *CI = dyn_cast<Constant>(V)) { - MIRBuilder.buildConstDbgValue(*CI, DI.getOffset(), DI.getVariable(), - DI.getExpression()); + MIRBuilder.buildConstDbgValue(*CI, DI.getVariable(), DI.getExpression()); } else { unsigned Reg = getOrCreateVReg(*V); // FIXME: This does not handle register-indirect values at offset 0. The // direct/indirect thing shouldn't really be handled by something as // implicit as reg+noreg vs reg+imm in the first palce, but it seems // pretty baked in right now. - if (DI.getOffset() != 0) - MIRBuilder.buildIndirectDbgValue(Reg, DI.getOffset(), DI.getVariable(), - DI.getExpression()); - else - MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), - DI.getExpression()); + MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), DI.getExpression()); } return true; } @@ -850,14 +851,10 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) { const TargetLowering &TLI = *MF->getSubtarget().getTargetLowering(); TargetLowering::IntrinsicInfo Info; // TODO: Add a GlobalISel version of getTgtMemIntrinsic. - if (TLI.getTgtMemIntrinsic(Info, CI, ID)) { - MachineMemOperand::Flags Flags = - Info.vol ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; - Flags |= - Info.readMem ? MachineMemOperand::MOLoad : MachineMemOperand::MOStore; - uint64_t Size = Info.memVT.getSizeInBits() >> 3; + if (TLI.getTgtMemIntrinsic(Info, CI, *MF, ID)) { + uint64_t Size = Info.memVT.getStoreSize(); MIB.addMemOperand(MF->getMachineMemOperand(MachinePointerInfo(Info.ptrVal), - Flags, Size, Info.align)); + Info.flags, Size, Info.align)); } return true; @@ -928,7 +925,7 @@ bool IRTranslator::translateLandingPad(const User &U, // If there aren't registers to copy the values into (e.g., during SjLj // exceptions), then don't bother. auto &TLI = *MF->getSubtarget().getTargetLowering(); - const Constant *PersonalityFn = MF->getFunction()->getPersonalityFn(); + const Constant *PersonalityFn = MF->getFunction().getPersonalityFn(); if (TLI.getExceptionPointerRegister(PersonalityFn) == 0 && TLI.getExceptionSelectorRegister(PersonalityFn) == 0) return true; @@ -1105,7 +1102,7 @@ bool IRTranslator::translateShuffleVector(const User &U, bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) { const PHINode &PI = cast<PHINode>(U); - auto MIB = MIRBuilder.buildInstr(TargetOpcode::PHI); + auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI); MIB.addDef(getOrCreateVReg(PI)); PendingPHIs.emplace_back(&PI, MIB.getInstr()); @@ -1239,7 +1236,7 @@ void IRTranslator::finalizeFunction() { bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { MF = &CurMF; - const Function &F = *MF->getFunction(); + const Function &F = MF->getFunction(); if (F.empty()) return false; CLI = MF->getSubtarget().getCallLowering(); @@ -1252,6 +1249,14 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { assert(PendingPHIs.empty() && "stale PHIs"); + if (!DL->isLittleEndian()) { + // Currently we don't properly handle big endian code. + OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", + F.getSubprogram(), &F.getEntryBlock()); + R << "unable to translate in big endian mode"; + reportTranslationError(*MF, *TPC, *ORE, R); + } + // Release the per-function state when we return, whether we succeeded or not. auto FinalizeOnReturn = make_scope_exit([this]() { finalizeFunction(); }); @@ -1276,12 +1281,14 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { // Lower the actual args into this basic block. SmallVector<unsigned, 8> VRegArgs; - for (const Argument &Arg: F.args()) + for (const Argument &Arg: F.args()) { + if (DL->getTypeStoreSize(Arg.getType()) == 0) + continue; // Don't handle zero sized types. VRegArgs.push_back(getOrCreateVReg(Arg)); + } if (!CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs)) { OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", - MF->getFunction()->getSubprogram(), - &MF->getFunction()->getEntryBlock()); + F.getSubprogram(), &F.getEntryBlock()); R << "unable to lower arguments: " << ore::NV("Prototype", F.getType()); reportTranslationError(*MF, *TPC, *ORE, R); return false; @@ -1298,14 +1305,18 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { if (translate(Inst)) continue; - std::string InstStrStorage; - raw_string_ostream InstStr(InstStrStorage); - InstStr << Inst; - OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", Inst.getDebugLoc(), &BB); - R << "unable to translate instruction: " << ore::NV("Opcode", &Inst) - << ": '" << InstStr.str() << "'"; + R << "unable to translate instruction: " << ore::NV("Opcode", &Inst); + + if (ORE->allowExtraAnalysis("gisel-irtranslator")) { + std::string InstStrStorage; + raw_string_ostream InstStr(InstStrStorage); + InstStr << Inst; + + R << ": '" << InstStr.str() << "'"; + } + reportTranslationError(*MF, *TPC, *ORE, R); return false; } diff --git a/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/lib/CodeGen/GlobalISel/InstructionSelect.cpp index a16e14fe2db6..422cc2219aa8 100644 --- a/lib/CodeGen/GlobalISel/InstructionSelect.cpp +++ b/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -19,18 +19,29 @@ #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/MachineRegisterInfo.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/Target/TargetLowering.h" -#include "llvm/Target/TargetSubtargetInfo.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", @@ -66,6 +77,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector(); + CodeGenCoverage CoverageInfo; assert(ISel && "Cannot work without InstructionSelector"); // An optimization remark emitter. Used to report failures. @@ -127,7 +139,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { continue; } - if (!ISel->select(MI)) { + if (!ISel->select(MI, CoverageInfo)) { // 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); @@ -177,7 +189,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { if (MF.size() != NumBlocks) { MachineOptimizationRemarkMissed R("gisel-select", "GISelFailure", - MF.getFunction()->getSubprogram(), + MF.getFunction().getSubprogram(), /*MBB=*/nullptr); R << "inserting blocks is not supported yet"; reportGISelFailure(MF, TPC, MORE, R); @@ -187,6 +199,13 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { auto &TLI = *MF.getSubtarget().getTargetLowering(); TLI.finalizeLowering(MF); + CoverageInfo.emit(CoveragePrefix, + MF.getSubtarget() + .getTargetLowering() + ->getTargetMachine() + .getTarget() + .getBackendName()); + // FIXME: Should we accurately track changes? return true; } diff --git a/lib/CodeGen/GlobalISel/InstructionSelector.cpp b/lib/CodeGen/GlobalISel/InstructionSelector.cpp index bf427225d6a9..88669bd68c00 100644 --- a/lib/CodeGen/GlobalISel/InstructionSelector.cpp +++ b/lib/CodeGen/GlobalISel/InstructionSelector.cpp @@ -6,8 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// /// \file /// This file implements the InstructionSelector class. +// //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" @@ -16,14 +18,11 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/MC/MCInstrDesc.h" -#include "llvm/IR/Constants.h" -#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetRegisterInfo.h" #include <cassert> #define DEBUG_TYPE "instructionselector" @@ -31,7 +30,7 @@ using namespace llvm; InstructionSelector::MatcherState::MatcherState(unsigned MaxRenderers) - : Renderers(MaxRenderers, nullptr), MIs() {} + : Renderers(MaxRenderers), MIs() {} InstructionSelector::InstructionSelector() = default; @@ -100,7 +99,30 @@ bool InstructionSelector::isOperandImmEqual( return false; } -bool InstructionSelector::isObviouslySafeToFold(MachineInstr &MI) const { +bool InstructionSelector::isBaseWithConstantOffset( + const MachineOperand &Root, const MachineRegisterInfo &MRI) const { + if (!Root.isReg()) + return false; + + MachineInstr *RootI = MRI.getVRegDef(Root.getReg()); + if (RootI->getOpcode() != TargetOpcode::G_GEP) + return false; + + MachineOperand &RHS = RootI->getOperand(2); + MachineInstr *RHSI = MRI.getVRegDef(RHS.getReg()); + if (RHSI->getOpcode() != TargetOpcode::G_CONSTANT) + return false; + + return true; +} + +bool InstructionSelector::isObviouslySafeToFold(MachineInstr &MI, + MachineInstr &IntoMI) const { + // Immediate neighbours are already folded. + if (MI.getParent() == IntoMI.getParent() && + std::next(MI.getIterator()) == IntoMI.getIterator()) + return true; + return !MI.mayLoadOrStore() && !MI.hasUnmodeledSideEffects() && MI.implicit_operands().begin() == MI.implicit_operands().end(); } diff --git a/lib/CodeGen/GlobalISel/Legalizer.cpp b/lib/CodeGen/GlobalISel/Legalizer.cpp index b699156c568b..f09b0d9f11e7 100644 --- a/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -14,14 +14,17 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GlobalISel/Legalizer.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/GlobalISel/GISelWorkList.h" +#include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Support/Debug.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetSubtargetInfo.h" #include <iterator> @@ -50,79 +53,18 @@ void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { void Legalizer::init(MachineFunction &MF) { } -bool Legalizer::combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, - const TargetInstrInfo &TII, - MachineIRBuilder &MIRBuilder) { - if (MI.getOpcode() != TargetOpcode::G_UNMERGE_VALUES) +static bool isArtifact(const MachineInstr &MI) { + switch (MI.getOpcode()) { + default: return false; - - unsigned NumDefs = MI.getNumOperands() - 1; - unsigned SrcReg = MI.getOperand(NumDefs).getReg(); - MachineInstr &MergeI = *MRI.def_instr_begin(SrcReg); - if (MergeI.getOpcode() != TargetOpcode::G_MERGE_VALUES) - return false; - - const unsigned NumMergeRegs = MergeI.getNumOperands() - 1; - - if (NumMergeRegs < NumDefs) { - if (NumDefs % NumMergeRegs != 0) - return false; - - MIRBuilder.setInstr(MI); - // Transform to UNMERGEs, for example - // %1 = G_MERGE_VALUES %4, %5 - // %9, %10, %11, %12 = G_UNMERGE_VALUES %1 - // to - // %9, %10 = G_UNMERGE_VALUES %4 - // %11, %12 = G_UNMERGE_VALUES %5 - - const unsigned NewNumDefs = NumDefs / NumMergeRegs; - for (unsigned Idx = 0; Idx < NumMergeRegs; ++Idx) { - SmallVector<unsigned, 2> DstRegs; - for (unsigned j = 0, DefIdx = Idx * NewNumDefs; j < NewNumDefs; - ++j, ++DefIdx) - DstRegs.push_back(MI.getOperand(DefIdx).getReg()); - - MIRBuilder.buildUnmerge(DstRegs, MergeI.getOperand(Idx + 1).getReg()); - } - - } else if (NumMergeRegs > NumDefs) { - if (NumMergeRegs % NumDefs != 0) - return false; - - MIRBuilder.setInstr(MI); - // Transform to MERGEs - // %6 = G_MERGE_VALUES %17, %18, %19, %20 - // %7, %8 = G_UNMERGE_VALUES %6 - // to - // %7 = G_MERGE_VALUES %17, %18 - // %8 = G_MERGE_VALUES %19, %20 - - const unsigned NumRegs = NumMergeRegs / NumDefs; - for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) { - SmallVector<unsigned, 2> Regs; - for (unsigned j = 0, Idx = NumRegs * DefIdx + 1; j < NumRegs; ++j, ++Idx) - Regs.push_back(MergeI.getOperand(Idx).getReg()); - - MIRBuilder.buildMerge(MI.getOperand(DefIdx).getReg(), Regs); - } - - } else { - // FIXME: is a COPY appropriate if the types mismatch? We know both - // registers are allocatable by now. - if (MRI.getType(MI.getOperand(0).getReg()) != - MRI.getType(MergeI.getOperand(1).getReg())) - return false; - - for (unsigned Idx = 0; Idx < NumDefs; ++Idx) - MRI.replaceRegWith(MI.getOperand(Idx).getReg(), - MergeI.getOperand(Idx + 1).getReg()); + case TargetOpcode::G_TRUNC: + case TargetOpcode::G_ZEXT: + case TargetOpcode::G_ANYEXT: + case TargetOpcode::G_SEXT: + case TargetOpcode::G_MERGE_VALUES: + case TargetOpcode::G_UNMERGE_VALUES: + return true; } - - MI.eraseFromParent(); - if (MRI.use_empty(MergeI.getOperand(0).getReg())) - MergeI.eraseFromParent(); - return true; } bool Legalizer::runOnMachineFunction(MachineFunction &MF) { @@ -136,79 +78,108 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) { MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); LegalizerHelper Helper(MF); - // FIXME: an instruction may need more than one pass before it is legal. For - // example on most architectures <3 x i3> is doubly-illegal. It would - // typically proceed along a path like: <3 x i3> -> <3 x i8> -> <8 x i8>. We - // probably want a worklist of instructions rather than naive iterate until - // convergence for performance reasons. - bool Changed = false; - MachineBasicBlock::iterator NextMI; - for (auto &MBB : MF) { - for (auto MI = MBB.begin(); MI != MBB.end(); MI = NextMI) { - // Get the next Instruction before we try to legalize, because there's a - // good chance MI will be deleted. - NextMI = std::next(MI); + const size_t NumBlocks = MF.size(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + // Populate Insts + GISelWorkList<256> InstList; + GISelWorkList<128> ArtifactList; + ReversePostOrderTraversal<MachineFunction *> RPOT(&MF); + // Perform legalization bottom up so we can DCE as we legalize. + // Traverse BB in RPOT and within each basic block, add insts top down, + // so when we pop_back_val in the legalization process, we traverse bottom-up. + for (auto *MBB : RPOT) { + if (MBB->empty()) + continue; + for (MachineInstr &MI : *MBB) { // Only legalize pre-isel generic instructions: others don't have types // and are assumed to be legal. - if (!isPreISelGenericOpcode(MI->getOpcode())) + if (!isPreISelGenericOpcode(MI.getOpcode())) continue; - unsigned NumNewInsns = 0; - SmallVector<MachineInstr *, 4> WorkList; - Helper.MIRBuilder.recordInsertions([&](MachineInstr *MI) { - // Only legalize pre-isel generic instructions. - // Legalization process could generate Target specific pseudo - // instructions with generic types. Don't record them - if (isPreISelGenericOpcode(MI->getOpcode())) { - ++NumNewInsns; - WorkList.push_back(MI); - } - }); - WorkList.push_back(&*MI); - - bool Changed = false; - LegalizerHelper::LegalizeResult Res; - unsigned Idx = 0; - do { - Res = Helper.legalizeInstrStep(*WorkList[Idx]); - // Error out if we couldn't legalize this instruction. We may want to - // fall back to DAG ISel instead in the future. - if (Res == LegalizerHelper::UnableToLegalize) { - Helper.MIRBuilder.stopRecordingInsertions(); - if (Res == LegalizerHelper::UnableToLegalize) { - reportGISelFailure(MF, TPC, MORE, "gisel-legalize", - "unable to legalize instruction", - *WorkList[Idx]); - return false; - } - } - Changed |= Res == LegalizerHelper::Legalized; - ++Idx; - -#ifndef NDEBUG - if (NumNewInsns) { - DEBUG(dbgs() << ".. .. Emitted " << NumNewInsns << " insns\n"); - for (auto I = WorkList.end() - NumNewInsns, E = WorkList.end(); - I != E; ++I) - DEBUG(dbgs() << ".. .. New MI: "; (*I)->print(dbgs())); - NumNewInsns = 0; - } -#endif - } while (Idx < WorkList.size()); - - Helper.MIRBuilder.stopRecordingInsertions(); + if (isArtifact(MI)) + ArtifactList.insert(&MI); + else + InstList.insert(&MI); } } + Helper.MIRBuilder.recordInsertions([&](MachineInstr *MI) { + // Only legalize pre-isel generic instructions. + // Legalization process could generate Target specific pseudo + // instructions with generic types. Don't record them + if (isPreISelGenericOpcode(MI->getOpcode())) { + if (isArtifact(*MI)) + ArtifactList.insert(MI); + else + InstList.insert(MI); + } + DEBUG(dbgs() << ".. .. New MI: " << *MI;); + }); + const LegalizerInfo &LInfo(Helper.getLegalizerInfo()); + LegalizationArtifactCombiner ArtCombiner(Helper.MIRBuilder, MF.getRegInfo(), LInfo); + auto RemoveDeadInstFromLists = [&InstList, + &ArtifactList](MachineInstr *DeadMI) { + InstList.remove(DeadMI); + ArtifactList.remove(DeadMI); + }; + bool Changed = false; + do { + while (!InstList.empty()) { + MachineInstr &MI = *InstList.pop_back_val(); + assert(isPreISelGenericOpcode(MI.getOpcode()) && "Expecting generic opcode"); + if (isTriviallyDead(MI, MRI)) { + DEBUG(dbgs() << MI << "Is dead; erasing.\n"); + MI.eraseFromParentAndMarkDBGValuesForRemoval(); + continue; + } - MachineRegisterInfo &MRI = MF.getRegInfo(); - const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); - for (auto &MBB : MF) { - for (auto MI = MBB.begin(); MI != MBB.end(); MI = NextMI) { - // Get the next Instruction before we try to legalize, because there's a - // good chance MI will be deleted. - NextMI = std::next(MI); - Changed |= combineMerges(*MI, MRI, TII, Helper.MIRBuilder); + // Do the legalization for this instruction. + auto Res = Helper.legalizeInstrStep(MI); + // Error out if we couldn't legalize this instruction. We may want to + // fall back to DAG ISel instead in the future. + if (Res == LegalizerHelper::UnableToLegalize) { + Helper.MIRBuilder.stopRecordingInsertions(); + reportGISelFailure(MF, TPC, MORE, "gisel-legalize", + "unable to legalize instruction", MI); + return false; + } + Changed |= Res == LegalizerHelper::Legalized; + } + while (!ArtifactList.empty()) { + MachineInstr &MI = *ArtifactList.pop_back_val(); + assert(isPreISelGenericOpcode(MI.getOpcode()) && "Expecting generic opcode"); + if (isTriviallyDead(MI, MRI)) { + DEBUG(dbgs() << MI << "Is dead; erasing.\n"); + RemoveDeadInstFromLists(&MI); + MI.eraseFromParentAndMarkDBGValuesForRemoval(); + continue; + } + SmallVector<MachineInstr *, 4> DeadInstructions; + if (ArtCombiner.tryCombineInstruction(MI, DeadInstructions)) { + for (auto *DeadMI : DeadInstructions) { + DEBUG(dbgs() << ".. Erasing Dead Instruction " << *DeadMI); + RemoveDeadInstFromLists(DeadMI); + DeadMI->eraseFromParentAndMarkDBGValuesForRemoval(); + } + Changed = true; + continue; + } + // If this was not an artifact (that could be combined away), this might + // need special handling. Add it to InstList, so when it's processed + // there, it has to be legal or specially handled. + else + InstList.insert(&MI); } + } while (!InstList.empty()); + + // For now don't support if new blocks are inserted - we would need to fix the + // outerloop for that. + if (MF.size() != NumBlocks) { + MachineOptimizationRemarkMissed R("gisel-legalize", "GISelFailure", + MF.getFunction().getSubprogram(), + /*MBB=*/nullptr); + R << "inserting blocks is not supported yet"; + reportGISelFailure(MF, TPC, MORE, R); + return false; } return Changed; diff --git a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 5258370e6680..87a658be4c29 100644 --- a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -17,12 +17,11 @@ #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetLowering.h" -#include "llvm/Target/TargetSubtargetInfo.h" -#include <sstream> #define DEBUG_TYPE "legalizer" @@ -91,6 +90,15 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { case TargetOpcode::G_FADD: assert((Size == 32 || Size == 64) && "Unsupported size"); return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32; + case TargetOpcode::G_FSUB: + assert((Size == 32 || Size == 64) && "Unsupported size"); + return Size == 64 ? RTLIB::SUB_F64 : RTLIB::SUB_F32; + case TargetOpcode::G_FMUL: + assert((Size == 32 || Size == 64) && "Unsupported size"); + return Size == 64 ? RTLIB::MUL_F64 : RTLIB::MUL_F32; + case TargetOpcode::G_FDIV: + assert((Size == 32 || Size == 64) && "Unsupported size"); + return Size == 64 ? RTLIB::DIV_F64 : RTLIB::DIV_F32; case TargetOpcode::G_FREM: return Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32; case TargetOpcode::G_FPOW: @@ -128,7 +136,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::libcall(MachineInstr &MI) { LLT LLTy = MRI.getType(MI.getOperand(0).getReg()); unsigned Size = LLTy.getSizeInBits(); - auto &Ctx = MIRBuilder.getMF().getFunction()->getContext(); + auto &Ctx = MIRBuilder.getMF().getFunction().getContext(); MIRBuilder.setInstr(MI); @@ -146,6 +154,9 @@ LegalizerHelper::libcall(MachineInstr &MI) { break; } case TargetOpcode::G_FADD: + case TargetOpcode::G_FSUB: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_FDIV: case TargetOpcode::G_FPOW: case TargetOpcode::G_FREM: { Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); @@ -169,12 +180,18 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, MIRBuilder.setInstr(MI); + int64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); + int64_t NarrowSize = NarrowTy.getSizeInBits(); + switch (MI.getOpcode()) { default: return UnableToLegalize; case TargetOpcode::G_IMPLICIT_DEF: { - int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / - NarrowTy.getSizeInBits(); + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) + return UnableToLegalize; + int NumParts = SizeOp0 / NarrowSize; SmallVector<unsigned, 2> DstRegs; for (int i = 0; i < NumParts; ++i) { @@ -187,9 +204,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return Legalized; } case TargetOpcode::G_ADD: { + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) + return UnableToLegalize; // Expand in terms of carry-setting/consuming G_ADDE instructions. - int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / - NarrowTy.getSizeInBits(); + int NumParts = SizeOp0 / NarrowTy.getSizeInBits(); SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); @@ -217,9 +237,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, if (TypeIdx != 1) return UnableToLegalize; - int64_t NarrowSize = NarrowTy.getSizeInBits(); - int NumParts = - MRI.getType(MI.getOperand(1).getReg()).getSizeInBits() / NarrowSize; + int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); + // FIXME: add support for when SizeOp1 isn't an exact multiple of + // NarrowSize. + if (SizeOp1 % NarrowSize != 0) + return UnableToLegalize; + int NumParts = SizeOp1 / NarrowSize; SmallVector<unsigned, 2> SrcRegs, DstRegs; SmallVector<uint64_t, 2> Indexes; @@ -266,12 +289,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return Legalized; } case TargetOpcode::G_INSERT: { - if (TypeIdx != 0) + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) return UnableToLegalize; - int64_t NarrowSize = NarrowTy.getSizeInBits(); - int NumParts = - MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; + int NumParts = SizeOp0 / NarrowSize; SmallVector<unsigned, 2> SrcRegs, DstRegs; SmallVector<uint64_t, 2> Indexes; @@ -326,9 +349,11 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return Legalized; } case TargetOpcode::G_LOAD: { - unsigned NarrowSize = NarrowTy.getSizeInBits(); - int NumParts = - MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) + return UnableToLegalize; + int NumParts = SizeOp0 / NarrowSize; LLT OffsetTy = LLT::scalar( MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits()); @@ -353,9 +378,11 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return Legalized; } case TargetOpcode::G_STORE: { - unsigned NarrowSize = NarrowTy.getSizeInBits(); - int NumParts = - MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) + return UnableToLegalize; + int NumParts = SizeOp0 / NarrowSize; LLT OffsetTy = LLT::scalar( MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits()); @@ -377,11 +404,13 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return Legalized; } case TargetOpcode::G_CONSTANT: { - unsigned NarrowSize = NarrowTy.getSizeInBits(); - int NumParts = - MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) + return UnableToLegalize; + int NumParts = SizeOp0 / NarrowSize; const APInt &Cst = MI.getOperand(1).getCImm()->getValue(); - LLVMContext &Ctx = MIRBuilder.getMF().getFunction()->getContext(); + LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); SmallVector<unsigned, 2> DstRegs; for (int i = 0; i < NumParts; ++i) { @@ -396,6 +425,53 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, MI.eraseFromParent(); return Legalized; } + case TargetOpcode::G_OR: { + // Legalize bitwise operation: + // A = BinOp<Ty> B, C + // into: + // B1, ..., BN = G_UNMERGE_VALUES B + // C1, ..., CN = G_UNMERGE_VALUES C + // A1 = BinOp<Ty/N> B1, C2 + // ... + // AN = BinOp<Ty/N> BN, CN + // A = G_MERGE_VALUES A1, ..., AN + + // FIXME: add support for when SizeOp0 isn't an exact multiple of + // NarrowSize. + if (SizeOp0 % NarrowSize != 0) + return UnableToLegalize; + int NumParts = SizeOp0 / NarrowSize; + + // List the registers where the destination will be scattered. + SmallVector<unsigned, 2> DstRegs; + // List the registers where the first argument will be split. + SmallVector<unsigned, 2> SrcsReg1; + // List the registers where the second argument will be split. + SmallVector<unsigned, 2> SrcsReg2; + // Create all the temporary registers. + for (int i = 0; i < NumParts; ++i) { + unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); + unsigned SrcReg1 = MRI.createGenericVirtualRegister(NarrowTy); + unsigned SrcReg2 = MRI.createGenericVirtualRegister(NarrowTy); + + DstRegs.push_back(DstReg); + SrcsReg1.push_back(SrcReg1); + SrcsReg2.push_back(SrcReg2); + } + // Explode the big arguments into smaller chunks. + MIRBuilder.buildUnmerge(SrcsReg1, MI.getOperand(1).getReg()); + MIRBuilder.buildUnmerge(SrcsReg2, MI.getOperand(2).getReg()); + + // Do the operation on each small part. + for (int i = 0; i < NumParts; ++i) + MIRBuilder.buildOr(DstRegs[i], SrcsReg1[i], SrcsReg2[i]); + + // Gather the destination registers into the final destination. + unsigned DstReg = MI.getOperand(0).getReg(); + MIRBuilder.buildMerge(DstReg, DstRegs); + MI.eraseFromParent(); + return Legalized; + } } } @@ -597,22 +673,58 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { MI.eraseFromParent(); return Legalized; } + case TargetOpcode::G_FCMP: { + unsigned Op0Ext, Op1Ext, DstReg; + unsigned Cmp1 = MI.getOperand(2).getReg(); + unsigned Cmp2 = MI.getOperand(3).getReg(); + if (TypeIdx == 0) { + Op0Ext = Cmp1; + Op1Ext = Cmp2; + DstReg = MRI.createGenericVirtualRegister(WideTy); + } else { + Op0Ext = MRI.createGenericVirtualRegister(WideTy); + Op1Ext = MRI.createGenericVirtualRegister(WideTy); + DstReg = MI.getOperand(0).getReg(); + MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op0Ext, Cmp1); + MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op1Ext, Cmp2); + } + MIRBuilder.buildFCmp( + static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), + DstReg, Op0Ext, Op1Ext); + if (TypeIdx == 0) + MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(), + DstReg); + MI.eraseFromParent(); + return Legalized; + } case TargetOpcode::G_ICMP: { - assert(TypeIdx == 1 && "unable to legalize predicate"); bool IsSigned = CmpInst::isSigned( static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate())); - unsigned Op0Ext = MRI.createGenericVirtualRegister(WideTy); - unsigned Op1Ext = MRI.createGenericVirtualRegister(WideTy); - if (IsSigned) { - MIRBuilder.buildSExt(Op0Ext, MI.getOperand(2).getReg()); - MIRBuilder.buildSExt(Op1Ext, MI.getOperand(3).getReg()); + unsigned Cmp1 = MI.getOperand(2).getReg(); + unsigned Cmp2 = MI.getOperand(3).getReg(); + unsigned Op0Ext, Op1Ext, DstReg; + if (TypeIdx == 0) { + Op0Ext = Cmp1; + Op1Ext = Cmp2; + DstReg = MRI.createGenericVirtualRegister(WideTy); } else { - MIRBuilder.buildZExt(Op0Ext, MI.getOperand(2).getReg()); - MIRBuilder.buildZExt(Op1Ext, MI.getOperand(3).getReg()); + Op0Ext = MRI.createGenericVirtualRegister(WideTy); + Op1Ext = MRI.createGenericVirtualRegister(WideTy); + DstReg = MI.getOperand(0).getReg(); + if (IsSigned) { + MIRBuilder.buildSExt(Op0Ext, Cmp1); + MIRBuilder.buildSExt(Op1Ext, Cmp2); + } else { + MIRBuilder.buildZExt(Op0Ext, Cmp1); + MIRBuilder.buildZExt(Op1Ext, Cmp2); + } } MIRBuilder.buildICmp( static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), - MI.getOperand(0).getReg(), Op0Ext, Op1Ext); + DstReg, Op0Ext, Op1Ext); + if (TypeIdx == 0) + MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(), + DstReg); MI.eraseFromParent(); return Legalized; } @@ -623,6 +735,35 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { MI.getOperand(2).setReg(OffsetExt); return Legalized; } + case TargetOpcode::G_PHI: { + assert(TypeIdx == 0 && "Expecting only Idx 0"); + auto getExtendedReg = [&](unsigned Reg, MachineBasicBlock &MBB) { + auto FirstTermIt = MBB.getFirstTerminator(); + MIRBuilder.setInsertPt(MBB, FirstTermIt); + MachineInstr *DefMI = MRI.getVRegDef(Reg); + MachineInstrBuilder MIB; + if (DefMI->getOpcode() == TargetOpcode::G_TRUNC) + MIB = MIRBuilder.buildAnyExtOrTrunc(WideTy, + DefMI->getOperand(1).getReg()); + else + MIB = MIRBuilder.buildAnyExt(WideTy, Reg); + return MIB->getOperand(0).getReg(); + }; + auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, WideTy); + for (auto OpIt = MI.operands_begin() + 1, OpE = MI.operands_end(); + OpIt != OpE;) { + unsigned Reg = OpIt++->getReg(); + MachineBasicBlock *OpMBB = OpIt++->getMBB(); + MIB.addReg(getExtendedReg(Reg, *OpMBB)); + MIB.addMBB(OpMBB); + } + auto *MBB = MI.getParent(); + MIRBuilder.setInsertPt(*MBB, MBB->getFirstNonPHI()); + MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), + MIB->getOperand(0).getReg()); + MI.eraseFromParent(); + return Legalized; + } } } @@ -683,7 +824,7 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { return UnableToLegalize; unsigned Res = MI.getOperand(0).getReg(); Type *ZeroTy; - LLVMContext &Ctx = MIRBuilder.getMF().getFunction()->getContext(); + LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); switch (Ty.getSizeInBits()) { case 16: ZeroTy = Type::getHalfTy(Ctx); @@ -726,6 +867,18 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { MI.eraseFromParent(); return Legalized; } + case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: { + unsigned OldValRes = MI.getOperand(0).getReg(); + unsigned SuccessRes = MI.getOperand(1).getReg(); + unsigned Addr = MI.getOperand(2).getReg(); + unsigned CmpVal = MI.getOperand(3).getReg(); + unsigned NewVal = MI.getOperand(4).getReg(); + MIRBuilder.buildAtomicCmpXchg(OldValRes, Addr, CmpVal, NewVal, + **MI.memoperands_begin()); + MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, OldValRes, CmpVal); + MI.eraseFromParent(); + return Legalized; + } } } @@ -741,7 +894,12 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case TargetOpcode::G_ADD: { unsigned NarrowSize = NarrowTy.getSizeInBits(); unsigned DstReg = MI.getOperand(0).getReg(); - int NumParts = MRI.getType(DstReg).getSizeInBits() / NarrowSize; + unsigned Size = MRI.getType(DstReg).getSizeInBits(); + int NumParts = Size / NarrowSize; + // FIXME: Don't know how to handle the situation where the small vectors + // aren't all the same size yet. + if (Size % NarrowSize != 0) + return UnableToLegalize; MIRBuilder.setInstr(MI); diff --git a/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/lib/CodeGen/GlobalISel/LegalizerInfo.cpp index 76917aa9660d..9c27c59a0654 100644 --- a/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ b/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -22,51 +22,136 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LowLevelTypeImpl.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Target/TargetOpcodes.h" #include <algorithm> -#include <cassert> -#include <tuple> -#include <utility> - +#include <map> using namespace llvm; -LegalizerInfo::LegalizerInfo() { - DefaultActions[TargetOpcode::G_IMPLICIT_DEF] = NarrowScalar; - - // FIXME: these two can be legalized to the fundamental load/store Jakob - // proposed. Once loads & stores are supported. - DefaultActions[TargetOpcode::G_ANYEXT] = Legal; - DefaultActions[TargetOpcode::G_TRUNC] = Legal; +LegalizerInfo::LegalizerInfo() : TablesInitialized(false) { + // Set defaults. + // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the + // fundamental load/store Jakob proposed. Once loads & stores are supported. + setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}}); + setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}}); + setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}}); + setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}}); + setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}}); - DefaultActions[TargetOpcode::G_INTRINSIC] = Legal; - DefaultActions[TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS] = Legal; + setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}}); + setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}}); - DefaultActions[TargetOpcode::G_ADD] = NarrowScalar; - DefaultActions[TargetOpcode::G_LOAD] = NarrowScalar; - DefaultActions[TargetOpcode::G_STORE] = NarrowScalar; + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall); - DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar; - DefaultActions[TargetOpcode::G_INSERT] = NarrowScalar; - DefaultActions[TargetOpcode::G_EXTRACT] = NarrowScalar; - DefaultActions[TargetOpcode::G_FNEG] = Lower; + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall); + setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}}); } void LegalizerInfo::computeTables() { - for (unsigned Opcode = 0; Opcode <= LastOp - FirstOp; ++Opcode) { - for (unsigned Idx = 0; Idx != Actions[Opcode].size(); ++Idx) { - for (auto &Action : Actions[Opcode][Idx]) { - LLT Ty = Action.first; - if (!Ty.isVector()) - continue; + assert(TablesInitialized == false); + + for (unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) { + const unsigned Opcode = FirstOp + OpcodeIdx; + for (unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size(); + ++TypeIdx) { + // 0. Collect information specified through the setAction API, i.e. + // for specific bit sizes. + // For scalar types: + SizeAndActionsVec ScalarSpecifiedActions; + // For pointer types: + std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions; + // For vector types: + std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions; + for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) { + const LLT Type = LLT2Action.first; + const LegalizeAction Action = LLT2Action.second; + + auto SizeAction = std::make_pair(Type.getSizeInBits(), Action); + if (Type.isPointer()) + AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back( + SizeAction); + else if (Type.isVector()) + ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()] + .push_back(SizeAction); + else + ScalarSpecifiedActions.push_back(SizeAction); + } + + // 1. Handle scalar types + { + // Decide how to handle bit sizes for which no explicit specification + // was given. + SizeChangeStrategy S = &unsupportedForDifferentSizes; + if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() && + ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) + S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx]; + std::sort(ScalarSpecifiedActions.begin(), ScalarSpecifiedActions.end()); + checkPartialSizeAndActionsVector(ScalarSpecifiedActions); + setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions)); + } + + // 2. Handle pointer types + for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) { + std::sort(PointerSpecifiedActions.second.begin(), + PointerSpecifiedActions.second.end()); + checkPartialSizeAndActionsVector(PointerSpecifiedActions.second); + // For pointer types, we assume that there isn't a meaningfull way + // to change the number of bits used in the pointer. + setPointerAction( + Opcode, TypeIdx, PointerSpecifiedActions.first, + unsupportedForDifferentSizes(PointerSpecifiedActions.second)); + } - auto &Entry = MaxLegalVectorElts[std::make_pair(Opcode + FirstOp, - Ty.getElementType())]; - Entry = std::max(Entry, Ty.getNumElements()); + // 3. Handle vector types + SizeAndActionsVec ElementSizesSeen; + for (auto VectorSpecifiedActions : ElemSize2SpecifiedActions) { + std::sort(VectorSpecifiedActions.second.begin(), + VectorSpecifiedActions.second.end()); + const uint16_t ElementSize = VectorSpecifiedActions.first; + ElementSizesSeen.push_back({ElementSize, Legal}); + checkPartialSizeAndActionsVector(VectorSpecifiedActions.second); + // For vector types, we assume that the best way to adapt the number + // of elements is to the next larger number of elements type for which + // the vector type is legal, unless there is no such type. In that case, + // legalize towards a vector type with a smaller number of elements. + SizeAndActionsVec NumElementsActions; + for (SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) { + assert(BitsizeAndAction.first % ElementSize == 0); + const uint16_t NumElements = BitsizeAndAction.first / ElementSize; + NumElementsActions.push_back({NumElements, BitsizeAndAction.second}); + } + setVectorNumElementAction( + Opcode, TypeIdx, ElementSize, + moreToWiderTypesAndLessToWidest(NumElementsActions)); } + std::sort(ElementSizesSeen.begin(), ElementSizesSeen.end()); + SizeChangeStrategy VectorElementSizeChangeStrategy = + &unsupportedForDifferentSizes; + if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() && + VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) + VectorElementSizeChangeStrategy = + VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx]; + setScalarInVectorAction( + Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen)); } } @@ -82,62 +167,23 @@ LegalizerInfo::getAction(const InstrAspect &Aspect) const { assert(TablesInitialized && "backend forgot to call computeTables"); // These *have* to be implemented for now, they're the fundamental basis of // how everything else is transformed. + if (Aspect.Type.isScalar() || Aspect.Type.isPointer()) + return findScalarLegalAction(Aspect); + assert(Aspect.Type.isVector()); + return findVectorLegalAction(Aspect); +} - // FIXME: the long-term plan calls for expansion in terms of load/store (if - // they're not legal). - if (Aspect.Opcode == TargetOpcode::G_MERGE_VALUES || - Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES) - return std::make_pair(Legal, Aspect.Type); - - LLT Ty = Aspect.Type; - LegalizeAction Action = findInActions(Aspect); - // LegalizerHelper is not able to handle non-power-of-2 types right now, so do - // not try to legalize them unless they are marked as Legal or Custom. - // FIXME: This is a temporary hack until the general non-power-of-2 - // legalization works. - if (!isPowerOf2_64(Ty.getSizeInBits()) && - !(Action == Legal || Action == Custom)) - return std::make_pair(Unsupported, LLT()); - - if (Action != NotFound) - return findLegalAction(Aspect, Action); - - unsigned Opcode = Aspect.Opcode; - if (!Ty.isVector()) { - auto DefaultAction = DefaultActions.find(Aspect.Opcode); - if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal) - return std::make_pair(Legal, Ty); - - if (DefaultAction != DefaultActions.end() && DefaultAction->second == Lower) - return std::make_pair(Lower, Ty); - - if (DefaultAction == DefaultActions.end() || - DefaultAction->second != NarrowScalar) - return std::make_pair(Unsupported, LLT()); - return findLegalAction(Aspect, NarrowScalar); - } - - LLT EltTy = Ty.getElementType(); - int NumElts = Ty.getNumElements(); - - auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy)); - if (ScalarAction != ScalarInVectorActions.end() && - ScalarAction->second != Legal) - return findLegalAction(Aspect, ScalarAction->second); - - // The element type is legal in principle, but the number of elements is - // wrong. - auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy)); - if (MaxLegalElts > NumElts) - return findLegalAction(Aspect, MoreElements); - - if (MaxLegalElts == 0) { - // Scalarize if there's no legal vector type, which is just a special case - // of FewerElements. - return std::make_pair(FewerElements, EltTy); - } - - return findLegalAction(Aspect, FewerElements); +/// Helper function to get LLT for the given type index. +static LLT getTypeFromTypeIdx(const MachineInstr &MI, + const MachineRegisterInfo &MRI, unsigned OpIdx, + unsigned TypeIdx) { + assert(TypeIdx < MI.getNumOperands() && "Unexpected TypeIdx"); + // G_UNMERGE_VALUES has variable number of operands, but there is only + // one source type and one destination type as all destinations must be the + // same type. So, get the last operand if TypeIdx == 1. + if (MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES && TypeIdx == 1) + return MRI.getType(MI.getOperand(MI.getNumOperands() - 1).getReg()); + return MRI.getType(MI.getOperand(OpIdx).getReg()); } std::tuple<LegalizerInfo::LegalizeAction, unsigned, LLT> @@ -145,19 +191,20 @@ LegalizerInfo::getAction(const MachineInstr &MI, const MachineRegisterInfo &MRI) const { SmallBitVector SeenTypes(8); const MCOperandInfo *OpInfo = MI.getDesc().OpInfo; + // FIXME: probably we'll need to cache the results here somehow? for (unsigned i = 0; i < MI.getDesc().getNumOperands(); ++i) { if (!OpInfo[i].isGenericType()) continue; - // We don't want to repeatedly check the same operand index, that - // could get expensive. + // We must only record actions once for each TypeIdx; otherwise we'd + // try to legalize operands multiple times down the line. unsigned TypeIdx = OpInfo[i].getGenericTypeIndex(); if (SeenTypes[TypeIdx]) continue; SeenTypes.set(TypeIdx); - LLT Ty = MRI.getType(MI.getOperand(i).getReg()); + LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx); auto Action = getAction({MI.getOpcode(), TypeIdx, Ty}); if (Action.first != Legal) return std::make_tuple(Action.first, TypeIdx, Action.second); @@ -170,38 +217,166 @@ bool LegalizerInfo::isLegal(const MachineInstr &MI, return std::get<0>(getAction(MI, MRI)) == Legal; } -Optional<LLT> LegalizerInfo::findLegalType(const InstrAspect &Aspect, - LegalizeAction Action) const { - switch(Action) { - default: - llvm_unreachable("Cannot find legal type"); +bool LegalizerInfo::legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, + MachineIRBuilder &MIRBuilder) const { + return false; +} + +LegalizerInfo::SizeAndActionsVec +LegalizerInfo::increaseToLargerTypesAndDecreaseToLargest( + const SizeAndActionsVec &v, LegalizeAction IncreaseAction, + LegalizeAction DecreaseAction) { + SizeAndActionsVec result; + unsigned LargestSizeSoFar = 0; + if (v.size() >= 1 && v[0].first != 1) + result.push_back({1, IncreaseAction}); + for (size_t i = 0; i < v.size(); ++i) { + result.push_back(v[i]); + LargestSizeSoFar = v[i].first; + if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) { + result.push_back({LargestSizeSoFar + 1, IncreaseAction}); + LargestSizeSoFar = v[i].first + 1; + } + } + result.push_back({LargestSizeSoFar + 1, DecreaseAction}); + return result; +} + +LegalizerInfo::SizeAndActionsVec +LegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest( + const SizeAndActionsVec &v, LegalizeAction DecreaseAction, + LegalizeAction IncreaseAction) { + SizeAndActionsVec result; + if (v.size() == 0 || v[0].first != 1) + result.push_back({1, IncreaseAction}); + for (size_t i = 0; i < v.size(); ++i) { + result.push_back(v[i]); + if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) { + result.push_back({v[i].first + 1, DecreaseAction}); + } + } + return result; +} + +LegalizerInfo::SizeAndAction +LegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) { + assert(Size >= 1); + // Find the last element in Vec that has a bitsize equal to or smaller than + // the requested bit size. + // That is the element just before the first element that is bigger than Size. + auto VecIt = std::upper_bound( + Vec.begin(), Vec.end(), Size, + [](const uint32_t Size, const SizeAndAction lhs) -> bool { + return Size < lhs.first; + }); + assert(VecIt != Vec.begin() && "Does Vec not start with size 1?"); + --VecIt; + int VecIdx = VecIt - Vec.begin(); + + LegalizeAction Action = Vec[VecIdx].second; + switch (Action) { case Legal: case Lower: case Libcall: case Custom: - return Aspect.Type; + return {Size, Action}; + case FewerElements: + // FIXME: is this special case still needed and correct? + // Special case for scalarization: + if (Vec == SizeAndActionsVec({{1, FewerElements}})) + return {1, FewerElements}; + LLVM_FALLTHROUGH; case NarrowScalar: { - return findLegalizableSize( - Aspect, [&](LLT Ty) -> LLT { return Ty.halfScalarSize(); }); - } - case WidenScalar: { - return findLegalizableSize(Aspect, [&](LLT Ty) -> LLT { - return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize(); - }); - } - case FewerElements: { - return findLegalizableSize( - Aspect, [&](LLT Ty) -> LLT { return Ty.halfElements(); }); + // The following needs to be a loop, as for now, we do allow needing to + // go over "Unsupported" bit sizes before finding a legalizable bit size. + // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8, + // we need to iterate over s9, and then to s32 to return (s32, Legal). + // If we want to get rid of the below loop, we should have stronger asserts + // when building the SizeAndActionsVecs, probably not allowing + // "Unsupported" unless at the ends of the vector. + for (int i = VecIdx - 1; i >= 0; --i) + if (!needsLegalizingToDifferentSize(Vec[i].second) && + Vec[i].second != Unsupported) + return {Vec[i].first, Action}; + llvm_unreachable(""); } + case WidenScalar: case MoreElements: { - return findLegalizableSize( - Aspect, [&](LLT Ty) -> LLT { return Ty.doubleElements(); }); + // See above, the following needs to be a loop, at least for now. + for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i) + if (!needsLegalizingToDifferentSize(Vec[i].second) && + Vec[i].second != Unsupported) + return {Vec[i].first, Action}; + llvm_unreachable(""); } + case Unsupported: + return {Size, Unsupported}; + case NotFound: + llvm_unreachable("NotFound"); } + llvm_unreachable("Action has an unknown enum value"); } -bool LegalizerInfo::legalizeCustom(MachineInstr &MI, - MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const { - return false; +std::pair<LegalizerInfo::LegalizeAction, LLT> +LegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const { + assert(Aspect.Type.isScalar() || Aspect.Type.isPointer()); + if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) + return {NotFound, LLT()}; + const unsigned OpcodeIdx = Aspect.Opcode - FirstOp; + if (Aspect.Type.isPointer() && + AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) == + AddrSpace2PointerActions[OpcodeIdx].end()) { + return {NotFound, LLT()}; + } + const SmallVector<SizeAndActionsVec, 1> &Actions = + Aspect.Type.isPointer() + ? AddrSpace2PointerActions[OpcodeIdx] + .find(Aspect.Type.getAddressSpace()) + ->second + : ScalarActions[OpcodeIdx]; + if (Aspect.Idx >= Actions.size()) + return {NotFound, LLT()}; + const SizeAndActionsVec &Vec = Actions[Aspect.Idx]; + // FIXME: speed up this search, e.g. by using a results cache for repeated + // queries? + auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits()); + return {SizeAndAction.second, + Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first) + : LLT::pointer(Aspect.Type.getAddressSpace(), + SizeAndAction.first)}; +} + +std::pair<LegalizerInfo::LegalizeAction, LLT> +LegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const { + assert(Aspect.Type.isVector()); + // First legalize the vector element size, then legalize the number of + // lanes in the vector. + if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) + return {NotFound, Aspect.Type}; + const unsigned OpcodeIdx = Aspect.Opcode - FirstOp; + const unsigned TypeIdx = Aspect.Idx; + if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size()) + return {NotFound, Aspect.Type}; + const SizeAndActionsVec &ElemSizeVec = + ScalarInVectorActions[OpcodeIdx][TypeIdx]; + + LLT IntermediateType; + auto ElementSizeAndAction = + findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits()); + IntermediateType = + LLT::vector(Aspect.Type.getNumElements(), ElementSizeAndAction.first); + if (ElementSizeAndAction.second != Legal) + return {ElementSizeAndAction.second, IntermediateType}; + + auto i = NumElements2Actions[OpcodeIdx].find( + IntermediateType.getScalarSizeInBits()); + if (i == NumElements2Actions[OpcodeIdx].end()) { + return {NotFound, IntermediateType}; + } + const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx]; + auto NumElementsAndAction = + findAction(NumElementsVec, IntermediateType.getNumElements()); + return {NumElementsAndAction.second, + LLT::vector(NumElementsAndAction.first, + IntermediateType.getScalarSizeInBits())}; } diff --git a/lib/CodeGen/GlobalISel/Localizer.cpp b/lib/CodeGen/GlobalISel/Localizer.cpp index c5d0999fe438..8e16470b6f90 100644 --- a/lib/CodeGen/GlobalISel/Localizer.cpp +++ b/lib/CodeGen/GlobalISel/Localizer.cpp @@ -101,7 +101,8 @@ bool Localizer::runOnMachineFunction(MachineFunction &MF) { // Don't try to be smart for the insertion point. // There is no guarantee that the first seen use is the first // use in the block. - InsertMBB->insert(InsertMBB->getFirstNonPHI(), LocalizedMI); + InsertMBB->insert(InsertMBB->SkipPHIsAndLabels(InsertMBB->begin()), + LocalizedMI); // Set a new register for the definition. unsigned NewReg = @@ -112,7 +113,7 @@ bool Localizer::runOnMachineFunction(MachineFunction &MF) { MBBWithLocalDef.insert(std::make_pair(MBBAndReg, NewReg)).first; DEBUG(dbgs() << "Inserted: " << *LocalizedMI); } - DEBUG(dbgs() << "Update use with: " << PrintReg(NewVRegIt->second) + DEBUG(dbgs() << "Update use with: " << printReg(NewVRegIt->second) << '\n'); // Update the user reg. MOUse.setReg(NewVRegIt->second); diff --git a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 4636806c3f08..475bb82e5b9c 100644 --- a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -15,10 +15,10 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetOpcodes.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DebugInfo.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetOpcodes.h" -#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; @@ -83,30 +83,26 @@ MachineInstrBuilder MachineIRBuilder::insertInstr(MachineInstrBuilder MIB) { return MIB; } -MachineInstrBuilder MachineIRBuilder::buildDirectDbgValue( - unsigned Reg, const MDNode *Variable, const MDNode *Expr) { +MachineInstrBuilder +MachineIRBuilder::buildDirectDbgValue(unsigned Reg, const MDNode *Variable, + const MDNode *Expr) { assert(isa<DILocalVariable>(Variable) && "not a variable"); assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && "Expected inlined-at fields to agree"); - return buildInstr(TargetOpcode::DBG_VALUE) - .addReg(Reg, RegState::Debug) - .addReg(0, RegState::Debug) - .addMetadata(Variable) - .addMetadata(Expr); + return insertInstr(BuildMI(getMF(), DL, getTII().get(TargetOpcode::DBG_VALUE), + /*IsIndirect*/ false, Reg, Variable, Expr)); } -MachineInstrBuilder MachineIRBuilder::buildIndirectDbgValue( - unsigned Reg, unsigned Offset, const MDNode *Variable, const MDNode *Expr) { +MachineInstrBuilder +MachineIRBuilder::buildIndirectDbgValue(unsigned Reg, const MDNode *Variable, + const MDNode *Expr) { assert(isa<DILocalVariable>(Variable) && "not a variable"); assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && "Expected inlined-at fields to agree"); - return buildInstr(TargetOpcode::DBG_VALUE) - .addReg(Reg, RegState::Debug) - .addImm(Offset) - .addMetadata(Variable) - .addMetadata(Expr); + return insertInstr(BuildMI(getMF(), DL, getTII().get(TargetOpcode::DBG_VALUE), + /*IsIndirect*/ true, Reg, Variable, Expr)); } MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI, @@ -124,7 +120,6 @@ MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI, } MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C, - unsigned Offset, const MDNode *Variable, const MDNode *Expr) { assert(isa<DILocalVariable>(Variable) && "not a variable"); @@ -144,7 +139,7 @@ MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C, MIB.addReg(0U); } - return MIB.addImm(Offset).addMetadata(Variable).addMetadata(Expr); + return MIB.addImm(0).addMetadata(Variable).addMetadata(Expr); } MachineInstrBuilder MachineIRBuilder::buildFrameIndex(unsigned Res, int Idx) { @@ -268,7 +263,7 @@ MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, const ConstantInt *NewVal = &Val; if (Ty.getSizeInBits() != Val.getBitWidth()) - NewVal = ConstantInt::get(MF->getFunction()->getContext(), + NewVal = ConstantInt::get(MF->getFunction().getContext(), Val.getValue().sextOrTrunc(Ty.getSizeInBits())); return buildInstr(TargetOpcode::G_CONSTANT).addDef(Res).addCImm(NewVal); @@ -276,7 +271,7 @@ MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, int64_t Val) { - auto IntN = IntegerType::get(MF->getFunction()->getContext(), + auto IntN = IntegerType::get(MF->getFunction().getContext(), MRI->getType(Res).getSizeInBits()); ConstantInt *CI = ConstantInt::get(IntN, Val, true); return buildConstant(Res, *CI); @@ -351,14 +346,17 @@ MachineInstrBuilder MachineIRBuilder::buildZExt(unsigned Res, unsigned Op) { return buildInstr(TargetOpcode::G_ZEXT).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res, - unsigned Op) { +MachineInstrBuilder +MachineIRBuilder::buildExtOrTrunc(unsigned ExtOpc, unsigned Res, unsigned Op) { + assert((TargetOpcode::G_ANYEXT == ExtOpc || TargetOpcode::G_ZEXT == ExtOpc || + TargetOpcode::G_SEXT == ExtOpc) && + "Expecting Extending Opc"); assert(MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()); assert(MRI->getType(Res).isScalar() == MRI->getType(Op).isScalar()); unsigned Opcode = TargetOpcode::COPY; if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits()) - Opcode = TargetOpcode::G_SEXT; + Opcode = ExtOpc; else if (MRI->getType(Res).getSizeInBits() < MRI->getType(Op).getSizeInBits()) Opcode = TargetOpcode::G_TRUNC; else @@ -367,20 +365,19 @@ MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res, return buildInstr(Opcode).addDef(Res).addUse(Op); } -MachineInstrBuilder MachineIRBuilder::buildZExtOrTrunc(unsigned Res, +MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res, unsigned Op) { - assert(MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()); - assert(MRI->getType(Res).isScalar() == MRI->getType(Op).isScalar()); + return buildExtOrTrunc(TargetOpcode::G_SEXT, Res, Op); +} - unsigned Opcode = TargetOpcode::COPY; - if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits()) - Opcode = TargetOpcode::G_ZEXT; - else if (MRI->getType(Res).getSizeInBits() < MRI->getType(Op).getSizeInBits()) - Opcode = TargetOpcode::G_TRUNC; - else - assert(MRI->getType(Res) == MRI->getType(Op)); +MachineInstrBuilder MachineIRBuilder::buildZExtOrTrunc(unsigned Res, + unsigned Op) { + return buildExtOrTrunc(TargetOpcode::G_ZEXT, Res, Op); +} - return buildInstr(Opcode).addDef(Res).addUse(Op); +MachineInstrBuilder MachineIRBuilder::buildAnyExtOrTrunc(unsigned Res, + unsigned Op) { + return buildExtOrTrunc(TargetOpcode::G_ANYEXT, Res, Op); } MachineInstrBuilder MachineIRBuilder::buildCast(unsigned Dst, unsigned Src) { @@ -661,6 +658,31 @@ MachineInstrBuilder MachineIRBuilder::buildExtractVectorElement(unsigned Res, .addUse(Idx); } +MachineInstrBuilder +MachineIRBuilder::buildAtomicCmpXchg(unsigned OldValRes, unsigned Addr, + unsigned CmpVal, unsigned NewVal, + MachineMemOperand &MMO) { +#ifndef NDEBUG + LLT OldValResTy = MRI->getType(OldValRes); + LLT AddrTy = MRI->getType(Addr); + LLT CmpValTy = MRI->getType(CmpVal); + LLT NewValTy = MRI->getType(NewVal); + assert(OldValResTy.isScalar() && "invalid operand type"); + assert(AddrTy.isPointer() && "invalid operand type"); + assert(CmpValTy.isValid() && "invalid operand type"); + assert(NewValTy.isValid() && "invalid operand type"); + assert(OldValResTy == CmpValTy && "type mismatch"); + assert(OldValResTy == NewValTy && "type mismatch"); +#endif + + return buildInstr(TargetOpcode::G_ATOMIC_CMPXCHG) + .addDef(OldValRes) + .addUse(Addr) + .addUse(CmpVal) + .addUse(NewVal) + .addMemOperand(&MMO); +} + void MachineIRBuilder::validateTruncExt(unsigned Dst, unsigned Src, bool IsExtend) { #ifndef NDEBUG diff --git a/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/lib/CodeGen/GlobalISel/RegBankSelect.cpp index 677941dbbf6d..006c9ea23034 100644 --- a/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ b/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -26,9 +26,12 @@ #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetPassConfig.h" -#include "llvm/IR/Function.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/CommandLine.h" @@ -36,9 +39,6 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetOpcodes.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetSubtargetInfo.h" #include <algorithm> #include <cassert> #include <cstdint> @@ -159,7 +159,7 @@ bool RegBankSelect::repairReg( // same types because the type is a placeholder when this function is called. MachineInstr *MI = MIRBuilder.buildInstrNoInsert(TargetOpcode::COPY).addDef(Dst).addUse(Src); - DEBUG(dbgs() << "Copy: " << PrintReg(Src) << " to: " << PrintReg(Dst) + DEBUG(dbgs() << "Copy: " << printReg(Src) << " to: " << printReg(Dst) << '\n'); // TODO: // Check if MI is legal. if not, we need to legalize all the @@ -221,9 +221,8 @@ uint64_t RegBankSelect::getRepairCost( // into a new virtual register. // We would also need to propagate this information in the // repairing placement. - unsigned Cost = - RBI->copyCost(*DesiredRegBrank, *CurRegBank, - RegisterBankInfo::getSizeInBits(MO.getReg(), *MRI, *TRI)); + unsigned Cost = RBI->copyCost(*DesiredRegBrank, *CurRegBank, + RBI->getSizeInBits(MO.getReg(), *MRI, *TRI)); // TODO: use a dedicated constant for ImpossibleCost. if (Cost != std::numeric_limits<unsigned>::max()) return Cost; @@ -602,9 +601,9 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { return false; DEBUG(dbgs() << "Assign register banks for: " << MF.getName() << '\n'); - const Function *F = MF.getFunction(); + const Function &F = MF.getFunction(); Mode SaveOptMode = OptMode; - if (F->hasFnAttribute(Attribute::OptimizeNone)) + if (F.hasFnAttribute(Attribute::OptimizeNone)) OptMode = Mode::Fast; init(MF); diff --git a/lib/CodeGen/GlobalISel/RegisterBank.cpp b/lib/CodeGen/GlobalISel/RegisterBank.cpp index 83b21e637097..4d3ae69d3a9d 100644 --- a/lib/CodeGen/GlobalISel/RegisterBank.cpp +++ b/lib/CodeGen/GlobalISel/RegisterBank.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GlobalISel/RegisterBank.h" -#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" #define DEBUG_TYPE "registerbank" diff --git a/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp b/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp index a841902feed1..b3d9209ae6eb 100644 --- a/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp +++ b/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp @@ -19,13 +19,12 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetOpcodes.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Type.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetOpcodes.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetSubtargetInfo.h" #include <algorithm> // For std::max. @@ -84,7 +83,7 @@ const RegisterBank * RegisterBankInfo::getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const { if (TargetRegisterInfo::isPhysicalRegister(Reg)) - return &getRegBankFromRegClass(*TRI.getMinimalPhysRegClass(Reg)); + return &getRegBankFromRegClass(getMinimalPhysRegClass(Reg, TRI)); assert(Reg && "NoRegister does not have a register bank"); const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(Reg); @@ -95,6 +94,19 @@ RegisterBankInfo::getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, return nullptr; } +const TargetRegisterClass & +RegisterBankInfo::getMinimalPhysRegClass(unsigned Reg, + const TargetRegisterInfo &TRI) const { + assert(TargetRegisterInfo::isPhysicalRegister(Reg) && + "Reg must be a physreg"); + const auto &RegRCIt = PhysRegMinimalRCs.find(Reg); + if (RegRCIt != PhysRegMinimalRCs.end()) + return *RegRCIt->second; + const TargetRegisterClass *PhysRC = TRI.getMinimalPhysRegClass(Reg); + PhysRegMinimalRCs[Reg] = PhysRC; + return *PhysRC; +} + const RegisterBank *RegisterBankInfo::getRegBankFromConstraints( const MachineInstr &MI, unsigned OpIdx, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI) const { @@ -151,7 +163,7 @@ RegisterBankInfo::getInstrMappingImpl(const MachineInstr &MI) const { // is important. The rest is not constrained. unsigned NumOperandsForMapping = IsCopyLike ? 1 : MI.getNumOperands(); - const MachineFunction &MF = *MI.getParent()->getParent(); + const MachineFunction &MF = *MI.getMF(); const TargetSubtargetInfo &STI = MF.getSubtarget(); const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); const MachineRegisterInfo &MRI = MF.getRegInfo(); @@ -419,16 +431,20 @@ void RegisterBankInfo::applyDefaultMapping(const OperandsMapper &OpdMapper) { } unsigned OrigReg = MO.getReg(); unsigned NewReg = *NewRegs.begin(); - DEBUG(dbgs() << " changed, replace " << PrintReg(OrigReg, nullptr)); + DEBUG(dbgs() << " changed, replace " << printReg(OrigReg, nullptr)); MO.setReg(NewReg); - DEBUG(dbgs() << " with " << PrintReg(NewReg, nullptr)); + DEBUG(dbgs() << " with " << printReg(NewReg, nullptr)); // The OperandsMapper creates plain scalar, we may have to fix that. // Check if the types match and if not, fix that. LLT OrigTy = MRI.getType(OrigReg); LLT NewTy = MRI.getType(NewReg); if (OrigTy != NewTy) { - assert(OrigTy.getSizeInBits() == NewTy.getSizeInBits() && + // The default mapping is not supposed to change the size of + // the storage. However, right now we don't necessarily bump all + // the types to storage size. For instance, we can consider + // s16 G_AND legal whereas the storage size is going to be 32. + assert(OrigTy.getSizeInBits() <= NewTy.getSizeInBits() && "Types with difference size cannot be handled by the default " "mapping"); DEBUG(dbgs() << "\nChange type of new opd from " << NewTy << " to " @@ -441,13 +457,13 @@ void RegisterBankInfo::applyDefaultMapping(const OperandsMapper &OpdMapper) { unsigned RegisterBankInfo::getSizeInBits(unsigned Reg, const MachineRegisterInfo &MRI, - const TargetRegisterInfo &TRI) { + const TargetRegisterInfo &TRI) const { const TargetRegisterClass *RC = nullptr; if (TargetRegisterInfo::isPhysicalRegister(Reg)) { // The size is not directly available for physical registers. // Instead, we need to access a register class that contains Reg and // get the size of that register class. - RC = TRI.getMinimalPhysRegClass(Reg); + RC = &getMinimalPhysRegClass(Reg, TRI); } else { LLT Ty = MRI.getType(Reg); unsigned RegSize = Ty.isValid() ? Ty.getSizeInBits() : 0; @@ -543,10 +559,11 @@ bool RegisterBankInfo::InstructionMapping::verify( // For PHI, we only care about mapping the definition. assert(NumOperands == (isCopyLike(MI) ? 1 : MI.getNumOperands()) && "NumOperands must match, see constructor"); - assert(MI.getParent() && MI.getParent()->getParent() && + assert(MI.getParent() && MI.getMF() && "MI must be connected to a MachineFunction"); - const MachineFunction &MF = *MI.getParent()->getParent(); - (void)MF; + const MachineFunction &MF = *MI.getMF(); + const RegisterBankInfo *RBI = MF.getSubtarget().getRegBankInfo(); + (void)RBI; for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { const MachineOperand &MO = MI.getOperand(Idx); @@ -564,7 +581,7 @@ bool RegisterBankInfo::InstructionMapping::verify( (void)MOMapping; // Register size in bits. // This size must match what the mapping expects. - assert(MOMapping.verify(getSizeInBits( + assert(MOMapping.verify(RBI->getSizeInBits( Reg, MF.getRegInfo(), *MF.getSubtarget().getRegisterInfo())) && "Value mapping is invalid"); } @@ -725,8 +742,8 @@ void RegisterBankInfo::OperandsMapper::print(raw_ostream &OS, // If we have a function, we can pretty print the name of the registers. // Otherwise we will print the raw numbers. const TargetRegisterInfo *TRI = - getMI().getParent() && getMI().getParent()->getParent() - ? getMI().getParent()->getParent()->getSubtarget().getRegisterInfo() + getMI().getParent() && getMI().getMF() + ? getMI().getMF()->getSubtarget().getRegisterInfo() : nullptr; bool IsFirst = true; for (unsigned Idx = 0; Idx != NumOpds; ++Idx) { @@ -735,13 +752,13 @@ void RegisterBankInfo::OperandsMapper::print(raw_ostream &OS, if (!IsFirst) OS << ", "; IsFirst = false; - OS << '(' << PrintReg(getMI().getOperand(Idx).getReg(), TRI) << ", ["; + OS << '(' << printReg(getMI().getOperand(Idx).getReg(), TRI) << ", ["; bool IsFirstNewVReg = true; for (unsigned VReg : getVRegs(Idx)) { if (!IsFirstNewVReg) OS << ", "; IsFirstNewVReg = false; - OS << PrintReg(VReg, TRI); + OS << printReg(VReg, TRI); } OS << "])"; } diff --git a/lib/CodeGen/GlobalISel/Utils.cpp b/lib/CodeGen/GlobalISel/Utils.cpp index 5ecaf5c563f8..ef990b49aceb 100644 --- a/lib/CodeGen/GlobalISel/Utils.cpp +++ b/lib/CodeGen/GlobalISel/Utils.cpp @@ -17,10 +17,10 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/IR/Constants.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetRegisterInfo.h" #define DEBUG_TYPE "globalisel-utils" @@ -99,7 +99,10 @@ void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC, const MachineInstr &MI) { MachineOptimizationRemarkMissed R(PassName, "GISelFailure: ", MI.getDebugLoc(), MI.getParent()); - R << Msg << ": " << ore::MNV("Inst", MI); + R << Msg; + // Printing MI is expensive; only do it if expensive remarks are enabled. + if (MORE.allowExtraAnalysis(PassName)) + R << ": " << ore::MNV("Inst", MI); reportGISelFailure(MF, TPC, MORE, R); } @@ -126,3 +129,19 @@ const llvm::ConstantFP* llvm::getConstantFPVRegVal(unsigned VReg, return nullptr; return MI->getOperand(1).getFPImm(); } + +llvm::MachineInstr *llvm::getOpcodeDef(unsigned Opcode, unsigned Reg, + const MachineRegisterInfo &MRI) { + auto *DefMI = MRI.getVRegDef(Reg); + auto DstTy = MRI.getType(DefMI->getOperand(0).getReg()); + if (!DstTy.isValid()) + return nullptr; + while (DefMI->getOpcode() == TargetOpcode::COPY) { + unsigned SrcReg = DefMI->getOperand(1).getReg(); + auto SrcTy = MRI.getType(SrcReg); + if (!SrcTy.isValid() || SrcTy != DstTy) + break; + DefMI = MRI.getVRegDef(SrcReg); + } + return DefMI->getOpcode() == Opcode ? DefMI : nullptr; +} |
