summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/AArch64
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AArch64')
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp162
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstructionSelector.h39
-rw-r--r--llvm/lib/Target/AArch64/AArch64Subtarget.cpp5
-rw-r--r--llvm/lib/Target/AArch64/AArch64Subtarget.h1
-rw-r--r--llvm/lib/Target/AArch64/AArch64TargetMachine.cpp22
-rw-r--r--llvm/lib/Target/AArch64/CMakeLists.txt1
6 files changed, 228 insertions, 2 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
new file mode 100644
index 00000000000..6899950c263
--- /dev/null
+++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
@@ -0,0 +1,162 @@
+//===- AArch64InstructionSelector.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 InstructionSelector class for
+/// AArch64.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#include "AArch64InstructionSelector.h"
+#include "AArch64InstrInfo.h"
+#include "AArch64RegisterBankInfo.h"
+#include "AArch64RegisterInfo.h"
+#include "AArch64Subtarget.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "aarch64-isel"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+AArch64InstructionSelector::AArch64InstructionSelector(
+ const AArch64Subtarget &STI, const AArch64RegisterBankInfo &RBI)
+ : InstructionSelector(), TII(*STI.getInstrInfo()),
+ TRI(*STI.getRegisterInfo()), RBI(RBI) {}
+
+/// Select the AArch64 opcode for the basic binary operation \p GenericOpc
+/// (such as G_OR or G_ADD), appropriate for the register bank \p RegBankID
+/// and of size \p OpSize.
+/// \returns \p GenericOpc if the combination is unsupported.
+static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID,
+ unsigned OpSize) {
+ switch (RegBankID) {
+ case AArch64::GPRRegBankID:
+ switch (OpSize) {
+ case 32:
+ switch (GenericOpc) {
+ case TargetOpcode::G_OR:
+ return AArch64::ORRWrr;
+ case TargetOpcode::G_ADD:
+ return AArch64::ADDWrr;
+ default:
+ return GenericOpc;
+ }
+ case 64:
+ switch (GenericOpc) {
+ case TargetOpcode::G_OR:
+ return AArch64::ORRXrr;
+ case TargetOpcode::G_ADD:
+ return AArch64::ADDXrr;
+ default:
+ return GenericOpc;
+ }
+ }
+ };
+ return GenericOpc;
+}
+
+bool AArch64InstructionSelector::select(MachineInstr &I) const {
+ assert(I.getParent() && "Instruction should be in a basic block!");
+ assert(I.getParent()->getParent() && "Instruction should be in a function!");
+
+ MachineBasicBlock &MBB = *I.getParent();
+ MachineFunction &MF = *MBB.getParent();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ // FIXME: Is there *really* nothing to be done here? This assumes that
+ // no upstream pass introduces things like generic vreg on copies or
+ // target-specific instructions.
+ // We should document (and verify) that assumption.
+ if (!isPreISelGenericOpcode(I.getOpcode()))
+ return true;
+
+ if (I.getNumOperands() != I.getNumExplicitOperands()) {
+ DEBUG(dbgs() << "Generic instruction has unexpected implicit operands\n");
+ return false;
+ }
+
+ LLT Ty = I.getType();
+ assert(Ty.isValid() && "Generic instruction doesn't have a type");
+
+ // FIXME: Support unsized instructions (e.g., G_BR).
+ if (!Ty.isSized()) {
+ DEBUG(dbgs() << "Unsized generic instructions are unsupported\n");
+ return false;
+ }
+
+ // The size (in bits) of the operation, or 0 for the label type.
+ const unsigned OpSize = Ty.getSizeInBits();
+
+ switch (I.getOpcode()) {
+ case TargetOpcode::G_OR:
+ case TargetOpcode::G_ADD: {
+ DEBUG(dbgs() << "AArch64: Selecting: binop\n");
+
+ // Reject the various things we don't support yet.
+ {
+ const RegisterBank *PrevOpBank = nullptr;
+ for (auto &MO : I.operands()) {
+ // FIXME: Support non-register operands.
+ if (!MO.isReg()) {
+ DEBUG(dbgs() << "Generic inst non-reg operands are unsupported\n");
+ return false;
+ }
+
+ // FIXME: Can generic operations have physical registers operands? If
+ // so, this will need to be taught about that, and we'll need to get the
+ // bank out of the minimal class for the register.
+ // Either way, this needs to be documented (and possibly verified).
+ if (!TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
+ DEBUG(dbgs() << "Generic inst has physical register operand\n");
+ return false;
+ }
+
+ const RegisterBank *OpBank = RBI.getRegBank(MO.getReg(), MRI, TRI);
+ if (!OpBank) {
+ DEBUG(dbgs() << "Generic register has no bank or class\n");
+ return false;
+ }
+
+ if (PrevOpBank && OpBank != PrevOpBank) {
+ DEBUG(dbgs() << "Generic inst operands have different banks\n");
+ return false;
+ }
+ PrevOpBank = OpBank;
+ }
+ }
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ const unsigned NewOpc = selectBinaryOp(I.getOpcode(), RB.getID(), OpSize);
+ if (NewOpc == I.getOpcode())
+ return false;
+
+ I.setDesc(TII.get(NewOpc));
+ // FIXME: Should the type be always reset in setDesc?
+ I.setType(LLT());
+
+ // Now that we selected an opcode, we need to constrain the register
+ // operands to use appropriate classes.
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ }
+ }
+
+ return false;
+}
diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.h b/llvm/lib/Target/AArch64/AArch64InstructionSelector.h
new file mode 100644
index 00000000000..8b9a90d7f2f
--- /dev/null
+++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.h
@@ -0,0 +1,39 @@
+//===- AArch64InstructionSelector --------------------------------*- 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 InstructionSelector class for
+/// AArch64.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64INSTRUCTIONSELECTOR_H
+#define LLVM_LIB_TARGET_AARCH64_AARCH64INSTRUCTIONSELECTOR_H
+
+#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+
+namespace llvm {
+class AArch64InstrInfo;
+class AArch64RegisterBankInfo;
+class AArch64RegisterInfo;
+class AArch64Subtarget;
+
+class AArch64InstructionSelector : public InstructionSelector {
+public:
+ AArch64InstructionSelector(const AArch64Subtarget &STI,
+ const AArch64RegisterBankInfo &RBI);
+
+ virtual bool select(MachineInstr &I) const override;
+
+private:
+ const AArch64InstrInfo &TII;
+ const AArch64RegisterInfo &TRI;
+ const AArch64RegisterBankInfo &RBI;
+};
+
+} // End llvm namespace.
+#endif
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index 9ec3b164243..d257e81a952 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 InstructionSelector *AArch64Subtarget::getInstructionSelector() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getInstructionSelector();
+}
+
const MachineLegalizer *AArch64Subtarget::getMachineLegalizer() const {
assert(GISel && "Access to GlobalISel APIs not set");
return GISel->getMachineLegalizer();
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index e4bafa4d79d..ee07fec2e75 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 InstructionSelector *getInstructionSelector() const override;
const MachineLegalizer *getMachineLegalizer() const override;
const RegisterBankInfo *getRegBankInfo() const override;
const Triple &getTargetTriple() const { return TargetTriple; }
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 6107e6c94db..7ee07efbc88 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -12,12 +12,14 @@
#include "AArch64.h"
#include "AArch64CallLowering.h"
+#include "AArch64InstructionSelector.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/InstructionSelect.h"
#include "llvm/CodeGen/GlobalISel/MachineLegalizePass.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/Passes.h"
@@ -198,11 +200,15 @@ AArch64TargetMachine::~AArch64TargetMachine() {}
namespace {
struct AArch64GISelActualAccessor : public GISelAccessor {
std::unique_ptr<CallLowering> CallLoweringInfo;
+ std::unique_ptr<InstructionSelector> InstSelector;
std::unique_ptr<MachineLegalizer> Legalizer;
std::unique_ptr<RegisterBankInfo> RegBankInfo;
const CallLowering *getCallLowering() const override {
return CallLoweringInfo.get();
}
+ const InstructionSelector *getInstructionSelector() const override {
+ return InstSelector.get();
+ }
const class MachineLegalizer *getMachineLegalizer() const override {
return Legalizer.get();
}
@@ -241,8 +247,15 @@ AArch64TargetMachine::getSubtargetImpl(const Function &F) const {
GISel->CallLoweringInfo.reset(
new AArch64CallLowering(*I->getTargetLowering()));
GISel->Legalizer.reset(new AArch64MachineLegalizer());
- GISel->RegBankInfo.reset(
- new AArch64RegisterBankInfo(*I->getRegisterInfo()));
+
+ auto *RBI = new AArch64RegisterBankInfo(*I->getRegisterInfo());
+
+ // FIXME: At this point, we can't rely on Subtarget having RBI.
+ // It's awkward to mix passing RBI and the Subtarget; should we pass
+ // TII/TRI as well?
+ GISel->InstSelector.reset(new AArch64InstructionSelector(*I, *RBI));
+
+ GISel->RegBankInfo.reset(RBI);
#endif
I->setGISelAccessor(*GISel);
}
@@ -286,6 +299,7 @@ public:
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
+ bool addGlobalInstructionSelect() override;
#endif
bool addILPOpts() override;
void addPreRegAlloc() override;
@@ -391,6 +405,10 @@ bool AArch64PassConfig::addRegBankSelect() {
addPass(new RegBankSelect());
return false;
}
+bool AArch64PassConfig::addGlobalInstructionSelect() {
+ addPass(new InstructionSelect());
+ return false;
+}
#endif
bool AArch64PassConfig::addILPOpts() {
diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index 9944a068243..89cfaa763a0 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
+ AArch64InstructionSelector.cpp
AArch64MachineLegalizer.cpp
AArch64RegisterBankInfo.cpp
)
OpenPOWER on IntegriCloud