[llvm] r276875 - [GlobalISel] Introduce an instruction selector.

Ahmed Bougacha via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 27 07:31:56 PDT 2016


Author: ab
Date: Wed Jul 27 09:31:55 2016
New Revision: 276875

URL: http://llvm.org/viewvc/llvm-project?rev=276875&view=rev
Log:
[GlobalISel] Introduce an instruction selector.

And implement it for AArch64, supporting x/w ADD/OR.

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

Added:
    llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelect.h
    llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
    llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelector.cpp
    llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
    llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.h
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir
Modified:
    llvm/trunk/include/llvm/CodeGen/GlobalISel/GISelAccessor.h
    llvm/trunk/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
    llvm/trunk/include/llvm/CodeGen/MachineRegisterInfo.h
    llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h
    llvm/trunk/include/llvm/InitializePasses.h
    llvm/trunk/include/llvm/Target/TargetSubtargetInfo.h
    llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt
    llvm/trunk/lib/CodeGen/GlobalISel/GlobalISel.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp
    llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp
    llvm/trunk/lib/CodeGen/MachineRegisterInfo.cpp
    llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp
    llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h
    llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp
    llvm/trunk/lib/Target/AArch64/CMakeLists.txt
    llvm/trunk/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp

Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/GISelAccessor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/GISelAccessor.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/GISelAccessor.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/GISelAccessor.h Wed Jul 27 09:31:55 2016
@@ -17,6 +17,7 @@
 
 namespace llvm {
 class CallLowering;
+class InstructionSelector;
 class MachineLegalizer;
 class RegisterBankInfo;
 
@@ -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;
   }

Added: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelect.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelect.h?rev=276875&view=auto
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelect.h (added)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelect.h Wed Jul 27 09:31:55 2016
@@ -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

Added: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=276875&view=auto
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h (added)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h Wed Jul 27 09:31:55 2016
@@ -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

Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h Wed Jul 27 09:31:55 2016
@@ -437,6 +437,15 @@ public:
     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.

Modified: llvm/trunk/include/llvm/CodeGen/MachineRegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineRegisterInfo.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineRegisterInfo.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineRegisterInfo.h Wed Jul 27 09:31:55 2016
@@ -658,6 +658,10 @@ public:
   /// \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(); }

Modified: llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h (original)
+++ llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h Wed Jul 27 09:31:55 2016
@@ -234,6 +234,16 @@ public:
   /// 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();

