[llvm] r276184 - GlobalISel: implement Legalization querying framework.

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 20 14:13:29 PDT 2016


Author: tnorthover
Date: Wed Jul 20 16:13:29 2016
New Revision: 276184

URL: http://llvm.org/viewvc/llvm-project?rev=276184&view=rev
Log:
GlobalISel: implement Legalization querying framework.

This adds an (incomplete, inefficient) framework for deciding what to do with
some operation on a given type.

Added:
    llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h
    llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizer.cpp
    llvm/trunk/unittests/CodeGen/GlobalISel/
    llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt
    llvm/trunk/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp
Modified:
    llvm/trunk/include/llvm/CodeGen/LowLevelType.h
    llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt
    llvm/trunk/unittests/CodeGen/CMakeLists.txt

Added: llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h?rev=276184&view=auto
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h (added)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h Wed Jul 20 16:13:29 2016
@@ -0,0 +1,157 @@
+//==-- llvm/CodeGen/GlobalISel/MachineLegalizer.h ----------------*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// Interface for Targets to specify which operations they can successfully
+/// select and how the others should be expanded most efficiently.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZER_H
+#define LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/CodeGen/LowLevelType.h"
+
+#include <cstdint>
+#include <functional>
+
+namespace llvm {
+class LLVMContext;
+class MachineInstr;
+class Type;
+class VectorType;
+
+class MachineLegalizer {
+public:
+  enum LegalizeAction : std::uint8_t {
+    /// The operation is expected to be selectable directly by the target, and
+    /// no transformation is necessary.
+    Legal,
+
+    /// The operation should be synthesized from multiple instructions acting on
+    /// a narrower scalar base-type. For example a 64-bit add might be
+    /// implemented in terms of 32-bit add-with-carry.
+    NarrowScalar,
+
+    /// The operation should be implemented in terms of a wider scalar
+    /// base-type. For example a <2 x s8> add could be implemented as a <2
+    /// x s32> add (ignoring the high bits).
+    WidenScalar,
+
+    /// The (vector) operation should be implemented by splitting it into
+    /// sub-vectors where the operation is legal. For example a <8 x s64> add
+    /// might be implemented as 4 separate <2 x s64> adds.
+    FewerElements,
+
+    /// The (vector) operation should be implemented by widening the input
+    /// vector and ignoring the lanes added by doing so. For example <2 x i8> is
+    /// rarely legal, but you might perform an <8 x i8> and then only look at
+    /// the first two results.
+    MoreElements,
+
+    /// The operation should be implemented as a call to some kind of runtime
+    /// support library. For example this usually happens on machines that don't
+    /// support floating-point operations natively.
+    Libcall,
+
+    /// The target wants to do something special with this combination of
+    /// operand and type. A callback will be issued when it is needed.
+    Custom,
+
+    /// This operation is completely unsupported on the target. A programming
+    /// error has occurred.
+    Unsupported,
+  };
+
+  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.
+  void computeTables();
+
+  /// More friendly way to set an action for common types that have an LLT
+  /// representation.
+  void setAction(unsigned Opcode, LLT Ty, LegalizeAction Action) {
+    TablesInitialized = false;
+    Actions[std::make_pair(Opcode, Ty)] = Action;
+  }
+
+  /// If an operation on a given vector type (say <M x iN>) isn't explicitly
+  /// specified, we proceed in 2 stages. First we legalize the underlying scalar
+  /// (so that there's at least one legal vector with that scalar), then we
+  /// adjust the number of elements in the vector so that it is legal. The
+  /// desired action in the first step is controlled by this function.
+  void setScalarInVectorAction(unsigned Opcode, LLT ScalarTy,
+                               LegalizeAction Action) {
+    assert(!ScalarTy.isVector());
+    ScalarInVectorActions[std::make_pair(Opcode, ScalarTy)] = Action;
+  }
+
+
+  /// Determine what action should be taken to legalize the given generic
+  /// instruction and type. Requires computeTables to have been called.
+  ///
+  /// \returns a pair consisting of the kind of legalization that should be
+  /// performed and the destination type.
+  std::pair<LegalizeAction, LLT> getAction(unsigned Opcode, LLT) const;
+  std::pair<LegalizeAction, LLT> getAction(MachineInstr &MI) const;
+
+  /// Iterate the given function (typically something like doubling the width)
+  /// on Ty until we find a legal type for this operation.
+  LLT findLegalType(unsigned Opcode, LLT Ty,
+                      std::function<LLT(LLT)> NextType) const {
+    LegalizeAction Action;
+    do {
+      Ty = NextType(Ty);
+      auto ActionIt = Actions.find(std::make_pair(Opcode, Ty));
+      if (ActionIt == Actions.end())
+        Action = DefaultActions.find(Opcode)->second;
+      else
+        Action = ActionIt->second;
+    } while(Action != Legal);
+    return Ty;
+  }
+
+  /// Find what type it's actually OK to perform the given operation on, given
+  /// the general approach we've decided to take.
+  LLT findLegalType(unsigned Opcode, LLT Ty, LegalizeAction Action) const;
+
+  std::pair<LegalizeAction, LLT> findLegalAction(unsigned Opcode, LLT Ty,
+                                                 LegalizeAction Action) const {
+    return std::make_pair(Action, findLegalType(Opcode, Ty, Action));
+  }
+
+  bool isLegal(MachineInstr &MI) const;
+
+private:
+  typedef DenseMap<std::pair<unsigned, LLT>, LegalizeAction> ActionMap;
+
+  ActionMap Actions;
+  ActionMap ScalarInVectorActions;
+  DenseMap<std::pair<unsigned, LLT>, uint16_t> MaxLegalVectorElts;
+  DenseMap<unsigned, LegalizeAction> DefaultActions;
+
+  bool TablesInitialized;
+};
+
+} // End namespace llvm.
+
+#endif

