[clang] f6ea026 - [SveEmitter] Fix encoding/decoding of SVETypeFlags

Sander de Smalen via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 14 07:51:17 PDT 2020


Author: Sander de Smalen
Date: 2020-04-14T15:48:28+01:00
New Revision: f6ea026f179a02cd335d71e4800b4d67c25c006b

URL: https://github.com/llvm/llvm-project/commit/f6ea026f179a02cd335d71e4800b4d67c25c006b
DIFF: https://github.com/llvm/llvm-project/commit/f6ea026f179a02cd335d71e4800b4d67c25c006b.diff

LOG: [SveEmitter] Fix encoding/decoding of SVETypeFlags

Summary:
This issue was introduced when reworking D75861. The bug isn't
actually hit with current unit tests because the contiguous loads/stores
infer the EltType and the MemEltType from the pointer and result, rather
than using the flags. But it will be needed for other intrinsics, such as
gather/scatter.

Reviewers: SjoerdMeijer, Andrzej

Reviewed By: SjoerdMeijer

Subscribers: andwar, tschuett, cfe-commits, llvm-commits

Tags: #clang

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

Added: 
    

Modified: 
    clang/include/clang/Basic/TargetBuiltins.h
    clang/include/clang/Basic/arm_sve.td
    clang/utils/TableGen/SveEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 99af2412426f..468167957974 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -17,6 +17,7 @@
 
 #include <stdint.h>
 #include "clang/Basic/Builtins.h"
