summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp')
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp162
1 files changed, 162 insertions, 0 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;
+}
OpenPOWER on IntegriCloud