Modified: llvm/trunk/include/llvm/CodeGen/LowLevelType.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LowLevelType.h?rev=276184&r1=276183&r2=276184&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/LowLevelType.h (original)
+++ llvm/trunk/include/llvm/CodeGen/LowLevelType.h Wed Jul 20 16:13:29 2016
@@ -67,6 +67,7 @@ public:
   }
 
   /// \brief get an unsized but valid low-level type (e.g. for a label).
+
   static LLT unsized() {
     return LLT{Unsized, 1, 0};
   }

Modified: llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt?rev=276184&r1=276183&r2=276184&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/CMakeLists.txt Wed Jul 20 16:13:29 2016
@@ -2,6 +2,7 @@
 set(GLOBAL_ISEL_FILES
       IRTranslator.cpp
       MachineIRBuilder.cpp
+      MachineLegalizer.cpp
       RegBankSelect.cpp
       RegisterBank.cpp
       RegisterBankInfo.cpp

Added: llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizer.cpp?rev=276184&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizer.cpp (added)
+++ llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizer.cpp Wed Jul 20 16:13:29 2016
@@ -0,0 +1,128 @@
+//===---- lib/CodeGen/GlobalISel/MachineLegalizer.cpp - IRTranslator -------==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement an interface to specify and query how an illegal operation on a
+// given type should be expanded.
+//
+// Issues to be resolved:
+//   + Make it fast.
+//   + Support weird types like i3, <7 x i3>, ...
+//   + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Target/TargetOpcodes.h"
+using namespace llvm;
+
+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;
+    if (!Ty.isVector())
+      continue;
+
+    auto &Entry =
+        MaxLegalVectorElts[std::make_pair(Op.first.first, Ty.getElementType())];
+    Entry = std::max(Entry, Ty.getNumElements());
+  }
+
+  TablesInitialized = true;
+}
+
+// FIXME: inefficient implementation for now. Without ComputeValueVTs we're
+// probably going to need specialized lookup structures for various types before
+// we have any hope of doing well with something like <13 x i3>. Even the common
+// cases should do better than what we have now.
+std::pair<MachineLegalizer::LegalizeAction, LLT>
+MachineLegalizer::getAction(unsigned Opcode, LLT Ty) const {
+  assert(TablesInitialized && "backend forgot to call computeTables");
+  // These *have* to be implemented for now, they're the fundamental basis of
+  // how everything else is transformed.
+
+  auto ActionIt = Actions.find(std::make_pair(Opcode, Ty));
+  if (ActionIt != Actions.end())
+    return findLegalAction(Opcode, Ty, ActionIt->second);
+
+  if (!Ty.isVector()) {
+    auto DefaultAction = DefaultActions.find(Opcode);
+    if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal)
+      return std::make_pair(Legal, Ty);
+
+    assert(DefaultAction->second == NarrowScalar && "unexpected default");
+    return findLegalAction(Opcode, Ty, NarrowScalar);
+  }
+
+  LLT EltTy = Ty.getElementType();
+  int NumElts = Ty.getNumElements();
+
+  auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy));
+  if (ScalarAction != ScalarInVectorActions.end() &&
+      ScalarAction->second != Legal)
+    return findLegalAction(Opcode, EltTy, ScalarAction->second);
+
+  // The element type is legal in principle, but the number of elements is
+  // wrong.
+  auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy));
+  if (MaxLegalElts > NumElts)
+    return findLegalAction(Opcode, Ty, MoreElements);
+
+  if (MaxLegalElts == 0) {
+    // Scalarize if there's no legal vector type, which is just a special case
+    // of FewerElements.
+    return std::make_pair(FewerElements, EltTy);
+  }
+
+  return findLegalAction(Opcode, Ty, FewerElements);
+}
+
+std::pair<MachineLegalizer::LegalizeAction, LLT>
+MachineLegalizer::getAction(MachineInstr &MI) const {
+  return getAction(MI.getOpcode(), MI.getType());
+}
+
+bool MachineLegalizer::isLegal(MachineInstr &MI) const {
+  return getAction(MI).first == Legal;
+}
+
+LLT MachineLegalizer::findLegalType(unsigned Opcode, LLT Ty,
+                                    LegalizeAction Action) const {
+  switch(Action) {
+  default:
+    llvm_unreachable("Cannot find legal type");
+  case Legal:
+    return Ty;
+  case NarrowScalar: {
+    return findLegalType(Opcode, Ty,
+                         [&](LLT Ty) -> LLT { return Ty.halfScalarSize(); });
+  }
+  case WidenScalar: {
+    return findLegalType(Opcode, Ty,
+                         [&](LLT Ty) -> LLT { return Ty.doubleScalarSize(); });
+  }
+  case FewerElements: {
+    return findLegalType(Opcode, Ty,
+                         [&](LLT Ty) -> LLT { return Ty.halfElements(); });
+  }
+  case MoreElements: {
+    return findLegalType(
+        Opcode, Ty, [&](LLT Ty) -> LLT { return Ty.doubleElements(); });
+  }
+  }
+}

