diff options
Diffstat (limited to 'llvm')
25 files changed, 554 insertions, 16 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GISelAccessor.h b/llvm/include/llvm/CodeGen/GlobalISel/GISelAccessor.h index 7c5ec9f3adc..8465bce2a06 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GISelAccessor.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GISelAccessor.h @@ -17,6 +17,7 @@ namespace llvm { class CallLowering; +class MachineLegalizer; class RegisterBankInfo; /// The goal of this helper class is to gather the accessor to all @@ -27,6 +28,9 @@ class RegisterBankInfo; struct GISelAccessor { virtual ~GISelAccessor() {} virtual const CallLowering *getCallLowering() const { return nullptr;} + virtual const MachineLegalizer *getMachineLegalizer() const { + return nullptr; + } virtual const RegisterBankInfo *getRegBankInfo() const { return nullptr;} }; } // End namespace llvm; diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 6728f4f3fea..55eafb372f9 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -80,7 +80,7 @@ public: /// Set the insertion point to before (\p Before = true) or after /// (\p Before = false) \p MI. /// \pre MI must be in getMF(). - void setInstr(MachineInstr &MI, bool Before = false); + void setInstr(MachineInstr &MI, bool Before = true); /// @} /// Set the debug location to \p DL for all the next build instructions. @@ -152,6 +152,37 @@ public: /// \return The newly created instruction. MachineInstr *buildFrameIndex(LLT Ty, unsigned Res, int Idx); + /// Build and insert \p Res<def> = G_ADD \p Ty \p Op0, \p Op1 + /// + /// G_ADD sets \p Res to the sum of integer parameters \p Op0 and \p Op1, + /// truncated to their width. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return The newly created instruction. + MachineInstr *buildAdd(LLT Ty, unsigned Res, unsigned Op0, unsigned Op1); + + /// Build and insert `Res0<def>, ... = G_EXTRACT Ty Src, Idx0, ...`. + /// + /// If \p Ty has size N bits, G_EXTRACT sets \p Res[0] to bits `[Idxs[0], + /// Idxs[0] + N)` of \p Src and similarly for subsequent bit-indexes. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return The newly created instruction. + MachineInstr *buildExtract(LLT Ty, ArrayRef<unsigned> Results, unsigned Src, + ArrayRef<unsigned> Indexes); + + /// Build and insert \p Res<def> = G_SEQUENCE \p Ty \p Ops[0], ... + /// + /// G_SEQUENCE concatenates each element in Ops into a single register, where + /// Ops[0] starts at bit 0 of \p Res. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre The sum of the input sizes must equal the result's size. + /// + /// \return The newly created instruction. + MachineInstr *buildSequence(LLT Ty, unsigned Res, ArrayRef<unsigned> Ops); }; } // End namespace llvm. diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h new file mode 100644 index 00000000000..7252fedac9e --- /dev/null +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h @@ -0,0 +1,92 @@ +//== llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h ----------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file A pass to convert the target-illegal operations created by IR -> MIR +/// translation into ones the target expects to be able to select. This may +/// occur in multiple phases, for example G_ADD <2 x i8> -> G_ADD <2 x i16> -> +/// G_ADD <4 x i16>. +/// +/// The MachineLegalizeHelper class is where most of the work happens, and is +/// designed to be callable from other passes that find themselves with an +/// illegal instruction. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZEHELPER_H +#define LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZEHELPER_H + +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/LowLevelType.h" + +namespace llvm { +// Forward declarations. +class MachineLegalizeInfo; +class MachineLegalizer; +class MachineRegisterInfo; + +class MachineLegalizeHelper { +public: + enum LegalizeResult { + /// Instruction was already legal and no change was made to the + /// MachineFunction. + AlreadyLegal, + + /// Instruction has been legalized and the MachineFunction changed. + Legalized, + + /// Some kind of error has occurred and we could not legalize this + /// instruction. + UnableToLegalize, + }; + + MachineLegalizeHelper(MachineFunction &MF); + + /// Replace \p MI by a sequence of legal instructions that can implement the + /// same operation. Note that this means \p MI may be deleted, so any iterator + /// steps should be performed before calling this function. \p Helper should + /// be initialized to the MachineFunction containing \p MI. + /// + /// Considered as an opaque blob, the legal code will use and define the same + /// registers as \p MI. + LegalizeResult legalizeInstr(MachineInstr &MI, + const MachineLegalizer &Legalizer); + + /// Legalize an instruction by reducing the width of the underlying scalar + /// type. + LegalizeResult narrowScalar(MachineInstr &MI, LLT NarrowTy); + + /// Legalize an instruction by performing the operation on a wider scalar type + /// (for example a 16-bit addition can be safely performed at 32-bits + /// precision, ignoring the unused bits). + LegalizeResult widenScalar(MachineInstr &MI, LLT WideTy); + + /// Legalize a vector instruction by splitting into multiple components, each + /// acting on the same scalar type as the original but with fewer elements. + LegalizeResult fewerElementsVector(MachineInstr &MI, LLT NarrowTy); + + /// Legalize a vector instruction by increasing the number of vector elements + /// involved and ignoring the added elements later. + LegalizeResult moreElementsVector(MachineInstr &MI, LLT WideTy); + +private: + + /// Helper function to split a wide generic register into bitwise blocks with + /// the given Type (which implies the number of blocks needed). The generic + /// registers created are appended to Ops, starting at bit 0 of Reg. + void extractParts(unsigned Reg, LLT Ty, int NumParts, + SmallVectorImpl<unsigned> &Ops); + + MachineIRBuilder MIRBuilder; + MachineRegisterInfo &MRI; +}; + +} // End namespace llvm. + +#endif diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizePass.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizePass.h new file mode 100644 index 00000000000..e1cc32aa793 --- /dev/null +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizePass.h @@ -0,0 +1,50 @@ +//== llvm/CodeGen/GlobalISel/MachineLegalizePass.h ------------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file A pass to convert the target-illegal operations created by IR -> MIR +/// translation into ones the target expects to be able to select. This may +/// occur in multiple phases, for example G_ADD <2 x i8> -> G_ADD <2 x i16> -> +/// G_ADD <4 x i16>. +/// +/// The LegalizeHelper class is where most of the work happens, and is designed +/// to be callable from other passes that find themselves with an illegal +/// instruction. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZEMACHINEIRPASS_H +#define LLVM_CODEGEN_GLOBALISEL_LEGALIZEMACHINEIRPASS_H + +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { + +class MachineLegalizePass : public MachineFunctionPass { +public: + static char ID; + +private: + + /// Initialize the field members using \p MF. + void init(MachineFunction &MF); + +public: + // Ctor, nothing fancy. + MachineLegalizePass(); + + const char *getPassName() const override { + return "MachineLegalizePass"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // End namespace llvm. + +#endif diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h index 96ddadfc993..1ba1a75f32f 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h @@ -71,17 +71,6 @@ public: MachineLegalizer(); - /// Replace \p MI by a sequence of legal instructions that can implement the - /// same operation. Note that this means \p MI may be deleted, so any iterator - /// steps should be performed before calling this function. - /// - /// Considered as an opaque blob, the legal code will use and define the same - /// registers as \p MI. - /// - /// \returns true if the function is modified, false if the instruction was - /// already legal. - bool legalizeInstr(MachineInstr &MI) const; - /// Compute any ancillary tables needed to quickly decide how an operation /// should be handled. This must be called after all "set*Action"methods but /// before any query is made or incorrect results may be returned. diff --git a/llvm/include/llvm/CodeGen/TargetPassConfig.h b/llvm/include/llvm/CodeGen/TargetPassConfig.h index 9309655a972..656433dd987 100644 --- a/llvm/include/llvm/CodeGen/TargetPassConfig.h +++ b/llvm/include/llvm/CodeGen/TargetPassConfig.h @@ -218,6 +218,14 @@ public: virtual bool addIRTranslator() { return true; } /// This method may be implemented by targets that want to run passes + /// immediately before legalization. + virtual void addPreLegalizeMachineIR() {} + + /// This method should install a legalize pass, which converts the instruction + /// sequence into one that can be selected by the target. + virtual bool addLegalizeMachineIR() { return true; } + + /// This method may be implemented by targets that want to run passes /// immediately before the register bank selection. virtual void addPreRegBankSelect() {} diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index 1c0610dcf30..12a5f43ab92 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -214,6 +214,7 @@ void initializeMachineCopyPropagationPass(PassRegistry&); void initializeMachineDominanceFrontierPass(PassRegistry&); void initializeMachineDominatorTreePass(PassRegistry&); void initializeMachineFunctionPrinterPassPass(PassRegistry&); +void initializeMachineLegalizePassPass(PassRegistry&); void initializeMachineLICMPass(PassRegistry&); void initializeMachineLoopInfoPass(PassRegistry&); void initializeMachineModuleInfoPass(PassRegistry&); diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 97036350171..4c297322aa7 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -58,6 +58,27 @@ def G_OR : Instruction { } //------------------------------------------------------------------------------ +// Variadic ops +//------------------------------------------------------------------------------ + +// Extract multiple registers specified size, starting from blocks given by +// indexes. This will almost certainly be mapped to sub-register COPYs after +// register banks have been selected. +def G_EXTRACT : Instruction { + let OutOperandList = (outs variable_ops); + let InOperandList = (ins variable_ops); + let hasSideEffects = 0; +} + +// Combine a sequence of generic vregs into a single larger value (starting at +// bit 0). +def G_SEQUENCE : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins variable_ops); + let hasSideEffects = 0; +} + +//------------------------------------------------------------------------------ // Branches. //------------------------------------------------------------------------------ // Generic unconditional branch. diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def index cfb0649191a..297ff82ccfd 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.def +++ b/llvm/include/llvm/Target/TargetOpcodes.def @@ -172,6 +172,14 @@ HANDLE_TARGET_OPCODE(G_OR) /// stack-based object. HANDLE_TARGET_OPCODE(G_FRAME_INDEX) +/// Generic instruction to extract blocks of bits from the register given +/// (typically a sub-register COPY after instruction selection). +HANDLE_TARGET_OPCODE(G_EXTRACT) + +/// Generic instruction to paste a variable number of components together into a +/// larger register. +HANDLE_TARGET_OPCODE(G_SEQUENCE) + /// Generic BRANCH instruction. This is an unconditional branch. HANDLE_TARGET_OPCODE(G_BR) diff --git a/llvm/include/llvm/Target/TargetSubtargetInfo.h b/llvm/include/llvm/Target/TargetSubtargetInfo.h index b929070484f..750427debde 100644 --- a/llvm/include/llvm/Target/TargetSubtargetInfo.h +++ b/llvm/include/llvm/Target/TargetSubtargetInfo.h @@ -27,6 +27,7 @@ class CallLowering; class DataLayout; class MachineFunction; class MachineInstr; +class MachineLegalizer; class RegisterBankInfo; class SDep; class SUnit; @@ -94,6 +95,10 @@ public: return nullptr; } + virtual const MachineLegalizer *getMachineLegalizer() const { + return nullptr; + } + /// getRegisterInfo - If register information is available, return it. If /// not, return null. /// diff --git a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt index 960f51a842d..0d18ef63b8f 100644 --- a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt +++ b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt @@ -2,6 +2,8 @@ set(GLOBAL_ISEL_FILES IRTranslator.cpp MachineIRBuilder.cpp + MachineLegalizeHelper.cpp + MachineLegalizePass.cpp MachineLegalizer.cpp RegBankSelect.cpp RegisterBank.cpp diff --git a/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp b/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp index 231e5ac82be..c0ea873bcfe 100644 --- a/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp @@ -25,6 +25,7 @@ void llvm::initializeGlobalISel(PassRegistry &Registry) { void llvm::initializeGlobalISel(PassRegistry &Registry) { initializeIRTranslatorPass(Registry); + initializeMachineLegalizePassPass(Registry); initializeRegBankSelectPass(Registry); } #endif // LLVM_BUILD_GLOBAL_ISEL diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 220965ce660..2b91584c75d 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -110,3 +110,35 @@ MachineInstr *MachineIRBuilder::buildFrameIndex(LLT Ty, unsigned Res, int Idx) { MIB.addImm(Idx); return NewMI; } + +MachineInstr *MachineIRBuilder::buildAdd(LLT Ty, unsigned Res, unsigned Op0, + unsigned Op1) { + return buildInstr(TargetOpcode::G_ADD, Ty, Res, Op0, Op1); +} + +MachineInstr *MachineIRBuilder::buildExtract(LLT Ty, ArrayRef<unsigned> Results, + unsigned Src, + ArrayRef<unsigned> Indexes) { + assert(Results.size() == Indexes.size() && "inconsistent number of regs"); + + MachineInstr *NewMI = buildInstr(TargetOpcode::G_EXTRACT, Ty); + auto MIB = MachineInstrBuilder(getMF(), NewMI); + for (auto Res : Results) + MIB.addReg(Res, RegState::Define); + + MIB.addReg(Src); + + for (auto Idx : Indexes) + MIB.addImm(Idx); + return NewMI; +} + +MachineInstr *MachineIRBuilder::buildSequence(LLT Ty, unsigned Res, + ArrayRef<unsigned> Ops) { + MachineInstr *NewMI = buildInstr(TargetOpcode::G_SEQUENCE, Ty); + auto MIB = MachineInstrBuilder(getMF(), NewMI); + MIB.addReg(Res, RegState::Define); + for (auto Op : Ops) + MIB.addReg(Op); + return NewMI; +} diff --git a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp new file mode 100644 index 00000000000..55adbbd20ce --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp @@ -0,0 +1,98 @@ +//===-- llvm/CodeGen/GlobalISel/MachineLegalizeHelper.cpp -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file implements the MachineLegalizeHelper class to legalize +/// individual instructions and the LegalizeMachineIR wrapper pass for the +/// primary legalization. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h" +#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#include <sstream> + +#define DEBUG_TYPE "legalize-mir" + +using namespace llvm; + +MachineLegalizeHelper::MachineLegalizeHelper(MachineFunction &MF) + : MRI(MF.getRegInfo()) { + MIRBuilder.setMF(MF); +} + +MachineLegalizeHelper::LegalizeResult MachineLegalizeHelper::legalizeInstr( + MachineInstr &MI, const MachineLegalizer &Legalizer) { + auto Action = Legalizer.getAction(MI); + switch (Action.first) { + case MachineLegalizer::Legal: + return AlreadyLegal; + case MachineLegalizer::NarrowScalar: + return narrowScalar(MI, Action.second); + case MachineLegalizer::WidenScalar: + return widenScalar(MI, Action.second); + case MachineLegalizer::FewerElements: + return fewerElementsVector(MI, Action.second); + default: + return UnableToLegalize; + } +} + +void MachineLegalizeHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, + SmallVectorImpl<unsigned> &VRegs) { + unsigned Size = Ty.getSizeInBits(); + SmallVector<unsigned, 4> Indexes; + for (int i = 0; i < NumParts; ++i) { + VRegs.push_back(MRI.createGenericVirtualRegister(Size)); + Indexes.push_back(i * Size); + } + MIRBuilder.buildExtract(Ty, VRegs, Reg, Indexes); +} + +MachineLegalizeHelper::LegalizeResult +MachineLegalizeHelper::narrowScalar(MachineInstr &MI, LLT NarrowTy) { + return UnableToLegalize; +} + +MachineLegalizeHelper::LegalizeResult +MachineLegalizeHelper::widenScalar(MachineInstr &MI, LLT WideTy) { + return UnableToLegalize; +} + +MachineLegalizeHelper::LegalizeResult +MachineLegalizeHelper::fewerElementsVector(MachineInstr &MI, LLT NarrowTy) { + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_ADD: { + unsigned NarrowSize = NarrowTy.getSizeInBits(); + int NumParts = MI.getType().getSizeInBits() / NarrowSize; + + MIRBuilder.setInstr(MI); + + SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; + extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); + extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); + + for (int i = 0; i < NumParts; ++i) { + unsigned DstReg = MRI.createGenericVirtualRegister(NarrowSize); + MIRBuilder.buildAdd(NarrowTy, DstReg, Src1Regs[i], Src2Regs[i]); + DstRegs.push_back(DstReg); + } + + MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs); + MI.eraseFromParent(); + return Legalized; + } + } +} diff --git a/llvm/lib/CodeGen/GlobalISel/MachineLegalizePass.cpp b/llvm/lib/CodeGen/GlobalISel/MachineLegalizePass.cpp new file mode 100644 index 00000000000..4ddc82fc6b7 --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/MachineLegalizePass.cpp @@ -0,0 +1,72 @@ +//===-- llvm/CodeGen/GlobalISel/MachineLegalizePass.cpp -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file implements the LegalizeHelper class to legalize individual +/// instructions and the MachineLegalizePass wrapper pass for the primary +/// legalization. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/MachineLegalizePass.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h" +#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#define DEBUG_TYPE "legalize-mir" + +using namespace llvm; + +char MachineLegalizePass::ID = 0; +INITIALIZE_PASS(MachineLegalizePass, DEBUG_TYPE, + "Legalize the Machine IR a function's Machine IR", false, + false); + +MachineLegalizePass::MachineLegalizePass() : MachineFunctionPass(ID) { + initializeMachineLegalizePassPass(*PassRegistry::getPassRegistry()); +} + +void MachineLegalizePass::init(MachineFunction &MF) { +} + +bool MachineLegalizePass::runOnMachineFunction(MachineFunction &MF) { + DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n'); + init(MF); + const MachineLegalizer &Legalizer = *MF.getSubtarget().getMachineLegalizer(); + MachineLegalizeHelper 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); + auto Res = Helper.legalizeInstr(*MI, Legalizer); + + // Error out if we couldn't legalize this instruction. We may want to fall + // back to DAG ISel instead in the future. + if (Res == MachineLegalizeHelper::UnableToLegalize) { + std::string Msg; + raw_string_ostream OS(Msg); + OS << "unable to legalize instruction: "; + MI->print(OS); + report_fatal_error(OS.str()); + } + + Changed |= Res == MachineLegalizeHelper::Legalized; + } + return Changed; +} diff --git a/llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp b/llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp index edd5ccfd9cd..600f7bc5973 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp @@ -28,10 +28,6 @@ MachineLegalizer::MachineLegalizer() : TablesInitialized(false) { DefaultActions[TargetOpcode::G_ADD] = NarrowScalar; } -bool MachineLegalizer::legalizeInstr(MachineInstr &MI) const { - llvm_unreachable("Unimplemented functionality"); -} - void MachineLegalizer::computeTables() { for (auto &Op : Actions) { LLT Ty = Op.first.second; @@ -56,6 +52,11 @@ MachineLegalizer::getAction(unsigned Opcode, LLT Ty) const { // These *have* to be implemented for now, they're the fundamental basis of // how everything else is transformed. + // FIXME: the long-term plan calls for expansion in terms of load/store (if + // they're not legal). + if (Opcode == TargetOpcode::G_SEQUENCE || Opcode == TargetOpcode::G_EXTRACT) + return std::make_pair(Legal, Ty); + auto ActionIt = Actions.find(std::make_pair(Opcode, Ty)); if (ActionIt != Actions.end()) return findLegalAction(Opcode, Ty, ActionIt->second); diff --git a/llvm/lib/CodeGen/LLVMTargetMachine.cpp b/llvm/lib/CodeGen/LLVMTargetMachine.cpp index 9eb43d2bec1..b18a186c122 100644 --- a/llvm/lib/CodeGen/LLVMTargetMachine.cpp +++ b/llvm/lib/CodeGen/LLVMTargetMachine.cpp @@ -165,6 +165,11 @@ addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM, if (PassConfig->addIRTranslator()) return nullptr; + PassConfig->addPreLegalizeMachineIR(); + + if (PassConfig->addLegalizeMachineIR()) + return nullptr; + // Before running the register bank selector, ask the target if it // wants to run some passes. PassConfig->addPreRegBankSelect(); diff --git a/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp b/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp new file mode 100644 index 00000000000..40fda0b2243 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp @@ -0,0 +1,30 @@ +//===- AArch64MachineLegalizer.cpp -------------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the targeting of the Machinelegalizer class for +/// AArch64. +/// \todo This should be generated by TableGen. +//===----------------------------------------------------------------------===// + +#include "AArch64MachineLegalizer.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/Target/TargetOpcodes.h" + +using namespace llvm; + +#ifndef LLVM_BUILD_GLOBAL_ISEL +#error "You shouldn't build this" +#endif + +AArch64MachineLegalizer::AArch64MachineLegalizer() { + setAction(TargetOpcode::G_ADD, LLT::vector(2, 64), Legal); + computeTables(); +} diff --git a/llvm/lib/Target/AArch64/AArch64MachineLegalizer.h b/llvm/lib/Target/AArch64/AArch64MachineLegalizer.h new file mode 100644 index 00000000000..86708a558a3 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64MachineLegalizer.h @@ -0,0 +1,30 @@ +//===- AArch64Machinelegalizer --------------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares the targeting of the Machinelegalizer class for +/// AArch64. +/// \todo This should be generated by TableGen. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINELEGALIZER_H +#define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINELEGALIZER_H + +#include "llvm/CodeGen/GlobalISel/Machinelegalizer.h" + +namespace llvm { + +class LLVMContext; + +/// This class provides the information for the target register banks. +class AArch64MachineLegalizer : public MachineLegalizer { +public: + AArch64MachineLegalizer(); +}; +} // End llvm namespace. +#endif diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp index 7dd8ccbe6c2..9ec3b164243 100644 --- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -98,6 +98,11 @@ const CallLowering *AArch64Subtarget::getCallLowering() const { return GISel->getCallLowering(); } +const MachineLegalizer *AArch64Subtarget::getMachineLegalizer() const { + assert(GISel && "Access to GlobalISel APIs not set"); + return GISel->getMachineLegalizer(); +} + const RegisterBankInfo *AArch64Subtarget::getRegBankInfo() const { assert(GISel && "Access to GlobalISel APIs not set"); return GISel->getRegBankInfo(); diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h index 16a35405c89..7083be44bc5 100644 --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -147,6 +147,7 @@ public: return &getInstrInfo()->getRegisterInfo(); } const CallLowering *getCallLowering() const override; + const MachineLegalizer *getMachineLegalizer() const override; const RegisterBankInfo *getRegBankInfo() const override; const Triple &getTargetTriple() const { return TargetTriple; } bool enableMachineScheduler() const override { return true; } diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 145ff573d1b..605fb579d7b 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -12,11 +12,13 @@ #include "AArch64.h" #include "AArch64CallLowering.h" +#include "AArch64MachineLegalizer.h" #include "AArch64RegisterBankInfo.h" #include "AArch64TargetMachine.h" #include "AArch64TargetObjectFile.h" #include "AArch64TargetTransformInfo.h" #include "llvm/CodeGen/GlobalISel/IRTranslator.h" +#include "llvm/CodeGen/GlobalISel/MachineLegalizePass.h" #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/RegAllocRegistry.h" @@ -196,10 +198,14 @@ AArch64TargetMachine::~AArch64TargetMachine() {} namespace { struct AArch64GISelActualAccessor : public GISelAccessor { std::unique_ptr<CallLowering> CallLoweringInfo; + std::unique_ptr<MachineLegalizer> MachineLegalizer; std::unique_ptr<RegisterBankInfo> RegBankInfo; const CallLowering *getCallLowering() const override { return CallLoweringInfo.get(); } + const class MachineLegalizer *getMachineLegalizer() const override { + return MachineLegalizer.get(); + } const RegisterBankInfo *getRegBankInfo() const override { return RegBankInfo.get(); } @@ -234,6 +240,7 @@ AArch64TargetMachine::getSubtargetImpl(const Function &F) const { new AArch64GISelActualAccessor(); GISel->CallLoweringInfo.reset( new AArch64CallLowering(*I->getTargetLowering())); + GISel->MachineLegalizer.reset(new AArch64MachineLegalizer()); GISel->RegBankInfo.reset( new AArch64RegisterBankInfo(*I->getRegisterInfo())); #endif @@ -277,6 +284,7 @@ public: bool addInstSelector() override; #ifdef LLVM_BUILD_GLOBAL_ISEL bool addIRTranslator() override; + bool addLegalizeMachineIR() override; bool addRegBankSelect() override; #endif bool addILPOpts() override; @@ -375,6 +383,10 @@ bool AArch64PassConfig::addIRTranslator() { addPass(new IRTranslator()); return false; } +bool AArch64PassConfig::addLegalizeMachineIR() { + addPass(new MachineLegalizePass()); + return false; +} bool AArch64PassConfig::addRegBankSelect() { addPass(new RegBankSelect()); return false; diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index a79960ea960..9944a068243 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -19,6 +19,7 @@ add_public_tablegen_target(AArch64CommonTableGen) # List of all GlobalISel files. set(GLOBAL_ISEL_FILES AArch64CallLowering.cpp + AArch64MachineLegalizer.cpp AArch64RegisterBankInfo.cpp ) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp index b2d4e1144c7..9affa2e003d 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp @@ -315,6 +315,7 @@ public: bool addInstSelector() override; #ifdef LLVM_BUILD_GLOBAL_ISEL bool addIRTranslator() override; + bool addLegalizeMachineIR() override; bool addRegBankSelect() override; #endif void addFastRegAlloc(FunctionPass *RegAllocPass) override; @@ -520,6 +521,10 @@ bool GCNPassConfig::addIRTranslator() { return false; } +bool GCNPassConfig::addLegalizeMachineIR() { + return false; +} + bool GCNPassConfig::addRegBankSelect() { return false; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir new file mode 100644 index 00000000000..cf777eea604 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir @@ -0,0 +1,34 @@ +# RUN: llc -O0 -run-pass=legalize-mir -global-isel %s -o - 2>&1 | FileCheck %s +# REQUIRES: global-isel + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64-apple-ios" + define void @test_vector_add() { + entry: + ret void + } +... + +--- +name: test_vector_add +isSSA: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0.entry: + liveins: %q0, %q1, %q2, %q3 + ; CHECK-LABEL: name: test_vector_add + ; CHECK-DAG: [[LHS_LO:%.*]](128), [[LHS_HI:%.*]](128) = G_EXTRACT <2 x s64> %0, 0, 128 + ; CHECK-DAG: [[RHS_LO:%.*]](128), [[RHS_HI:%.*]](128) = G_EXTRACT <2 x s64> %1, 0, 128 + ; CHECK: [[RES_LO:%.*]](128) = G_ADD <2 x s64> [[LHS_LO]], [[RHS_LO]] + ; CHECK: [[RES_HI:%.*]](128) = G_ADD <2 x s64> [[LHS_HI]], [[RHS_HI]] + ; CHECK: %2(256) = G_SEQUENCE <4 x s64> [[RES_LO]], [[RES_HI]] + + %0(256) = G_SEQUENCE <4 x s64> %q0, %q1 + %1(256) = G_SEQUENCE <4 x s64> %q2, %q3 + %2(256) = G_ADD <4 x s64> %0, %1 + %q0, %q1 = G_EXTRACT <2 x s64> %2, 0, 128 +... |