Modified: llvm/trunk/include/llvm/InitializePasses.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/InitializePasses.h (original)
+++ llvm/trunk/include/llvm/InitializePasses.h Wed Jul 27 09:31:55 2016
@@ -155,6 +155,7 @@ void initializeInstNamerPass(PassRegistr
 void initializeInstSimplifierPass(PassRegistry&);
 void initializeInstrProfilingLegacyPassPass(PassRegistry &);
 void initializeInstructionCombiningPassPass(PassRegistry&);
+void initializeInstructionSelectPass(PassRegistry &);
 void initializeInterleavedAccessPass(PassRegistry &);
 void initializeInternalizeLegacyPassPass(PassRegistry&);
 void initializeIntervalPartitionPass(PassRegistry&);

Modified: llvm/trunk/include/llvm/Target/TargetSubtargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetSubtargetInfo.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/TargetSubtargetInfo.h (original)
+++ llvm/trunk/include/llvm/Target/TargetSubtargetInfo.h Wed Jul 27 09:31:55 2016
@@ -25,6 +25,7 @@ namespace llvm {
 
 class CallLowering;
 class DataLayout;
+class InstructionSelector;
 class MachineFunction;
 class MachineInstr;
 class MachineLegalizer;
@@ -89,6 +90,15 @@ public:
     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 {

Modified: llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt Wed Jul 27 09:31:55 2016
@@ -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

Modified: llvm/trunk/lib/CodeGen/GlobalISel/GlobalISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/GlobalISel.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/GlobalISel.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/GlobalISel.cpp Wed Jul 27 09:31:55 2016
@@ -27,5 +27,6 @@ void llvm::initializeGlobalISel(PassRegi
   initializeIRTranslatorPass(Registry);
   initializeMachineLegalizePassPass(Registry);
   initializeRegBankSelectPass(Registry);
+  initializeInstructionSelectPass(Registry);
 }
 #endif // LLVM_BUILD_GLOBAL_ISEL

Added: llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp?rev=276875&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp (added)
+++ llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp Wed Jul 27 09:31:55 2016
@@ -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;
+}

Added: llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelector.cpp?rev=276875&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelector.cpp (added)
+++ llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelector.cpp Wed Jul 27 09:31:55 2016
@@ -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;
+}

Modified: llvm/trunk/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp Wed Jul 27 09:31:55 2016
@@ -189,6 +189,25 @@ const RegisterBank *RegisterBankInfo::ge
   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,

Modified: llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp (original)
+++ llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp Wed Jul 27 09:31:55 2016
@@ -177,6 +177,11 @@ addPassesToGenerateCode(LLVMTargetMachin
     if (PassConfig->addRegBankSelect())
       return nullptr;
 
+    PassConfig->addPreGlobalInstructionSelect();
+
+    if (PassConfig->addGlobalInstructionSelect())
+      return nullptr;
+
   } else if (PassConfig->addInstSelector())
     return nullptr;
 

Modified: llvm/trunk/lib/CodeGen/MachineRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineRegisterInfo.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/MachineRegisterInfo.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineRegisterInfo.cpp Wed Jul 27 09:31:55 2016
@@ -136,6 +136,20 @@ MachineRegisterInfo::createGenericVirtua
   return Reg;
 }
 
+void MachineRegisterInfo::clearVirtRegSizes() {
+#ifndef NDEBUG
+  // Verify that the size of the now-constrained vreg is unchanged.
+  for (auto &VRegToSize : getVRegToSize()) {
+    auto *RC = getRegClass(VRegToSize.first);
+    if (VRegToSize.second != (RC->getSize() * 8))
+      llvm_unreachable(
+          "Virtual register has explicit size different from its class size");
+  }
+#endif
+
+  getVRegToSize().clear();
+}
+
 /// clearVirtRegs - Remove all virtual registers (after physreg assignment).
 void MachineRegisterInfo::clearVirtRegs() {
 #ifndef NDEBUG

Added: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp?rev=276875&view=auto
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp (added)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp Wed Jul 27 09:31:55 2016
@@ -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;
+}

Added: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.h?rev=276875&view=auto
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.h (added)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.h Wed Jul 27 09:31:55 2016
@@ -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

Modified: llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp Wed Jul 27 09:31:55 2016
@@ -98,6 +98,11 @@ const CallLowering *AArch64Subtarget::ge
   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();

Modified: llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h Wed Jul 27 09:31:55 2016
@@ -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; }

