[llvm] r300964 - [globalisel][tablegen] Import SelectionDAG's rule predicates and support the equivalent in GIRule.

Daniel Sanders via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 21 03:27:20 PDT 2017


Author: dsanders
Date: Fri Apr 21 05:27:20 2017
New Revision: 300964

URL: http://llvm.org/viewvc/llvm-project?rev=300964&view=rev
Log:
[globalisel][tablegen] Import SelectionDAG's rule predicates and support the equivalent in GIRule.

Summary:
The SelectionDAG importer now imports rules with Predicate's attached via
Requires, PredicateControl, etc. These predicates are implemented as
bitset's to allow multiple predicates to be tested together. However,
unlike the MC layer subtarget features, each target only pays for it's own
predicates (e.g. AArch64 doesn't have 192 feature bits just because X86
needs a lot).

Both AArch64 and X86 derive at least one predicate from the MachineFunction
or Function so they must re-initialize AvailableFeatures before each
function. They also declare locals in <Target>InstructionSelector so that
computeAvailableFeatures() can use the code from SelectionDAG without
modification.

Reviewers: rovka, qcolombet, aditya_nandakumar, t.p.northover, ab

Reviewed By: rovka

Subscribers: aemerson, rengolin, dberris, kristof.beyls, llvm-commits, igorb

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

Modified:
    llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
    llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
    llvm/trunk/lib/Target/X86/X86.h
    llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp
    llvm/trunk/lib/Target/X86/X86TargetMachine.cpp
    llvm/trunk/test/TableGen/GlobalISelEmitter.td
    llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp
    llvm/trunk/utils/TableGen/CodeEmitterGen.cpp
    llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
    llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp
    llvm/trunk/utils/TableGen/SubtargetFeatureInfo.h
    llvm/trunk/utils/TableGen/Types.cpp

Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h Fri Apr 21 05:27:20 2017
@@ -18,20 +18,50 @@
 
 #include "llvm/ADT/Optional.h"
 #include <cstdint>
