Skip to content

Commit

Permalink
[GlobalISel] Introduce an instruction selector.
Browse files Browse the repository at this point in the history
And implement it for AArch64, supporting x/w ADD/OR.

Differential Revision: https://reviews.llvm.org/D22373

llvm-svn: 276875
  • Loading branch information
ahmedbougacha committed Jul 27, 2016
1 parent 5e402ee commit 6756a2c
Show file tree
Hide file tree
Showing 23 changed files with 683 additions and 2 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/GISelAccessor.h
Expand Up @@ -17,6 +17,7 @@

namespace llvm {
class CallLowering;
class InstructionSelector;
class MachineLegalizer;
class RegisterBankInfo;

Expand All @@ -28,6 +29,9 @@ class RegisterBankInfo;
struct GISelAccessor {
virtual ~GISelAccessor() {}
virtual const CallLowering *getCallLowering() const { return nullptr;}
virtual const InstructionSelector *getInstructionSelector() const {
return nullptr;
}
virtual const MachineLegalizer *getMachineLegalizer() const {
return nullptr;
}
Expand Down
39 changes: 39 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/InstructionSelect.h
@@ -0,0 +1,39 @@
//== llvm/CodeGen/GlobalISel/InstructionSelect.h -----------------*- 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 describes the interface of the MachineFunctionPass
/// responsible for selecting (possibly generic) machine instructions to
/// target-specific instructions.
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECT_H
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECT_H

#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/MachineFunctionPass.h"

namespace llvm {
/// This pass is responsible for selecting generic machine instructions to
/// target-specific instructions. It relies on the InstructionSelector provided
/// by the target.
/// Selection is done by examining blocks in post-order, and instructions in
/// reverse order.
///
/// \post for all inst in MF: not isPreISelGenericOpcode(inst.opcode)
class InstructionSelect : public MachineFunctionPass {
public:
static char ID;
const char *getPassName() const override { return "InstructionSelect"; }

InstructionSelect();

bool runOnMachineFunction(MachineFunction &MF) override;
};
} // End namespace llvm.

#endif
63 changes: 63 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
@@ -0,0 +1,63 @@
//==-- llvm/CodeGen/GlobalISel/InstructionSelector.h -------------*- 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 API for the instruction selector.
/// This class is responsible for selecting machine instructions.
/// It's implemented by the target. It's used by the InstructionSelect pass.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H

namespace llvm {
class MachineInstr;
class RegisterBankInfo;
class TargetInstrInfo;
class TargetRegisterInfo;

/// Provides the logic to select generic machine instructions.
class InstructionSelector {
public:
virtual ~InstructionSelector() {}

/// Select the (possibly generic) instruction \p I to only use target-specific
/// opcodes. It is OK to insert multiple instructions, but they cannot be
/// generic pre-isel instructions.
///
/// \returns whether selection succeeded.
/// \pre I.getParent() && I.getParent()->getParent()
/// \post
/// if returns true:
/// for I in all mutated/inserted instructions:
/// !isPreISelGenericOpcode(I.getOpcode())
///
virtual bool select(MachineInstr &I) const = 0;

protected:
InstructionSelector();

/// Mutate the newly-selected instruction \p I to constrain its (possibly
/// generic) virtual register operands to the instruction's register class.
/// This could involve inserting COPYs before (for uses) or after (for defs).
/// This requires the number of operands to match the instruction description.
/// \returns whether operand regclass constraining succeeded.
///
// FIXME: Not all instructions have the same number of operands. We should
// probably expose a constrain helper per operand and let the target selector
// constrain individual registers, like fast-isel.
bool constrainSelectedInstRegOperands(MachineInstr &I,
const TargetInstrInfo &TII,
const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI) const;
};

} // End namespace llvm.

#endif
9 changes: 9 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
Expand Up @@ -437,6 +437,15 @@ class RegisterBankInfo {
return &A != &B;
}

/// Constrain the (possibly generic) virtual register \p Reg to \p RC.
///
/// \pre \p Reg is a virtual register that either has a bank or a class.
/// \returns The constrained register class, or nullptr if there is none.
/// \note This is a generic variant of MachineRegisterInfo::constrainRegClass
static const TargetRegisterClass *
constrainGenericRegister(unsigned Reg, const TargetRegisterClass &RC,
MachineRegisterInfo &MRI);

/// Identifier used when the related instruction mapping instance
/// is generated by target independent code.
/// Make sure not to use that identifier to avoid possible collision.
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/MachineRegisterInfo.h
Expand Up @@ -658,6 +658,10 @@ class MachineRegisterInfo {
/// \pre Size > 0.
unsigned createGenericVirtualRegister(unsigned Size);

/// Remove all sizes associated to virtual registers (after instruction
/// selection and constraining of all generic virtual registers).
void clearVirtRegSizes();

/// getNumVirtRegs - Return the number of virtual registers created.
///
unsigned getNumVirtRegs() const { return VRegInfo.size(); }
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/CodeGen/TargetPassConfig.h
Expand Up @@ -234,6 +234,16 @@ class TargetPassConfig : public ImmutablePass {
/// class or register banks.
virtual bool addRegBankSelect() { return true; }

/// This method may be implemented by targets that want to run passes
/// immediately before the (global) instruction selection.
virtual void addPreGlobalInstructionSelect() {}

/// This method should install a (global) instruction selector pass, which
/// converts possibly generic instructions to fully target-specific
/// instructions, thereby constraining all generic virtual registers to
/// register classes.
virtual bool addGlobalInstructionSelect() { return true; }

/// Add the complete, standard set of LLVM CodeGen passes.
/// Fully developed targets will not generally override this.
virtual void addMachinePasses();
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Expand Up @@ -155,6 +155,7 @@ void initializeInstNamerPass(PassRegistry&);
void initializeInstSimplifierPass(PassRegistry&);
void initializeInstrProfilingLegacyPassPass(PassRegistry &);
void initializeInstructionCombiningPassPass(PassRegistry&);
void initializeInstructionSelectPass(PassRegistry &);
void initializeInterleavedAccessPass(PassRegistry &);
void initializeInternalizeLegacyPassPass(PassRegistry&);
void initializeIntervalPartitionPass(PassRegistry&);
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/Target/TargetSubtargetInfo.h
Expand Up @@ -25,6 +25,7 @@ namespace llvm {

class CallLowering;
class DataLayout;
class InstructionSelector;
class MachineFunction;
class MachineInstr;
class MachineLegalizer;
Expand Down Expand Up @@ -89,6 +90,15 @@ class TargetSubtargetInfo : public MCSubtargetInfo {
return nullptr;
}
virtual const CallLowering *getCallLowering() const { return nullptr; }

// FIXME: This lets targets specialize the selector by subtarget (which lets
// us do things like a dedicated avx512 selector). However, we might want
// to also specialize selectors by MachineFunction, which would let us be
// aware of optsize/optnone and such.
virtual const InstructionSelector *getInstructionSelector() const {
return nullptr;
}

/// Target can subclass this hook to select a different DAG scheduler.
virtual RegisterScheduler::FunctionPassCtor
getDAGScheduler(CodeGenOpt::Level) const {
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/CMakeLists.txt
@@ -1,6 +1,8 @@
# List of all GlobalISel files.
set(GLOBAL_ISEL_FILES
IRTranslator.cpp
InstructionSelect.cpp
InstructionSelector.cpp
MachineIRBuilder.cpp
MachineLegalizeHelper.cpp
MachineLegalizePass.cpp
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp
Expand Up @@ -27,5 +27,6 @@ void llvm::initializeGlobalISel(PassRegistry &Registry) {
initializeIRTranslatorPass(Registry);
initializeMachineLegalizePassPass(Registry);
initializeRegBankSelectPass(Registry);
initializeInstructionSelectPass(Registry);
}
#endif // LLVM_BUILD_GLOBAL_ISEL
99 changes: 99 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -0,0 +1,99 @@
//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==//
//
// 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 InstructionSelect class.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetSubtargetInfo.h"

#define DEBUG_TYPE "instruction-select"

using namespace llvm;

char InstructionSelect::ID = 0;
INITIALIZE_PASS(InstructionSelect, DEBUG_TYPE,
"Select target instructions out of generic instructions",
false, false);

InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) {
initializeInstructionSelectPass(*PassRegistry::getPassRegistry());
}

static void reportSelectionError(const MachineInstr &MI, const Twine &Message) {
const MachineFunction &MF = *MI.getParent()->getParent();
std::string ErrStorage;
raw_string_ostream Err(ErrStorage);
Err << Message << ":\nIn function: " << MF.getName() << '\n' << MI << '\n';
report_fatal_error(Err.str());
}

bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n');

const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
assert(ISel && "Cannot work without InstructionSelector");

// FIXME: freezeReservedRegs is now done in IRTranslator, but there are many
// other MF/MFI fields we need to initialize.

#ifndef NDEBUG
// FIXME: We could introduce new blocks and will need to fix the outer loop.
// Until then, keep track of the number of blocks to assert that we don't.
const size_t NumBlocks = MF.size();
#endif

for (MachineBasicBlock *MBB : post_order(&MF)) {
for (MachineBasicBlock::reverse_iterator MII = MBB->rbegin(),
End = MBB->rend();
MII != End;) {
MachineInstr &MI = *MII++;
DEBUG(dbgs() << "Selecting: " << MI << '\n');
if (!ISel->select(MI))
reportSelectionError(MI, "Cannot select");
// FIXME: It would be nice to dump all inserted instructions. It's not
// obvious how, esp. considering select() can insert after MI.
}
}

assert(MF.size() == NumBlocks && "Inserting blocks is not supported yet");

// Check that we did select everything. Do this separately to make sure we
// didn't miss any newly inserted instructions.
// FIXME: This (and other checks) should move into a verifier, predicated on
// a "post-isel" MachineFunction property. That would also let us selectively
// enable it depending on build configuration.
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
if (isPreISelGenericOpcode(MI.getOpcode())) {
reportSelectionError(
MI, "Generic instruction survived instruction selection");
}
}
}

// Now that selection is complete, there are no more generic vregs.
// FIXME: We're still discussing what to do with the vreg->size map:
// it's somewhat redundant (with the def MIs type size), but having to
// examine MIs is also awkward. Another alternative is to track the type on
// the vreg instead, but that's not ideal either, because it's saying that
// vregs have types, which they really don't. But then again, LLT is just
// a size and a "shape": it's probably the same information as regbank info.
MF.getRegInfo().clearVirtRegSizes();

// FIXME: Should we accurately track changes?
return true;
}
52 changes: 52 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp
@@ -0,0 +1,52 @@
//===- llvm/CodeGen/GlobalISel/InstructionSelector.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 InstructionSelector class.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"

#define DEBUG_TYPE "instructionselector"

using namespace llvm;

InstructionSelector::InstructionSelector() {}

bool InstructionSelector::constrainSelectedInstRegOperands(
MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI) const {
MachineBasicBlock &MBB = *I.getParent();
MachineFunction &MF = *MBB.getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();

for (unsigned OpI = 0, OpE = I.getNumExplicitOperands(); OpI != OpE; ++OpI) {
MachineOperand &MO = I.getOperand(OpI);
DEBUG(dbgs() << "Converting operand: " << MO << '\n');

assert(MO.isReg() && "Unsupported binop non-reg operand");

const TargetRegisterClass *RC = TII.getRegClass(I.getDesc(), OpI, &TRI, MF);
assert(RC && "Selected inst should have regclass operand");

// If the operand is a vreg, we should constrain its regclass, and only
// insert COPYs if that's impossible.
// If the operand is a physreg, we only insert COPYs if the register class
// doesn't contain the register.
if (RBI.constrainGenericRegister(MO.getReg(), *RC, MRI))
continue;

DEBUG(dbgs() << "Constraining with COPYs isn't implemented yet");
return false;
}
return true;
}
19 changes: 19 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp
Expand Up @@ -189,6 +189,25 @@ const RegisterBank *RegisterBankInfo::getRegBankFromConstraints(
return &RegBank;
}

const TargetRegisterClass *RegisterBankInfo::constrainGenericRegister(
unsigned Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI) {

// If the register already has a class, fallback to MRI::constrainRegClass.
auto &RegClassOrBank = MRI.getRegClassOrRegBank(Reg);
if (RegClassOrBank.is<const TargetRegisterClass *>())
return MRI.constrainRegClass(Reg, &RC);

const RegisterBank *RB = RegClassOrBank.get<const RegisterBank *>();
assert(RB && "Generic register does not have a register bank");

// Otherwise, all we can do is ensure the bank covers the class, and set it.
if (!RB->covers(RC))
return nullptr;

MRI.setRegClass(Reg, &RC);
return &RC;
}

RegisterBankInfo::InstructionMapping
RegisterBankInfo::getInstrMappingImpl(const MachineInstr &MI) const {
RegisterBankInfo::InstructionMapping Mapping(DefaultMappingID, /*Cost*/ 1,
Expand Down

0 comments on commit 6756a2c

Please sign in to comment.