+#include "llvm/Support/MathExtras.h"
 #undef PPC
 
 namespace clang {
@@ -163,6 +164,9 @@ namespace clang {
   /// Flags to identify the types for overloaded SVE builtins.
   class SVETypeFlags {
     uint64_t Flags;
+    unsigned EltTypeShift;
+    unsigned MemEltTypeShift;
+    unsigned MergeTypeShift;
 
   public:
 #define LLVM_GET_SVE_TYPEFLAGS
@@ -181,15 +185,27 @@ namespace clang {
 #undef LLVM_GET_SVE_MEMELTTYPES
     };
 
-    SVETypeFlags(uint64_t F) : Flags(F) {}
-    SVETypeFlags(EltType ET, bool IsUnsigned) : Flags(ET) {}
+    enum MergeType {
+#define LLVM_GET_SVE_MERGETYPES
+#include "clang/Basic/arm_sve_typeflags.inc"
+#undef LLVM_GET_SVE_MERGETYPES
+    };
+    SVETypeFlags(uint64_t F) : Flags(F) {
+      EltTypeShift = llvm::countTrailingZeros(EltTypeMask);
+      MemEltTypeShift = llvm::countTrailingZeros(MemEltTypeMask);
+      MergeTypeShift = llvm::countTrailingZeros(MergeTypeMask);
+    }
 
     EltType getEltType() const {
-      return (EltType)((Flags & EltTypeMask) - FirstEltType);
+      return (EltType)((Flags & EltTypeMask) >> EltTypeShift);
     }
 
     MemEltType getMemEltType() const {
-      return (MemEltType)((Flags & MemEltTypeMask) - FirstMemEltType);
+      return (MemEltType)((Flags & MemEltTypeMask) >> MemEltTypeShift);
+    }
+
+    MergeType getMergeType() const {
+      return (MergeType)((Flags & MergeTypeMask) >> MergeTypeShift);
     }
 
     bool isLoad() const { return Flags & IsLoad; }

diff  --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td
index 4e75d0339b5c..9ed4ae86e1b7 100644
--- a/clang/include/clang/Basic/arm_sve.td
+++ b/clang/include/clang/Basic/arm_sve.td
@@ -84,15 +84,16 @@
 // Y: const pointer to uint32_t
 // Z: const pointer to uint64_t
 
-class MergeType<int val> {
+class MergeType<int val, string suffix=""> {
   int Value = val;
+  string Suffix = suffix;
 }
 def MergeNone    : MergeType<0>;
-def MergeAny     : MergeType<1>;
-def MergeOp1     : MergeType<2>;
-def MergeZero    : MergeType<3>;
-def MergeAnyExp  : MergeType<4>; // Use merged builtin with explicit
-def MergeZeroExp : MergeType<5>; // generation of its inactive argument.
+def MergeAny     : MergeType<1, "_x">;
+def MergeOp1     : MergeType<2, "_m">;
+def MergeZero    : MergeType<3, "_z">;
+def MergeAnyExp  : MergeType<4, "_x">; // Use merged builtin with explicit
+def MergeZeroExp : MergeType<5, "_z">; // generation of its inactive argument.
 
 class EltType<int val> {
   int Value = val;
@@ -134,13 +135,17 @@ def FirstMemEltType           : FlagType<0x00000010>;
 //      :                                     :
 //      :                                     :
 def MemEltTypeMask            : FlagType<0x00000070>;
-def IsLoad                    : FlagType<0x00000080>;
-def IsStore                   : FlagType<0x00000100>;
-def IsGatherLoad              : FlagType<0x00000200>;
-def IsScatterStore            : FlagType<0x00000400>;
-def IsStructLoad              : FlagType<0x00000800>;
-def IsStructStore             : FlagType<0x00001000>;
-def IsZExtReturn              : FlagType<0x00002000>; // Return value is sign-extend by default
+def FirstMergeTypeMask        : FlagType<0x00000080>;
+//      :                                     :
+//      :                                     :
+def MergeTypeMask             : FlagType<0x00000380>;
+def IsLoad                    : FlagType<0x00002000>;
+def IsStore                   : FlagType<0x00004000>;
+def IsGatherLoad              : FlagType<0x00008000>;
+def IsScatterStore            : FlagType<0x00010000>;
+def IsStructLoad              : FlagType<0x00020000>;
+def IsStructStore             : FlagType<0x00040000>;
+def IsZExtReturn              : FlagType<0x00080000>; // Return value is sign-extend by default
 
 // Every intrinsic subclasses Inst.
 class Inst<string n, string p, string t, MergeType mt, string i,
@@ -150,6 +155,7 @@ class Inst<string n, string p, string t, MergeType mt, string i,
   string Types = t;
   string ArchGuard = "";
   int Merge = mt.Value;
+  string MergeSuffix = mt.Suffix;
   string LLVMIntrinsic = i;
   list<FlagType> Flags = ft;
   int MemEltType = met.Value;

diff  --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp
index 831dfa804ca0..dc009e5ca443 100644
--- a/clang/utils/TableGen/SveEmitter.cpp
+++ b/clang/utils/TableGen/SveEmitter.cpp
@@ -65,9 +65,6 @@ class SVEType {
     applyModifier(CharMod);
   }
 
-  /// Return the value in SVETypeFlags for this type.
-  unsigned getTypeFlags() const;
-
   bool isPointer() const { return Pointer; }
   bool isVoidPointer() const { return Pointer && Void; }
   bool isSigned() const { return Signed; }
@@ -138,36 +135,22 @@ class Intrinsic {
   /// The architectural #ifdef guard.
   std::string Guard;
 
+  // The merge suffix such as _m, _x or _z.
+  std::string MergeSuffix;
+
   /// The types of return value [0] and parameters [1..].
   std::vector<SVEType> Types;
 
   /// The "base type", which is VarType('d', BaseTypeSpec).
   SVEType BaseType;
 
-  unsigned Flags;
+  uint64_t Flags;
 
 public:
-  /// The type of predication.
-  enum MergeType {
-    MergeNone,
-    MergeAny,
-    MergeOp1,
-    MergeZero,
-    MergeAnyExp,
-    MergeZeroExp,
-    MergeInvalid
-  } Merge;
-
-  Intrinsic(StringRef Name, StringRef Proto, int64_t MT, StringRef LLVMName,
-            unsigned Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter,
-            StringRef Guard)
-      : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
-        BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), BaseType(BT, 'd'),
-        Flags(Flags), Merge(MergeType(MT)) {
-    // Types[0] is the return value.
-    for (unsigned I = 0; I < Proto.size(); ++I)
-      Types.emplace_back(BaseTypeSpec, Proto[I]);
-  }
+  Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
+            StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
+            uint64_t Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter,
+            StringRef Guard);
 
   ~Intrinsic()=default;
 
@@ -179,14 +162,13 @@ class Intrinsic {
 
   StringRef getGuard() const { return Guard; }
   ClassKind getClassKind() const { return Class; }
-  MergeType getMergeType() const { return Merge; }
 
   SVEType getReturnType() const { return Types[0]; }
   ArrayRef<SVEType> getTypes() const { return Types; }
   SVEType getParamType(unsigned I) const { return Types[I + 1]; }
   unsigned getNumParams() const { return Proto.size() - 1; }
 
-  unsigned getFlags() const { return Flags; }
+  uint64_t getFlags() const { return Flags; }
   bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
 
   /// Return the type string for a BUILTIN() macro in Builtins.def.
@@ -209,7 +191,7 @@ class Intrinsic {
   void emitIntrinsic(raw_ostream &OS) const;
 
 private:
-  std::string getMergeSuffix() const;
+  std::string getMergeSuffix() const { return MergeSuffix; }
   std::string mangleName(ClassKind LocalCK) const;
   std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
                                    std::string Proto) const;
@@ -221,8 +203,8 @@ class SVEEmitter {
   llvm::StringMap<uint64_t> EltTypes;
   llvm::StringMap<uint64_t> MemEltTypes;
   llvm::StringMap<uint64_t> FlagTypes;
+  llvm::StringMap<uint64_t> MergeTypes;
 
-  unsigned getTypeFlags(const SVEType &T);
 public:
   SVEEmitter(RecordKeeper &R) : Records(R) {
     for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
@@ -231,8 +213,42 @@ class SVEEmitter {
       MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
     for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
       FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
+    for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
+      MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
+  }
+
+  // Returns the SVETypeFlags for a given value and mask.
+  uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
+    auto It = FlagTypes.find(MaskName);
+    if (It != FlagTypes.end()) {
+      uint64_t Mask = It->getValue();
+      unsigned Shift = llvm::countTrailingZeros(Mask);
+      return (V << Shift) & Mask;
+    }
+    llvm_unreachable("Unsupported flag");
+  }
+
+  // Returns the SVETypeFlags for the given element type.
+  uint64_t encodeEltType(StringRef EltName) {
+    auto It = EltTypes.find(EltName);
+    if (It != EltTypes.end())
+      return encodeFlag(It->getValue(), "EltTypeMask");
+    llvm_unreachable("Unsupported EltType");
+  }
+
+  // Returns the SVETypeFlags for the given memory element type.
+  uint64_t encodeMemoryElementType(uint64_t MT) {
+    return encodeFlag(MT, "MemEltTypeMask");
   }
 
+  // Returns the SVETypeFlags for the given merge type.
+  uint64_t encodeMergeType(uint64_t MT) {
+    return encodeFlag(MT, "MergeTypeMask");
+  }
+
+  // Returns the SVETypeFlags value for the given SVEType.
+  uint64_t encodeTypeFlags(const SVEType &T);
+
   /// Emit arm_sve.h.
   void createHeader(raw_ostream &o);
 
@@ -256,36 +272,6 @@ class SVEEmitter {
 // Type implementation
 //===----------------------------------------------------------------------===//
 
-unsigned SVEEmitter::getTypeFlags(const SVEType &T) {
-  unsigned FirstEltType = EltTypes["FirstEltType"];
-  if (T.isFloat()) {
-    switch (T.getElementSizeInBits()) {
-    case 16: return FirstEltType + EltTypes["EltTyFloat16"];
-    case 32: return FirstEltType + EltTypes["EltTyFloat32"];
-    case 64: return FirstEltType + EltTypes["EltTyFloat64"];
-    default: llvm_unreachable("Unhandled float element bitwidth!");
-    }
-  }
-
-  if (T.isPredicateVector()) {
-    switch (T.getElementSizeInBits()) {
-    case 8:  return FirstEltType + EltTypes["EltTyBool8"];
-    case 16: return FirstEltType + EltTypes["EltTyBool16"];
-    case 32: return FirstEltType + EltTypes["EltTyBool32"];
-    case 64: return FirstEltType + EltTypes["EltTyBool64"];
-    default: llvm_unreachable("Unhandled predicate element bitwidth!");
-    }
-  }
-
-  switch (T.getElementSizeInBits()) {
-  case 8:  return FirstEltType + EltTypes["EltTyInt8"];
-  case 16: return FirstEltType + EltTypes["EltTyInt16"];
-  case 32: return FirstEltType + EltTypes["EltTyInt32"];
-  case 64: return FirstEltType + EltTypes["EltTyInt64"];
-  default: llvm_unreachable("Unhandled integer element bitwidth!");
-  }
-}
-
 std::string SVEType::builtin_str() const {
   std::string S;
   if (isVoid())
@@ -543,6 +529,26 @@ void SVEType::applyModifier(char Mod) {
 // Intrinsic implementation
 //===----------------------------------------------------------------------===//
 
+Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
+                     StringRef MergeSuffix, uint64_t MemoryElementTy,
+                     StringRef LLVMName, uint64_t Flags, TypeSpec BT,
+                     ClassKind Class, SVEEmitter &Emitter, StringRef Guard)
+    : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
+      BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
+      MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags) {
+
+  // Types[0] is the return value.
+  for (unsigned I = 0; I < Proto.size(); ++I) {
+    SVEType T(BaseTypeSpec, Proto[I]);
+    Types.push_back(T);
+  }
+
+  // Set flags based on properties
+  this->Flags |= Emitter.encodeTypeFlags(BaseType);
+  this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
+  this->Flags |= Emitter.encodeMergeType(MergeTy);
+}
+
 std::string Intrinsic::getBuiltinTypeStr() {
   std::string S;
 
@@ -601,20 +607,6 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
   return Ret;
 }
 
-// ACLE function names have a merge style postfix.
-std::string Intrinsic::getMergeSuffix() const {
-  switch (getMergeType()) {
-    default:
-      llvm_unreachable("Unknown predication specifier");
-    case MergeNone:    return "";
-    case MergeAny:
-    case MergeAnyExp:  return "_x";
-    case MergeOp1:     return "_m";
-    case MergeZero:
-    case MergeZeroExp: return "_z";
-  }
-}
-
 std::string Intrinsic::mangleName(ClassKind LocalCK) const {
   std::string S = getName();
 
@@ -668,6 +660,49 @@ void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
 //===----------------------------------------------------------------------===//
 // SVEEmitter implementation
 //===----------------------------------------------------------------------===//
+uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
+  if (T.isFloat()) {
+    switch (T.getElementSizeInBits()) {
+    case 16:
+      return encodeEltType("EltTyFloat16");
+    case 32:
+      return encodeEltType("EltTyFloat32");
+    case 64:
+      return encodeEltType("EltTyFloat64");
+    default:
+      llvm_unreachable("Unhandled float element bitwidth!");
+    }
+  }
+
+  if (T.isPredicateVector()) {
+    switch (T.getElementSizeInBits()) {
+    case 8:
+      return encodeEltType("EltTyBool8");
+    case 16:
+      return encodeEltType("EltTyBool16");
+    case 32:
+      return encodeEltType("EltTyBool32");
+    case 64:
+      return encodeEltType("EltTyBool64");
+    default:
+      llvm_unreachable("Unhandled predicate element bitwidth!");
+    }
+  }
+
+  switch (T.getElementSizeInBits()) {
+  case 8:
+    return encodeEltType("EltTyInt8");
+  case 16:
+    return encodeEltType("EltTyInt16");
+  case 32:
+    return encodeEltType("EltTyInt32");
+  case 64:
+    return encodeEltType("EltTyInt64");
+  default:
+    llvm_unreachable("Unhandled integer element bitwidth!");
+  }
+}
+
 void SVEEmitter::createIntrinsic(
     Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
   StringRef Name = R->getValueAsString("Name");
@@ -675,13 +710,14 @@ void SVEEmitter::createIntrinsic(
   StringRef Types = R->getValueAsString("Types");
   StringRef Guard = R->getValueAsString("ArchGuard");
   StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
-  int64_t Merge = R->getValueAsInt("Merge");
+  uint64_t Merge = R->getValueAsInt("Merge");
+  StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
+  uint64_t MemEltType = R->getValueAsInt("MemEltType");
   std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
 
   int64_t Flags = 0;
   for (auto FlagRec : FlagsList)
     Flags |= FlagRec->getValueAsInt("Value");
-  Flags |= R->getValueAsInt("MemEltType") + MemEltTypes["FirstMemEltType"];
 
   // Extract type specs from string
   SmallVector<TypeSpec, 8> TypeSpecs;
@@ -701,14 +737,15 @@ void SVEEmitter::createIntrinsic(
 
   // Create an Intrinsic for each type spec.
   for (auto TS : TypeSpecs) {
-    Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge,
-                                              LLVMName, Flags, TS, ClassS,
-                                              *this, Guard));
+    Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, MergeSuffix,
+                                              MemEltType, LLVMName, Flags, TS,
+                                              ClassS, *this, Guard));
 
     // Also generate the short-form (e.g. svadd_m) for the given type-spec.
     if (Intrinsic::isOverloadedIntrinsic(Name))
-      Out.push_back(std::make_unique<Intrinsic>(
-          Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard));
+      Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, MergeSuffix,
+                                                MemEltType, LLVMName, Flags, TS,
+                                                ClassG, *this, Guard));
   }
 }
 
@@ -846,7 +883,7 @@ void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
     if (Def->getClassKind() == ClassG)
       continue;
 
-    uint64_t Flags = Def->getFlags() | getTypeFlags(Def->getBaseType());
+    uint64_t Flags = Def->getFlags();
     auto FlagString = std::to_string(Flags);
 
     std::string LLVMName = Def->getLLVMName();
@@ -876,6 +913,11 @@ void SVEEmitter::createTypeFlags(raw_ostream &OS) {
   for (auto &KV : MemEltTypes)
     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
   OS << "#endif\n\n";
+
+  OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
+  for (auto &KV : MergeTypes)
+    OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
+  OS << "#endif\n\n";
 }
 
 namespace clang {


        


More information about the cfe-commits mailing list