+#include <bitset>
 
 namespace llvm {
 class MachineInstr;
+class MachineFunction;
 class MachineOperand;
 class MachineRegisterInfo;
 class RegisterBankInfo;
 class TargetInstrInfo;
 class TargetRegisterInfo;
 
+/// Container class for CodeGen predicate results.
+/// This is convenient because std::bitset does not have a constructor
+/// with an initializer list of set bits.
+///
+/// Each InstructionSelector subclass should define a PredicateBitset class with:
+///   const unsigned MAX_SUBTARGET_PREDICATES = 192;
+///   using PredicateBitset = PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
+/// and updating the constant to suit the target. Tablegen provides a suitable
+/// definition for the predicates in use in <Target>GenGlobalISel.inc when
+/// GET_GLOBALISEL_PREDICATE_BITSET is defined.
+template <std::size_t MaxPredicates>
+class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
+public:
+  // Cannot inherit constructors because it's not supported by VC++..
+  PredicateBitsetImpl() = default;
+
+  PredicateBitsetImpl(const std::bitset<MaxPredicates> &B)
+      : std::bitset<MaxPredicates>(B) {}
+
+  PredicateBitsetImpl(std::initializer_list<unsigned> Init) {
+    for (auto I : Init)
+      std::bitset<MaxPredicates>::set(I);
+  }
+};
+
 /// Provides the logic to select generic machine instructions.
 class InstructionSelector {
 public:
   virtual ~InstructionSelector() {}
 
+  /// This is executed before selecting a function.
+  virtual void beginFunction(const MachineFunction &MF) {}
+
   /// 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.

Modified: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp Fri Apr 21 05:27:20 2017
@@ -41,12 +41,17 @@ using namespace llvm;
 
 namespace {
 
+#define GET_GLOBALISEL_PREDICATE_BITSET
+#include "AArch64GenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATE_BITSET
+
 class AArch64InstructionSelector : public InstructionSelector {
 public:
   AArch64InstructionSelector(const AArch64TargetMachine &TM,
                              const AArch64Subtarget &STI,
                              const AArch64RegisterBankInfo &RBI);
 
+  void beginFunction(const MachineFunction &MF) override;
   bool select(MachineInstr &I) const override;
 
 private:
@@ -70,6 +75,12 @@ private:
   const AArch64InstrInfo &TII;
   const AArch64RegisterInfo &TRI;
   const AArch64RegisterBankInfo &RBI;
+  bool ForCodeSize;
+
+  PredicateBitset AvailableFeatures;
+  PredicateBitset
+  computeAvailableFeatures(const MachineFunction *MF,
+                           const AArch64Subtarget *Subtarget) const;
 
 // We declare the temporaries used by selectImpl() in the class to minimize the
 // cost of constructing placeholder values.
@@ -88,7 +99,7 @@ AArch64InstructionSelector::AArch64Instr
     const AArch64TargetMachine &TM, const AArch64Subtarget &STI,
     const AArch64RegisterBankInfo &RBI)
     : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
-      TRI(*STI.getRegisterInfo()), RBI(RBI)
+      TRI(*STI.getRegisterInfo()), RBI(RBI), ForCodeSize(), AvailableFeatures()
 #define GET_GLOBALISEL_TEMPORARIES_INIT
 #include "AArch64GenGlobalISel.inc"
 #undef GET_GLOBALISEL_TEMPORARIES_INIT
@@ -567,6 +578,12 @@ bool AArch64InstructionSelector::selectV
   return true;
 }
 
+void AArch64InstructionSelector::beginFunction(
+    const MachineFunction &MF) {
+  ForCodeSize = MF.getFunction()->optForSize();
+  AvailableFeatures = computeAvailableFeatures(&MF, &STI);
+}
+
 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!");

Modified: llvm/trunk/lib/Target/X86/X86.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86.h?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86.h (original)
+++ llvm/trunk/lib/Target/X86/X86.h Fri Apr 21 05:27:20 2017
@@ -95,7 +95,8 @@ void initializeFixupBWInstPassPass(PassR
 /// encoding when possible in order to reduce code size.
 FunctionPass *createX86EvexToVexInsts();
 
-InstructionSelector *createX86InstructionSelector(X86Subtarget &,
+InstructionSelector *createX86InstructionSelector(const X86TargetMachine &TM,
+                                                  X86Subtarget &,
                                                   X86RegisterBankInfo &);
 
 void initializeEvexToVexInstPassPass(PassRegistry &);

Modified: llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp Fri Apr 21 05:27:20 2017
@@ -39,11 +39,16 @@ using namespace llvm;
 
 namespace {
 
+#define GET_GLOBALISEL_PREDICATE_BITSET
+#include "X86GenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATE_BITSET
+
 class X86InstructionSelector : public InstructionSelector {
 public:
-  X86InstructionSelector(const X86Subtarget &STI,
+  X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI,
                          const X86RegisterBankInfo &RBI);
 
+  void beginFunction(const MachineFunction &MF) override;
   bool select(MachineInstr &I) const override;
 
 private:
@@ -70,10 +75,17 @@ private:
   bool selectTrunc(MachineInstr &I, MachineRegisterInfo &MRI,
                    MachineFunction &MF) const;
 
+  const X86TargetMachine &TM;
   const X86Subtarget &STI;
   const X86InstrInfo &TII;
   const X86RegisterInfo &TRI;
   const X86RegisterBankInfo &RBI;
+  bool OptForSize;
+  bool OptForMinSize;
+
+  PredicateBitset AvailableFeatures;
+  PredicateBitset computeAvailableFeatures(const MachineFunction *MF,
+                                           const X86Subtarget *Subtarget) const;
 
 #define GET_GLOBALISEL_TEMPORARIES_DECL
 #include "X86GenGlobalISel.inc"
@@ -86,10 +98,12 @@ private:
 #include "X86GenGlobalISel.inc"
 #undef GET_GLOBALISEL_IMPL
 
-X86InstructionSelector::X86InstructionSelector(const X86Subtarget &STI,
+X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM,
+                                               const X86Subtarget &STI,
                                                const X86RegisterBankInfo &RBI)
-    : InstructionSelector(), STI(STI), TII(*STI.getInstrInfo()),
-      TRI(*STI.getRegisterInfo()), RBI(RBI)
+    : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
+      TRI(*STI.getRegisterInfo()), RBI(RBI), OptForSize(false),
+      OptForMinSize(false), AvailableFeatures()
 #define GET_GLOBALISEL_TEMPORARIES_INIT
 #include "X86GenGlobalISel.inc"
 #undef GET_GLOBALISEL_TEMPORARIES_INIT
@@ -181,6 +195,12 @@ static bool selectCopy(MachineInstr &I,
   return true;
 }
 
+void X86InstructionSelector::beginFunction(const MachineFunction &MF) {
+  OptForSize = MF.getFunction()->optForSize();
+  OptForMinSize = MF.getFunction()->optForMinSize();
+  AvailableFeatures = computeAvailableFeatures(&MF, &STI);
+}
+
 bool X86InstructionSelector::select(MachineInstr &I) const {
   assert(I.getParent() && "Instruction should be in a basic block!");
   assert(I.getParent()->getParent() && "Instruction should be in a function!");
@@ -571,7 +591,8 @@ bool X86InstructionSelector::selectTrunc
 }
 
 InstructionSelector *
-llvm::createX86InstructionSelector(X86Subtarget &Subtarget,
+llvm::createX86InstructionSelector(const X86TargetMachine &TM,
+                                   X86Subtarget &Subtarget,
                                    X86RegisterBankInfo &RBI) {
-  return new X86InstructionSelector(Subtarget, RBI);
+  return new X86InstructionSelector(TM, Subtarget, RBI);
 }

Modified: llvm/trunk/lib/Target/X86/X86TargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetMachine.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86TargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86TargetMachine.cpp Fri Apr 21 05:27:20 2017
@@ -286,7 +286,7 @@ X86TargetMachine::getSubtargetImpl(const
 
     auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo());
     GISel->RegBankInfo.reset(RBI);
-    GISel->InstSelector.reset(createX86InstructionSelector(*I, *RBI));
+    GISel->InstSelector.reset(createX86InstructionSelector(*this, *I, *RBI));
 #endif
     I->setGISelAccessor(*GISel);
   }

Modified: llvm/trunk/test/TableGen/GlobalISelEmitter.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/GlobalISelEmitter.td (original)
+++ llvm/trunk/test/TableGen/GlobalISelEmitter.td Fri Apr 21 05:27:20 2017
@@ -29,7 +29,31 @@ def m1 : OperandWithDefaultOps <i32, (op
 def Z : OperandWithDefaultOps <i32, (ops R0)>;
 def m1Z : OperandWithDefaultOps <i32, (ops (i32 -1), R0)>;
 
-//===- Test the function definition boilerplate. --------------------------===//
+def HasA : Predicate<"Subtarget->hasA()">;
+def HasB : Predicate<"Subtarget->hasB()">;
+
+//===- Test the function boilerplate. -------------------------------------===//
+
+// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
+// CHECK-NEXT:    Feature_HasABit = 0,
+// CHECK-NEXT:    Feature_HasBBit = 1,
+// CHECK-NEXT:  };
+
+// CHECK-LABEL: static const char *SubtargetFeatureNames[] = {
+// CHECK-NEXT:    "Feature_HasA",
+// CHECK-NEXT:    "Feature_HasB",
+// CHECK-NEXT:    nullptr
+// CHECK-NEXT:  };
+
+// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector::
+// CHECK-NEXT:  computeAvailableFeatures(const MachineFunction *MF, const MyTargetSubtarget *Subtarget) const {
+// CHECK-NEXT:    PredicateBitset Features;
+// CHECK-NEXT:    if (Subtarget->hasA())
+// CHECK-NEXT:      Features[Feature_HasABit] = 1;
+// CHECK-NEXT:    if (Subtarget->hasB())
+// CHECK-NEXT:      Features[Feature_HasBBit] = 1;
+// CHECK-NEXT:    return Features;
+// CHECK-NEXT:  }
 
 // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const {
 // CHECK: MachineFunction &MF = *I.getParent()->getParent();
@@ -103,6 +127,9 @@ def ADD : I<(outs GPR32:$dst), (ins GPR3
 //===- Test a nested instruction match. -----------------------------------===//
 
 // CHECK-LABEL: if ([&]() {
+// CHECK-NEXT:    PredicateBitset ExpectedFeatures = {Feature_HasABit};
+// CHECK-NEXT:    if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
+// CHECK-NEXT:      return false;
 // CHECK-NEXT:    MachineInstr &MI0 = I;
 // CHECK-NEXT:    if (MI0.getNumOperands() < 3)
 // CHECK-NEXT:      return false;
@@ -142,6 +169,9 @@ def ADD : I<(outs GPR32:$dst), (ins GPR3
 
 // We also get a second rule by commutativity.
 // CHECK-LABEL: if ([&]() {
+// CHECK-NEXT:    PredicateBitset ExpectedFeatures = {Feature_HasABit};
+// CHECK-NEXT:    if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
+// CHECK-NEXT:      return false;
 // CHECK-NEXT:    MachineInstr &MI0 = I;
 // CHECK-NEXT:    if (MI0.getNumOperands() < 3)
 // CHECK-NEXT:      return false;
@@ -181,11 +211,15 @@ def ADD : I<(outs GPR32:$dst), (ins GPR3
 
 def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
                [(set GPR32:$dst,
-                     (mul (add GPR32:$src1, GPR32:$src2), GPR32:$src3))]>;
+                     (mul (add GPR32:$src1, GPR32:$src2), GPR32:$src3))]>,
+             Requires<[HasA]>;
 
 //===- Test another simple pattern with regclass operands. ----------------===//
 
 // CHECK-LABEL: if ([&]() {
+// CHECK-NEXT:    PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit};
+// CHECK-NEXT:    if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
+// CHECK-NEXT:      return false;
 // CHECK-NEXT:    MachineInstr &MI0 = I;
 // CHECK-NEXT:    if (MI0.getNumOperands() < 3)
 // CHECK-NEXT:      return false;
@@ -213,7 +247,8 @@ def MULADD : I<(outs GPR32:$dst), (ins G
 // CHECK-NEXT:  }()) { return true; }
 
 def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
-             [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>;
+             [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>,
+          Requires<[HasA, HasB]>;
 
 //===- Test a pattern with ComplexPattern operands. -----------------------===//
 //

Modified: llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp Fri Apr 21 05:27:20 2017
@@ -2861,7 +2861,7 @@ void AsmMatcherEmitter::run(raw_ostream
   emitValidateOperandClass(Info, OS);
 
   // Emit the available features compute function.
-  SubtargetFeatureInfo::emitComputeAvailableFeatures(
+  SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
       Info.Target.getName(), ClassName, "ComputeAvailableFeatures",
       Info.SubtargetFeatures, OS);
 

Modified: llvm/trunk/utils/TableGen/CodeEmitterGen.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeEmitterGen.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeEmitterGen.cpp (original)
+++ llvm/trunk/utils/TableGen/CodeEmitterGen.cpp Fri Apr 21 05:27:20 2017
@@ -336,7 +336,7 @@ void CodeEmitterGen::run(raw_ostream &o)
   o << "#endif // NDEBUG\n";
 
   // Emit the available features compute function.
-  SubtargetFeatureInfo::emitComputeAvailableFeatures(
+  SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
       Target.getName(), "MCCodeEmitter", "computeAvailableFeatures",
       SubtargetFeatures, o);
 

Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Fri Apr 21 05:27:20 2017
@@ -31,6 +31,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CodeGenDAGPatterns.h"
+#include "SubtargetFeatureInfo.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
@@ -161,20 +162,6 @@ static std::string explainPredicates(con
   return Explanation;
 }
 
-static std::string explainRulePredicates(const ArrayRef<Init *> Predicates) {
-  std::string Explanation = "";
-  StringRef Separator = "";
-  for (const auto *P : Predicates) {
-    Explanation += Separator;
-
-    if (const DefInit *PDef = dyn_cast<DefInit>(P)) {
-      Explanation += PDef->getDef()->getName();
-    } else
-      Explanation += "<unknown>";
-  }
-  return Explanation;
-}
-
 std::string explainOperator(Record *Operator) {
   if (Operator->isSubClassOf("SDNode"))
     return " (" + Operator->getValueAsString("Opcode") + ")";
@@ -238,6 +225,8 @@ class RuleMatcher {
   /// ID for the next instruction variable defined with defineInsnVar()
   unsigned NextInsnVarID;
 
+  std::vector<Record *> RequiredFeatures;
+
 public:
   RuleMatcher()
       : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {}
@@ -245,6 +234,7 @@ public:
   RuleMatcher &operator=(RuleMatcher &&Other) = default;
 
   InstructionMatcher &addInstructionMatcher();
+  void addRequiredFeature(Record *Feature);
 
   template <class Kind, class... Args> Kind &addAction(Args &&... args);
 
@@ -255,7 +245,9 @@ public:
   void emitCxxCapturedInsnList(raw_ostream &OS);
   void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr);
 
-  void emit(raw_ostream &OS);
+  void emit(raw_ostream &OS,
+            std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
+                SubtargetFeatures);
 
   /// Compare the priority of this object and B.
   ///
@@ -1092,6 +1084,10 @@ InstructionMatcher &RuleMatcher::addInst
   return *Matchers.back();
 }
 
+void RuleMatcher::addRequiredFeature(Record *Feature) {
+  RequiredFeatures.push_back(Feature);
+}
+
 template <class Kind, class... Args>
 Kind &RuleMatcher::addAction(Args &&... args) {
   Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...));
@@ -1135,7 +1131,9 @@ void RuleMatcher::emitCxxCaptureStmts(ra
   Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName);
 }
 
-void RuleMatcher::emit(raw_ostream &OS) {
+void RuleMatcher::emit(raw_ostream &OS,
+                       std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
+                           SubtargetFeatures) {
   if (Matchers.empty())
     llvm_unreachable("Unexpected empty matcher!");
 
@@ -1149,7 +1147,22 @@ void RuleMatcher::emit(raw_ostream &OS)
   //    %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr
   // on some targets but we don't need to make use of that yet.
   assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
-  OS << "if ([&]() {\n";
+
+  OS << "if (";
+  OS << "[&]() {\n";
+  if (!RequiredFeatures.empty()) {
+    OS << "  PredicateBitset ExpectedFeatures = {";
+    StringRef Separator = "";
+    for (const auto &Predicate : RequiredFeatures) {
+      const auto &I = SubtargetFeatures.find(Predicate);
+      assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
+      OS << Separator << I->second.getEnumBitName();
+      Separator = ", ";
+    }
+    OS << "};\n";
+    OS << "if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)\n"
+       << "  return false;\n";
+  }
 
   emitCxxCaptureStmts(OS, "I");
 
@@ -1264,10 +1277,13 @@ private:
   /// GIComplexPatternEquiv.
   DenseMap<const Record *, const Record *> ComplexPatternEquivs;
 
+  // Map of predicates to their subtarget features.
+  std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
+
   void gatherNodeEquivs();
   const CodeGenInstruction *findNodeEquiv(Record *N) const;
 
-  Error importRulePredicates(RuleMatcher &M, ArrayRef<Init *> Predicates) const;
+  Error importRulePredicates(RuleMatcher &M, ArrayRef<Init *> Predicates);
   Expected<InstructionMatcher &>
   createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher,
                                const TreePatternNode *Src) const;
@@ -1287,6 +1303,8 @@ private:
   /// Analyze pattern \p P, returning a matcher for it if possible.
   /// Otherwise, return an Error explaining why we don't support it.
   Expected<RuleMatcher> runOnPattern(const PatternToMatch &P);
+
+  void declareSubtargetFeature(Record *Predicate);
 };
 
 void GlobalISelEmitter::gatherNodeEquivs() {
@@ -1315,10 +1333,13 @@ GlobalISelEmitter::GlobalISelEmitter(Rec
 
 Error
 GlobalISelEmitter::importRulePredicates(RuleMatcher &M,
-                                        ArrayRef<Init *> Predicates) const {
-  if (!Predicates.empty())
-    return failedImport("Pattern has a rule predicate (" +
-                        explainRulePredicates(Predicates) + ")");
+                                        ArrayRef<Init *> Predicates) {
+  for (const Init *Predicate : Predicates) {
+    const DefInit *PredicateDef = static_cast<const DefInit *>(Predicate);
+    declareSubtargetFeature(PredicateDef->getDef());
+    M.addRequiredFeature(PredicateDef->getDef());
+  }
+
   return Error::success();
 }
 
@@ -1725,6 +1746,13 @@ void GlobalISelEmitter::run(raw_ostream
   for (const auto &Rule : Rules)
     MaxTemporaries = std::max(MaxTemporaries, Rule.countTemporaryOperands());
 
+  OS << "#ifdef GET_GLOBALISEL_PREDICATE_BITSET\n"
+     << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size()
+     << ";\n"
+     << "using PredicateBitset = "
+        "PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n"
+     << "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n";
+
   OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n";
   for (unsigned I = 0; I < MaxTemporaries; ++I)
     OS << "  mutable MachineOperand TempOp" << I << ";\n";
@@ -1735,14 +1763,21 @@ void GlobalISelEmitter::run(raw_ostream
     OS << ", TempOp" << I << "(MachineOperand::CreatePlaceholder())\n";
   OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
 
-  OS << "#ifdef GET_GLOBALISEL_IMPL\n"
-     << "bool " << Target.getName()
+  OS << "#ifdef GET_GLOBALISEL_IMPL\n";
+  SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
+                                                           OS);
+  SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS);
+  SubtargetFeatureInfo::emitComputeAvailableFeatures(
+      Target.getName(), "InstructionSelector", "computeAvailableFeatures",
+      SubtargetFeatures, OS);
+
+  OS << "bool " << Target.getName()
      << "InstructionSelector::selectImpl(MachineInstr &I) const {\n"
      << "  MachineFunction &MF = *I.getParent()->getParent();\n"
      << "  const MachineRegisterInfo &MRI = MF.getRegInfo();\n";
 
   for (auto &Rule : Rules) {
-    Rule.emit(OS);
+    Rule.emit(OS, SubtargetFeatures);
     ++NumPatternEmitted;
   }
 
@@ -1751,6 +1786,12 @@ void GlobalISelEmitter::run(raw_ostream
      << "#endif // ifdef GET_GLOBALISEL_IMPL\n";
 }
 
+void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) {
+  if (SubtargetFeatures.count(Predicate) == 0)
+    SubtargetFeatures.emplace(
+        Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size()));
+}
+
 } // end anonymous namespace
 
 //===----------------------------------------------------------------------===//

Modified: llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp (original)
+++ llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp Fri Apr 21 05:27:20 2017
@@ -59,6 +59,20 @@ void SubtargetFeatureInfo::emitSubtarget
   OS << "};\n\n";
 }
 
+void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
+    std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures,
+    raw_ostream &OS) {
+  OS << "// Bits for subtarget features that participate in "
+     << "instruction matching.\n";
+  OS << "enum SubtargetFeatureBits : "
+     << getMinimalTypeForRange(SubtargetFeatures.size()) << " {\n";
+  for (const auto &SF : SubtargetFeatures) {
+    const SubtargetFeatureInfo &SFI = SF.second;
+    OS << "  " << SFI.getEnumBitName() << " = " << SFI.Index << ",\n";
+  }
+  OS << "};\n\n";
+}
+
 void SubtargetFeatureInfo::emitNameTable(
     std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures,
     raw_ostream &OS) {
@@ -90,6 +104,24 @@ void SubtargetFeatureInfo::emitComputeAv
     StringRef TargetName, StringRef ClassName, StringRef FuncName,
     std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures,
     raw_ostream &OS) {
+  OS << "PredicateBitset " << TargetName << ClassName << "::\n"
+     << FuncName << "(const MachineFunction *MF, const " << TargetName
+     << "Subtarget *Subtarget) const {\n";
+  OS << "  PredicateBitset Features;\n";
+  for (const auto &SF : SubtargetFeatures) {
+    const SubtargetFeatureInfo &SFI = SF.second;
+
+    OS << "  if (" << SFI.TheDef->getValueAsString("CondString") << ")\n";
+    OS << "    Features[" << SFI.getEnumBitName() << "] = 1;\n";
+  }
+  OS << "  return Features;\n";
+  OS << "}\n\n";
+}
+
+void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
+    StringRef TargetName, StringRef ClassName, StringRef FuncName,
+    std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures,
+    raw_ostream &OS) {
   OS << "uint64_t " << TargetName << ClassName << "::\n"
      << FuncName << "(const FeatureBitset& FB) const {\n";
   OS << "  uint64_t Features = 0;\n";

Modified: llvm/trunk/utils/TableGen/SubtargetFeatureInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/SubtargetFeatureInfo.h?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/SubtargetFeatureInfo.h (original)
+++ llvm/trunk/utils/TableGen/SubtargetFeatureInfo.h Fri Apr 21 05:27:20 2017
@@ -37,16 +37,34 @@ struct SubtargetFeatureInfo {
     return "Feature_" + TheDef->getName().str();
   }
 
+  /// \brief The name of the enumerated constant identifying the bitnumber for
+  /// this feature.
+  std::string getEnumBitName() const {
+    return "Feature_" + TheDef->getName().str() + "Bit";
+  }
+
   void dump() const;
   static std::vector<std::pair<Record *, SubtargetFeatureInfo>>
   getAll(const RecordKeeper &Records);
 
   /// Emit the subtarget feature flag definitions.
+  ///
+  /// This version emits the bit value for the feature and is therefore limited
+  /// to 64 feature bits.
   static void emitSubtargetFeatureFlagEnumeration(
       std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
           &SubtargetFeatures,
       raw_ostream &OS);
 
+  /// Emit the subtarget feature flag definitions.
+  ///
+  /// This version emits the bit index for the feature and can therefore support
+  /// more than 64 feature bits.
+  static void emitSubtargetFeatureBitEnumeration(
+      std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
+          &SubtargetFeatures,
+      raw_ostream &OS);
+
   static void emitNameTable(std::map<Record *, SubtargetFeatureInfo,
                                      LessRecordByID> &SubtargetFeatures,
                             raw_ostream &OS);
@@ -54,6 +72,9 @@ struct SubtargetFeatureInfo {
   /// Emit the function to compute the list of available features given a
   /// subtarget.
   ///
+  /// This version is used for subtarget features defined using Predicate<>
+  /// and supports more than 64 feature bits.
+  ///
   /// \param TargetName The name of the target as used in class prefixes (e.g.
   ///                   <TargetName>Subtarget)
   /// \param ClassName  The name of the class (without the <Target> prefix)
@@ -65,6 +86,25 @@ struct SubtargetFeatureInfo {
       StringRef TargetName, StringRef ClassName, StringRef FuncName,
       std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
           &SubtargetFeatures,
+      raw_ostream &OS);
+
+  /// Emit the function to compute the list of available features given a
+  /// subtarget.
+  ///
+  /// This version is used for subtarget features defined using
+  /// AssemblerPredicate<> and supports up to 64 feature bits.
+  ///
+  /// \param TargetName The name of the target as used in class prefixes (e.g.
+  ///                   <TargetName>Subtarget)
+  /// \param ClassName  The name of the class (without the <Target> prefix)
+  ///                   that will contain the generated functions.
+  /// \param FuncName   The name of the function to emit.
+  /// \param SubtargetFeatures A map of TableGen records to the
+  ///                          SubtargetFeatureInfo equivalent.
+  static void emitComputeAssemblerAvailableFeatures(
+      StringRef TargetName, StringRef ClassName, StringRef FuncName,
+      std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
+          &SubtargetFeatures,
       raw_ostream &OS);
 };
 } // end namespace llvm

Modified: llvm/trunk/utils/TableGen/Types.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/Types.cpp?rev=300964&r1=300963&r2=300964&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/Types.cpp (original)
+++ llvm/trunk/utils/TableGen/Types.cpp Fri Apr 21 05:27:20 2017
@@ -40,5 +40,6 @@ const char *llvm::getMinimalTypeForEnumB
   uint64_t MaxIndex = Size;
   if (MaxIndex > 0)
     MaxIndex--;
+  assert(MaxIndex <= 64 && "Too many bits");
   return getMinimalTypeForRange(1ULL << MaxIndex);
 }




More information about the llvm-commits mailing list