Modified: llvm/trunk/unittests/CodeGen/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/CMakeLists.txt?rev=276184&r1=276183&r2=276184&view=diff
==============================================================================
--- llvm/trunk/unittests/CodeGen/CMakeLists.txt (original)
+++ llvm/trunk/unittests/CodeGen/CMakeLists.txt Wed Jul 20 16:13:29 2016
@@ -10,3 +10,5 @@ set(CodeGenSources
 add_llvm_unittest(CodeGenTests
   ${CodeGenSources}
   )
+
+add_subdirectory(GlobalISel)

Added: llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt?rev=276184&view=auto
==============================================================================
--- llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt (added)
+++ llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt Wed Jul 20 16:13:29 2016
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+  GlobalISel
+  )
+
+if(LLVM_BUILD_GLOBAL_ISEL)
+  add_llvm_unittest(GlobalISelTests
+          MachineLegalizerTest.cpp
+          )
+endif()

Added: llvm/trunk/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp?rev=276184&view=auto
==============================================================================
--- llvm/trunk/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp (added)
+++ llvm/trunk/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp Wed Jul 20 16:13:29 2016
@@ -0,0 +1,102 @@
+//===- llvm/unittest/CodeGen/GlobalISel/MachineLegalizerTest.cpp ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h"
+#include "llvm/Target/TargetOpcodes.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using llvm::MachineLegalizer::LegalizeAction::Legal;
+using llvm::MachineLegalizer::LegalizeAction::NarrowScalar;
+using llvm::MachineLegalizer::LegalizeAction::WidenScalar;
+using llvm::MachineLegalizer::LegalizeAction::FewerElements;
+using llvm::MachineLegalizer::LegalizeAction::MoreElements;
+using llvm::MachineLegalizer::LegalizeAction::Libcall;
+using llvm::MachineLegalizer::LegalizeAction::Custom;
+using llvm::MachineLegalizer::LegalizeAction::Unsupported;
+
+// Define a couple of pretty printers to help debugging when things go wrong.
+namespace llvm {
+std::ostream &
+operator<<(std::ostream &OS, const llvm::MachineLegalizer::LegalizeAction Act) {
+  switch (Act) {
+  case Legal: OS << "Legal"; break;
+  case NarrowScalar: OS << "NarrowScalar"; break;
+  case WidenScalar:  OS << "WidenScalar"; break;
+  case FewerElements:  OS << "FewerElements"; break;
+  case MoreElements:  OS << "MoreElements"; break;
+  case Libcall: OS << "Libcall"; break;
+  case Custom: OS << "Custom"; break;
+  case Unsupported: OS << "Unsupported"; break;
+  }
+  return OS;
+}
+
+std::ostream &
+operator<<(std::ostream &OS, const llvm::LLT Ty) {
+  std::string Repr;
+  raw_string_ostream SS{Repr};
+  Ty.print(SS);
+  OS << SS.str();
+  return OS;
+}
+}
+
+namespace {
+
+
+TEST(MachineLegalizerTest, ScalarRISC) {
+  MachineLegalizer L;
+  // Typical RISCy set of operations based on AArch64.
+  L.setAction(TargetOpcode::G_ADD, LLT::scalar(8), WidenScalar);
+  L.setAction(TargetOpcode::G_ADD, LLT::scalar(16), WidenScalar);
+  L.setAction(TargetOpcode::G_ADD, LLT::scalar(32), Legal);
+  L.setAction(TargetOpcode::G_ADD, LLT::scalar(64), Legal);
+  L.computeTables();
+
+  // Check we infer the correct types and actually do what we're told.
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::scalar(8)),
+                        std::make_pair(WidenScalar, LLT::scalar(32)));
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::scalar(16)),
+                        std::make_pair(WidenScalar, LLT::scalar(32)));
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::scalar(32)),
+                        std::make_pair(Legal, LLT::scalar(32)));
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::scalar(64)),
+                        std::make_pair(Legal, LLT::scalar(64)));
+
+  // Make sure the default for over-sized types applies.
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::scalar(128)),
+                        std::make_pair(NarrowScalar, LLT::scalar(64)));
+}
+
+TEST(MachineLegalizerTest, VectorRISC) {
+  MachineLegalizer L;
+  // Typical RISCy set of operations based on ARM.
+  L.setScalarInVectorAction(TargetOpcode::G_ADD, LLT::scalar(8), Legal);
+  L.setScalarInVectorAction(TargetOpcode::G_ADD, LLT::scalar(16), Legal);
+  L.setScalarInVectorAction(TargetOpcode::G_ADD, LLT::scalar(32), Legal);
+
+  L.setAction(TargetOpcode::G_ADD, LLT::vector(8, 8), Legal);
+  L.setAction(TargetOpcode::G_ADD, LLT::vector(16, 8), Legal);
+  L.setAction(TargetOpcode::G_ADD, LLT::vector(4, 16), Legal);
+  L.setAction(TargetOpcode::G_ADD, LLT::vector(8, 16), Legal);
+  L.setAction(TargetOpcode::G_ADD, LLT::vector(2, 32), Legal);
+  L.setAction(TargetOpcode::G_ADD, LLT::vector(4, 32), Legal);
+  L.computeTables();
+
+  // Check we infer the correct types and actually do what we're told for some
+  // simple cases.
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::vector(2, 8)),
+            std::make_pair(MoreElements, LLT::vector(8, 8)));
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::vector(8, 8)),
+            std::make_pair(Legal, LLT::vector(8, 8)));
+  ASSERT_EQ(L.getAction(TargetOpcode::G_ADD, LLT::vector(8, 32)),
+            std::make_pair(FewerElements, LLT::vector(4, 32)));
+}
+}




More information about the llvm-commits mailing list