[llvm] [TabeGen] Add `PreferSmallerInstructions` for Targets. (PR #83587)

Alfie Richards via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 4 00:52:39 PST 2024


https://github.com/AlfieRichardsArm updated https://github.com/llvm/llvm-project/pull/83587

>From 505a547219b533bcdc632a05456757ea86dc8b22 Mon Sep 17 00:00:00 2001
From: Alfie Richards <alfie.richards at arm.com>
Date: Fri, 1 Mar 2024 14:42:43 +0000
Subject: [PATCH] [TabeGen] Add `PreferSmallerInstructions` for Targets.

This option means that in assembly matching instructions with smaller
encodings will be preferred.

This will be used for the ARM instruciton set where this is the correct
behaviour after some other refactoring.
---
 llvm/include/llvm/Target/Target.td        |  5 +++
 llvm/utils/TableGen/AsmMatcherEmitter.cpp | 38 +++++++++++++++++------
 llvm/utils/TableGen/CodeGenTarget.cpp     |  4 +++
 llvm/utils/TableGen/CodeGenTarget.h       |  5 +++
 4 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 0d97a47190b196..7f2a6c96189f8d 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1724,6 +1724,11 @@ class Target {
   // setting hasExtraDefRegAllocReq and hasExtraSrcRegAllocReq to 1
   // for all opcodes if this flag is set to 0.
   int AllowRegisterRenaming = 0;
+
+  // PreferSmallerInstructions - Should the assembly matcher prefer the smaller
+  // instructions. 1 if the instruction set should sort by size,
+  // 0 otherwise.
+  bit PreferSmallerInstructions = 0;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index febd96086df27b..6b32d19860d149 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -502,6 +502,9 @@ struct MatchableInfo {
   /// matchable came from.
   Record *const TheDef;
 
+  // ResInstSize - The size of the resulting instruction for this matchable.
+  unsigned ResInstSize;
+
   /// DefRec - This is the definition that it came from.
   PointerUnion<const CodeGenInstruction *, const CodeGenInstAlias *> DefRec;
 
@@ -543,10 +546,12 @@ struct MatchableInfo {
 
   MatchableInfo(const CodeGenInstruction &CGI)
       : AsmVariantID(0), AsmString(CGI.AsmString), TheDef(CGI.TheDef),
-        DefRec(&CGI), UseInstAsmMatchConverter(true) {}
+        ResInstSize(TheDef->getValueAsInt("Size")), DefRec(&CGI),
+        UseInstAsmMatchConverter(true) {}
 
   MatchableInfo(std::unique_ptr<const CodeGenInstAlias> Alias)
       : AsmVariantID(0), AsmString(Alias->AsmString), TheDef(Alias->TheDef),
+        ResInstSize(Alias->ResultInst->TheDef->getValueAsInt("Size")),
         DefRec(Alias.release()), UseInstAsmMatchConverter(TheDef->getValueAsBit(
                                      "UseInstAsmMatchConverter")) {}
 
@@ -608,12 +613,18 @@ struct MatchableInfo {
   void buildInstructionResultOperands();
   void buildAliasResultOperands(bool AliasConstraintsAreChecked);
 
-  /// operator< - Compare two matchables.
-  bool operator<(const MatchableInfo &RHS) const {
+  /// shouldBeMatchedBefore - Compare two matchables for ordering.
+  bool shouldBeMatchedBefore(const MatchableInfo &RHS,
+                             const CodeGenTarget &Target) const {
     // The primary comparator is the instruction mnemonic.
     if (int Cmp = Mnemonic.compare_insensitive(RHS.Mnemonic))
       return Cmp == -1;
 
+    // Sort by the resultant instuctions size, eg. for ARM instructions
+    // we must choose the smallest matching instruction.
+    if (Target.getPreferSmallerInstructions() && ResInstSize != RHS.ResInstSize)
+      return ResInstSize < RHS.ResInstSize;
+
     if (AsmOperands.size() != RHS.AsmOperands.size())
       return AsmOperands.size() < RHS.AsmOperands.size();
 
@@ -652,7 +663,8 @@ struct MatchableInfo {
   /// couldMatchAmbiguouslyWith - Check whether this matchable could
   /// ambiguously match the same set of operands as \p RHS (without being a
   /// strictly superior match).
-  bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) const {
+  bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS,
+                                 const CodeGenTarget &Target) const {
     // The primary comparator is the instruction mnemonic.
     if (Mnemonic != RHS.Mnemonic)
       return false;
@@ -661,6 +673,11 @@ struct MatchableInfo {
     if (AsmVariantID != RHS.AsmVariantID)
       return false;
 
+    // Sort by the resultant instuctions size, eg. for ARM instructions
+    // we must choose the smallest matching instruction.
+    if (Target.getPreferSmallerInstructions() && ResInstSize != RHS.ResInstSize)
+      return false;
+
     // The number of operands is unambiguous.
     if (AsmOperands.size() != RHS.AsmOperands.size())
       return false;
@@ -3224,17 +3241,18 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   // Sort the instruction table using the partial order on classes. We use
   // stable_sort to ensure that ambiguous instructions are still
   // deterministically ordered.
-  llvm::stable_sort(
-      Info.Matchables,
-      [](const std::unique_ptr<MatchableInfo> &a,
-         const std::unique_ptr<MatchableInfo> &b) { return *a < *b; });
+  llvm::stable_sort(Info.Matchables,
+                    [&Target](const std::unique_ptr<MatchableInfo> &a,
+                              const std::unique_ptr<MatchableInfo> &b) {
+                      return a->shouldBeMatchedBefore(*b, Target);
+                    });
 
 #ifdef EXPENSIVE_CHECKS
   // Verify that the table is sorted and operator < works transitively.
   for (auto I = Info.Matchables.begin(), E = Info.Matchables.end(); I != E;
        ++I) {
     for (auto J = I; J != E; ++J) {
-      assert(!(**J < **I));
+      assert(!((*J)->shouldBeMatchedBefore(**I, Target)));
     }
   }
 #endif
@@ -3253,7 +3271,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
         const MatchableInfo &A = **I;
         const MatchableInfo &B = **J;
 
-        if (A.couldMatchAmbiguouslyWith(B)) {
+        if (A.couldMatchAmbiguouslyWith(B, Target)) {
           errs() << "warning: ambiguous matchables:\n";
           A.dump();
           errs() << "\nis incomparable with:\n";
diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp
index 980c9bdb6367f7..9dea19188b6f0e 100644
--- a/llvm/utils/TableGen/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/CodeGenTarget.cpp
@@ -332,6 +332,10 @@ bool CodeGenTarget::getAllowRegisterRenaming() const {
   return TargetRec->getValueAsInt("AllowRegisterRenaming");
 }
 
+bool CodeGenTarget::getPreferSmallerInstructions() const {
+  return TargetRec->getValueAsBit("PreferSmallerInstructions");
+}
+
 /// getAsmParser - Return the AssemblyParser definition for this target.
 ///
 Record *CodeGenTarget::getAsmParser() const {
diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h
index 2ae3a3a2204dd0..36bebf0760a2b2 100644
--- a/llvm/utils/TableGen/CodeGenTarget.h
+++ b/llvm/utils/TableGen/CodeGenTarget.h
@@ -99,6 +99,11 @@ class CodeGenTarget {
   ///
   bool getAllowRegisterRenaming() const;
 
+  /// getPreferSmallerInstructions  - Return the PreferSmallerInstructions
+  /// flag value for this target.
+  ///
+  bool getPreferSmallerInstructions() const;
+
   /// getAsmParser - Return the AssemblyParser definition for this target.
   ///
   Record *getAsmParser() const;



More information about the llvm-commits mailing list