Modified: llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp Wed Jul 27 09:31:55 2016
@@ -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::~AArch64TargetMach
 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(c
     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() {

Modified: llvm/trunk/lib/Target/AArch64/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/CMakeLists.txt?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/AArch64/CMakeLists.txt Wed Jul 27 09:31:55 2016
@@ -19,6 +19,7 @@ add_public_tablegen_target(AArch64Common
 # List of all GlobalISel files.
 set(GLOBAL_ISEL_FILES
       AArch64CallLowering.cpp
+      AArch64InstructionSelector.cpp
       AArch64MachineLegalizer.cpp
       AArch64RegisterBankInfo.cpp
       )

Modified: llvm/trunk/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp?rev=276875&r1=276874&r2=276875&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp Wed Jul 27 09:31:55 2016
@@ -317,6 +317,7 @@ public:
   bool addIRTranslator() override;
   bool addLegalizeMachineIR() override;
   bool addRegBankSelect() override;
+  bool addGlobalInstructionSelect() override;
 #endif
   void addFastRegAlloc(FunctionPass *RegAllocPass) override;
   void addOptimizedRegAlloc(FunctionPass *RegAllocPass) override;
@@ -528,6 +529,10 @@ bool GCNPassConfig::addLegalizeMachineIR
 bool GCNPassConfig::addRegBankSelect() {
   return false;
 }
+
+bool GCNPassConfig::addGlobalInstructionSelect() {
+  return false;
+}
 #endif
 
 void GCNPassConfig::addPreRegAlloc() {

Added: llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir?rev=276875&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir (added)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir Wed Jul 27 09:31:55 2016
@@ -0,0 +1,118 @@
+# RUN: llc -O0 -run-pass=instruction-select -global-isel %s -o - | FileCheck %s
+# REQUIRES: global-isel
+
+# Test the instruction selector.
+# As we support more instructions, we need to split this up.
+
+--- |
+  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+  target triple = "aarch64-apple-ios"
+
+  define void @add_s32_gpr() { ret void }
+  define void @add_s64_gpr() { ret void }
+
+  define void @or_s32_gpr() { ret void }
+  define void @or_s64_gpr() { ret void }
+
+...
+
+---
+# Check that we select a 32-bit GPR G_ADD into ADDWrr on GPR32.
+# Also check that we constrain the register class of the COPY to GPR32.
+# CHECK-LABEL: name: add_s32_gpr
+name:            add_s32_gpr
+alignment:       2
+isSSA:           true
+
+# CHECK:      registers:
+# CHECK-NEXT:  - { id: 0, class: gpr32 }
+# CHECK-NEXT:  - { id: 1, class: gpr32 }
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+
+# CHECK:  body:
+# CHECK:    %0 = COPY %w0
+# CHECK:    %1 = ADDWrr %0, %0
+body:             |
+  bb.0:
+    liveins: %w0
+
+    %0(32) = COPY %w0
+    %1(32) = G_ADD s32 %0, %0
+...
+
+---
+# Same as add_s32_gpr, for 64-bit operations.
+# CHECK-LABEL: name: add_s64_gpr
+name:            add_s64_gpr
+alignment:       2
+isSSA:           true
+
+# CHECK:      registers:
+# CHECK-NEXT:  - { id: 0, class: gpr64 }
+# CHECK-NEXT:  - { id: 1, class: gpr64 }
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+
+# CHECK:  body:
+# CHECK:    %0 = COPY %x0
+# CHECK:    %1 = ADDXrr %0, %0
+body:             |
+  bb.0:
+    liveins: %x0
+
+    %0(64) = COPY %x0
+    %1(64) = G_ADD s64 %0, %0
+...
+
+---
+# Same as add_s32_gpr, for G_OR operations.
+# CHECK-LABEL: name: or_s32_gpr
+name:            or_s32_gpr
+alignment:       2
+isSSA:           true
+
+# CHECK:      registers:
+# CHECK-NEXT:  - { id: 0, class: gpr32 }
+# CHECK-NEXT:  - { id: 1, class: gpr32 }
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+
+# CHECK:  body:
+# CHECK:    %0 = COPY %w0
+# CHECK:    %1 = ORRWrr %0, %0
+body:             |
+  bb.0:
+    liveins: %w0
+
+    %0(32) = COPY %w0
+    %1(32) = G_OR s32 %0, %0
+...
+
+---
+# Same as add_s64_gpr, for G_OR operations.
+# CHECK-LABEL: name: or_s64_gpr
+name:            or_s64_gpr
+alignment:       2
+isSSA:           true
+
+# CHECK:      registers:
+# CHECK-NEXT:  - { id: 0, class: gpr64 }
+# CHECK-NEXT:  - { id: 1, class: gpr64 }
+registers:
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+
+# CHECK:  body:
+# CHECK:    %0 = COPY %x0
+# CHECK:    %1 = ORRXrr %0, %0
+body:             |
+  bb.0:
+    liveins: %x0
+
+    %0(64) = COPY %x0
+    %1(64) = G_OR s64 %0, %0
+...




More information about the llvm-commits mailing list