[clang] 8b409ea - [SVE] Auto-generate builtins and header for svld1.

Sander de Smalen via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 16 03:53:04 PDT 2020


Author: Sander de Smalen
Date: 2020-03-16T10:52:37Z
New Revision: 8b409eabaf755c88a7d652fe99d3ad858a4fe82a

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

LOG: [SVE] Auto-generate builtins and header for svld1.

This is a first patch in a series for the SveEmitter to generate the arm_sve.h
header file and builtins.

I've tried my best to strip down this patch as best as I could, but there
are still a few changes that are not necessarily exercised by the load intrinsics
in this patch, mostly around the SVEType class which has some common logic to
represent types from a type and prototype string. I thought it didn't make
much sense to remove that from this patch and split it up.

Reviewers: efriedma, rovka, SjoerdMeijer, rsandifo-arm, rengolin

Reviewed By: SjoerdMeijer

Tags: #clang

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

Added: 
    clang/include/clang/Basic/AArch64SVETypeFlags.h
    clang/include/clang/Basic/BuiltinsSVE.def

Modified: 
    clang/include/clang/Basic/BuiltinsAArch64.def
    clang/include/clang/Basic/CMakeLists.txt
    clang/include/clang/Basic/TargetBuiltins.h
    clang/include/clang/Basic/arm_sve.td
    clang/lib/Basic/Targets/AArch64.cpp
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/utils/TableGen/SveEmitter.cpp
    clang/utils/TableGen/TableGen.cpp
    clang/utils/TableGen/TableGenBackends.h

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/AArch64SVETypeFlags.h b/clang/include/clang/Basic/AArch64SVETypeFlags.h
new file mode 100644
index 000000000000..2b11fe6f9b2b
--- /dev/null
+++ b/clang/include/clang/Basic/AArch64SVETypeFlags.h
@@ -0,0 +1,67 @@
+//===- AArch64SVETypeFlags.h - Flags used to generate ACLE builtins- C++ -*-===//
+//
+//  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//  See https://llvm.org/LICENSE.txt for license information.
+//  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_AARCH64SVETYPEFLAGS_H
+#define LLVM_CLANG_BASIC_AARCH64SVETYPEFLAGS_H
+
+#include <stdint.h>
+
+namespace clang {
+
+/// Flags to identify the types for overloaded SVE builtins.
+class SVETypeFlags {
+  uint64_t Flags;
+
+public:
+  /// These must be kept in sync with the flags in
+  /// include/clang/Basic/arm_sve.td.
+  static const uint64_t MemEltTypeOffset = 4; // Bit offset of MemEltTypeMask
+  static const uint64_t EltTypeMask      = 0x00000000000f;
+  static const uint64_t MemEltTypeMask   = 0x000000000070;
+  static const uint64_t IsLoad           = 0x000000000080;
+
+  enum EltType {
+    Invalid,
+    Int8,
+    Int16,
+    Int32,
+    Int64,
+    Float16,
+    Float32,
+    Float64,
+    Bool8,
+    Bool16,
+    Bool32,
+    Bool64
+  };
+
+  enum MemEltTy {
+    MemEltTyDefault,
+    MemEltTyInt8,
+    MemEltTyInt16,
+    MemEltTyInt32,
+    MemEltTyInt64
+  };
+
+  SVETypeFlags(uint64_t F) : Flags(F) { }
+  SVETypeFlags(EltType ET, bool IsUnsigned) : Flags(ET) { }
+
+  EltType getEltType() const { return (EltType)(Flags & EltTypeMask); }
+  MemEltTy getMemEltType() const {
+    return (MemEltTy)((Flags & MemEltTypeMask) >> MemEltTypeOffset);
+  }
+
+  bool isLoad() const { return Flags & IsLoad; }
+
+  uint64_t getBits() const { return Flags; }
+  bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
+};
+
+} // end namespace clang
+
+#endif

diff  --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def
index 8f3a24c2e1f6..f07c567053de 100644
--- a/clang/include/clang/Basic/BuiltinsAArch64.def
+++ b/clang/include/clang/Basic/BuiltinsAArch64.def
@@ -99,19 +99,6 @@ BUILTIN(__builtin_arm_tcommit, "v", "n")
 BUILTIN(__builtin_arm_tcancel, "vWUIi", "n")
 BUILTIN(__builtin_arm_ttest, "WUi", "nc")
 
-// SVE
-BUILTIN(__builtin_sve_svld1_s16, "q8sq16bSsC*", "n")
-BUILTIN(__builtin_sve_svld1_s32, "q4iq16bSiC*", "n")
-BUILTIN(__builtin_sve_svld1_s64, "q2Wiq16bSWiC*", "n")
-BUILTIN(__builtin_sve_svld1_s8, "q16Scq16bScC*", "n")
-BUILTIN(__builtin_sve_svld1_u16, "q8Usq16bUsC*", "n")
-BUILTIN(__builtin_sve_svld1_u32, "q4Uiq16bUiC*", "n")
-BUILTIN(__builtin_sve_svld1_u64, "q2UWiq16bUWiC*", "n")
-BUILTIN(__builtin_sve_svld1_u8, "q16Ucq16bUcC*", "n")
-BUILTIN(__builtin_sve_svld1_f64, "q2dq16bdC*", "n")
-BUILTIN(__builtin_sve_svld1_f32, "q4fq16bfC*", "n")
-BUILTIN(__builtin_sve_svld1_f16, "q8hq16bhC*", "n")
-
 TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")

diff  --git a/clang/include/clang/Basic/BuiltinsSVE.def b/clang/include/clang/Basic/BuiltinsSVE.def
new file mode 100644
index 000000000000..2839ca992d98
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsSVE.def
@@ -0,0 +1,20 @@
+//===--- BuiltinsSVE.def - SVE Builtin function database --------*- C++ -*-===//
+//
+//  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//  See https://llvm.org/LICENSE.txt for license information.
+//  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SVE-specific builtin function database.  Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+#define GET_SVE_BUILTINS
+#include "clang/Basic/arm_sve_builtins.inc"
+#undef GET_SVE_BUILTINS
+
+#undef BUILTIN

diff  --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index ea011a8af177..2ce38c631eec 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -60,7 +60,12 @@ clang_tablegen(arm_mve_builtin_sema.inc -gen-arm-mve-builtin-sema
 clang_tablegen(arm_mve_builtin_aliases.inc -gen-arm-mve-builtin-aliases
   SOURCE arm_mve.td
   TARGET ClangARMMveBuiltinAliases)
-
+clang_tablegen(arm_sve_builtins.inc -gen-arm-sve-builtins
+  SOURCE arm_sve.td
+  TARGET ClangARMSveBuiltins)
+clang_tablegen(arm_sve_codegenmap.inc -gen-arm-sve-codegenmap
+  SOURCE arm_sve.td
+  TARGET ClangARMSveCodeGenMap)
 clang_tablegen(arm_cde_builtins.inc -gen-arm-cde-builtin-def
   SOURCE arm_cde.td
   TARGET ClangARMCdeBuiltinsDef)

diff  --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 0e2f0753b0c5..9ef7837353a0 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -41,11 +41,22 @@ namespace clang {
     };
   }
 
+  namespace SVE {
+  enum {
+    LastNEONBuiltin = NEON::FirstTSBuiltin - 1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsSVE.def"
+    FirstTSBuiltin,
+  };
+  }
+
   /// AArch64 builtins
   namespace AArch64 {
   enum {
     LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
     LastNEONBuiltin = NEON::FirstTSBuiltin - 1,
+    FirstSVEBuiltin = NEON::FirstTSBuiltin,
+    LastSVEBuiltin = SVE::FirstTSBuiltin - 1,
   #define BUILTIN(ID, TYPE, ATTRS) BI##ID,
   #include "clang/Basic/BuiltinsAArch64.def"
     LastTSBuiltin

diff  --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td
index 10417cdfcdea..afaab8a76e28 100644
--- a/clang/include/clang/Basic/arm_sve.td
+++ b/clang/include/clang/Basic/arm_sve.td
@@ -12,3 +12,110 @@
 //      https://developer.arm.com/architectures/system-architectures/software-standards/acle
 //
 //===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction definitions
+//===----------------------------------------------------------------------===//
+// Every intrinsic subclasses "Inst". An intrinsic has a name, a prototype and
+// a sequence of typespecs.
+//
+// The name is the base name of the intrinsic, for example "svld1". This is
+// then mangled by the tblgen backend to add type information ("svld1_s16").
+//
+// A typespec is a sequence of uppercase characters (modifiers) followed by one
+// lowercase character. A typespec encodes a particular "base type" of the
+// intrinsic.
+//
+// An example typespec is "Us" - unsigned short - svuint16_t. The available
+// typespec codes are given below.
+//
+// The string given to an Inst class is a sequence of typespecs. The intrinsic
+// is instantiated for every typespec in the sequence. For example "sdUsUd".
+//
+// The prototype is a string that defines the return type of the intrinsic
+// and the type of each argument. The return type and every argument gets a
+// "modifier" that can change in some way the "base type" of the intrinsic.
+//
+// The modifier 'd' means "default" and does not modify the base type in any
+// way. The available modifiers are given below.
+//
+// Typespecs
+// ---------
+// c: char
+// s: short
+// i: int
+// l: long
+// f: float
+// h: half-float
+// d: double
+
+// Typespec modifiers
+// ------------------
+// P: boolean
+// U: unsigned
+
+// Prototype modifiers
+// -------------------
+// prototype: return (arg, arg, ...)
+//
+// d: default
+// c: const pointer type
+// P: predicate type
+
+class MergeType<int val> {
+  int Value = val;
+}
+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.
+
+class MemEltTy<int val> {
+  int Value = val;
+}
+def MemEltTyDefault   : MemEltTy<0>;
+def MemEltTyInt8      : MemEltTy<1>;
+def MemEltTyInt16     : MemEltTy<2>;
+def MemEltTyInt32     : MemEltTy<3>;
+def MemEltTyInt64     : MemEltTy<4>;
+
+class FlagType<int val> {
+  int Value = val;
+}
+
+// These must be kept in sync with the flags in utils/TableGen/SveEmitter.h
+// and include/clang/Basic/TargetBuiltins.h
+def NoFlags                   : FlagType<0x00000000>;
+//                            0x00000001 => EltType
+//                            ...
+//                            0x0000000f => EltType
+//                            0x00000010 => MemEltType
+//                            ...
+//                            0x00000070 => MemEltType
+def IsLoad                    : FlagType<0x00000080>;
+
+// Every intrinsic subclasses Inst.
+class Inst<string n, string p, string t, MergeType mt, string i,
+           list<FlagType> ft, MemEltTy met> {
+  string Name = n;
+  string Prototype = p;
+  string Types = t;
+  string ArchGuard = "";
+  int Merge = mt.Value;
+  string LLVMIntrinsic = i;
+  list<FlagType> Flags = ft;
+  int MemEltType = met.Value;
+}
+
+// MInst: Instructions which access memory
+class MInst<string n, string p, string t, list<FlagType> f,
+            MemEltTy met=MemEltTyDefault, string i="">
+  : Inst<n, p, t, MergeNone, i, f, met> {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Loads
+
+// Load one vector (scalar base)
+def SVLD1   : MInst<"svld1[_{2}]", "dPc", "csilUcUsUiUlhfd", [IsLoad]>;

diff  --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index bd1a8834c2fa..f26aa1d1781a 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -26,6 +26,10 @@ const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
    {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
 #include "clang/Basic/BuiltinsNEON.def"
 
+#define BUILTIN(ID, TYPE, ATTRS)                                               \
+   {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsSVE.def"
+
 #define BUILTIN(ID, TYPE, ATTRS)                                               \
    {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
 #define LANGBUILTIN(ID, TYPE, ATTRS, LANG)                                     \

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d333aeffefd9..a1312d289d57 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -23,6 +23,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
+#include "clang/Basic/AArch64SVETypeFlags.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
@@ -4576,7 +4577,7 @@ enum {
 };
 
 namespace {
-struct NeonIntrinsicInfo {
+struct ARMVectorIntrinsicInfo {
   const char *NameHint;
   unsigned BuiltinID;
   unsigned LLVMIntrinsic;
@@ -4586,7 +4587,7 @@ struct NeonIntrinsicInfo {
   bool operator<(unsigned RHSBuiltinID) const {
     return BuiltinID < RHSBuiltinID;
   }
-  bool operator<(const NeonIntrinsicInfo &TE) const {
+  bool operator<(const ARMVectorIntrinsicInfo &TE) const {
     return BuiltinID < TE.BuiltinID;
   }
 };
@@ -4604,7 +4605,7 @@ struct NeonIntrinsicInfo {
       Intrinsic::LLVMIntrinsic, Intrinsic::AltLLVMIntrinsic, \
       TypeModifier }
 
-static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
+static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
   NEONMAP2(vabd_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
   NEONMAP2(vabdq_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
   NEONMAP1(vabs_v, arm_neon_vabs, 0),
@@ -4885,7 +4886,7 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
   NEONMAP0(vzipq_v)
 };
 
-static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
+static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
   NEONMAP1(vabs_v, aarch64_neon_abs, 0),
   NEONMAP1(vabsq_v, aarch64_neon_abs, 0),
   NEONMAP0(vaddhn_v),
@@ -5054,7 +5055,7 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
   NEONMAP0(vtstq_v),
 };
 
-static const NeonIntrinsicInfo AArch64SISDIntrinsicMap[] = {
+static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = {
   NEONMAP1(vabdd_f64, aarch64_sisd_fabd, Add1ArgType),
   NEONMAP1(vabds_f32, aarch64_sisd_fabd, Add1ArgType),
   NEONMAP1(vabsd_s64, aarch64_neon_abs, Add1ArgType),
@@ -5284,15 +5285,32 @@ static const NeonIntrinsicInfo AArch64SISDIntrinsicMap[] = {
 #undef NEONMAP1
 #undef NEONMAP2
 
+#define SVEMAP1(NameBase, LLVMIntrinsic, TypeModifier)                         \
+  {                                                                            \
+    #NameBase, SVE::BI__builtin_sve_##NameBase, Intrinsic::LLVMIntrinsic, 0,   \
+        TypeModifier                                                           \
+  }
+
+#define SVEMAP2(NameBase, TypeModifier)                                        \
+  { #NameBase, SVE::BI__builtin_sve_##NameBase, 0, 0, TypeModifier }
+static const ARMVectorIntrinsicInfo AArch64SVEIntrinsicMap[] = {
+#define GET_SVE_LLVM_INTRINSIC_MAP
+#include "clang/Basic/arm_sve_codegenmap.inc"
+#undef GET_SVE_LLVM_INTRINSIC_MAP
+};
+
+#undef SVEMAP1
+#undef SVEMAP2
+
 static bool NEONSIMDIntrinsicsProvenSorted = false;
 
 static bool AArch64SIMDIntrinsicsProvenSorted = false;
 static bool AArch64SISDIntrinsicsProvenSorted = false;
+static bool AArch64SVEIntrinsicsProvenSorted = false;
 
-
-static const NeonIntrinsicInfo *
-findNeonIntrinsicInMap(ArrayRef<NeonIntrinsicInfo> IntrinsicMap,
-                       unsigned BuiltinID, bool &MapProvenSorted) {
+static const ARMVectorIntrinsicInfo *
+findARMVectorIntrinsicInMap(ArrayRef<ARMVectorIntrinsicInfo> IntrinsicMap,
+                            unsigned BuiltinID, bool &MapProvenSorted) {
 
 #ifndef NDEBUG
   if (!MapProvenSorted) {
@@ -5301,7 +5319,8 @@ findNeonIntrinsicInMap(ArrayRef<NeonIntrinsicInfo> IntrinsicMap,
   }
 #endif
 
-  const NeonIntrinsicInfo *Builtin = llvm::lower_bound(IntrinsicMap, BuiltinID);
+  const ARMVectorIntrinsicInfo *Builtin =
+      llvm::lower_bound(IntrinsicMap, BuiltinID);
 
   if (Builtin != IntrinsicMap.end() && Builtin->BuiltinID == BuiltinID)
     return Builtin;
@@ -5348,10 +5367,9 @@ Function *CodeGenFunction::LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
   return CGM.getIntrinsic(IntrinsicID, Tys);
 }
 
-static Value *EmitCommonNeonSISDBuiltinExpr(CodeGenFunction &CGF,
-                                            const NeonIntrinsicInfo &SISDInfo,
-                                            SmallVectorImpl<Value *> &Ops,
-                                            const CallExpr *E) {
+static Value *EmitCommonNeonSISDBuiltinExpr(
+    CodeGenFunction &CGF, const ARMVectorIntrinsicInfo &SISDInfo,
+    SmallVectorImpl<Value *> &Ops, const CallExpr *E) {
   unsigned BuiltinID = SISDInfo.BuiltinID;
   unsigned int Int = SISDInfo.LLVMIntrinsic;
   unsigned Modifier = SISDInfo.TypeModifier;
@@ -6864,7 +6882,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
   // Many NEON builtins have identical semantics and uses in ARM and
   // AArch64. Emit these in a single function.
   auto IntrinsicMap = makeArrayRef(ARMSIMDIntrinsicMap);
-  const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
+  const ARMVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
       IntrinsicMap, BuiltinID, NEONSIMDIntrinsicsProvenSorted);
   if (Builtin)
     return EmitCommonNeonBuiltinExpr(
@@ -7436,9 +7454,40 @@ Value *CodeGenFunction::EmitSVEMaskedLoad(llvm::Type *ReturnTy,
   return Builder.CreateMaskedLoad(BasePtr, Align(1), Predicate, Splat0);
 }
 
+Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
+                                                  const CallExpr *E) {
+  // Find out if any arguments are required to be integer constant expressions.
+  unsigned ICEArguments = 0;
+  ASTContext::GetBuiltinTypeError Error;
+  getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
+  assert(Error == ASTContext::GE_None && "Should not codegen an error");
+
+  llvm::SmallVector<Value *, 4> Ops;
+  for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
+    if ((ICEArguments & (1 << i)) == 0)
+      Ops.push_back(EmitScalarExpr(E->getArg(i)));
+    else
+      llvm_unreachable("Not yet implemented");
+  }
+
+  auto *Builtin = findARMVectorIntrinsicInMap(AArch64SVEIntrinsicMap, BuiltinID,
+                                              AArch64SVEIntrinsicsProvenSorted);
+  SVETypeFlags TypeFlags(Builtin->TypeModifier);
+  llvm::Type *Ty = ConvertType(E->getType());
+  if (TypeFlags.isLoad())
+    return EmitSVEMaskedLoad(Ty, Ops);
+
+  /// Should not happen
+  return nullptr;
+}
+
 Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
                                                const CallExpr *E,
                                                llvm::Triple::ArchType Arch) {
+  if (BuiltinID >= AArch64::FirstSVEBuiltin &&
+      BuiltinID <= AArch64::LastSVEBuiltin)
+    return EmitAArch64SVEBuiltinExpr(BuiltinID, E);
+
   unsigned HintID = static_cast<unsigned>(-1);
   switch (BuiltinID) {
   default: break;
@@ -7472,27 +7521,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
     return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
   }
 
-  switch (BuiltinID) {
-  case AArch64::BI__builtin_sve_svld1_u8:
-  case AArch64::BI__builtin_sve_svld1_u16:
-  case AArch64::BI__builtin_sve_svld1_u32:
-  case AArch64::BI__builtin_sve_svld1_u64:
-  case AArch64::BI__builtin_sve_svld1_s8:
-  case AArch64::BI__builtin_sve_svld1_s16:
-  case AArch64::BI__builtin_sve_svld1_s32:
-  case AArch64::BI__builtin_sve_svld1_s64:
-  case AArch64::BI__builtin_sve_svld1_f16:
-  case AArch64::BI__builtin_sve_svld1_f32:
-  case AArch64::BI__builtin_sve_svld1_f64: {
-    llvm::SmallVector<Value *, 4> Ops = {EmitScalarExpr(E->getArg(0)),
-                                         EmitScalarExpr(E->getArg(1))};
-    llvm::Type *Ty = ConvertType(E->getType());
-    return EmitSVEMaskedLoad(Ty, Ops);
-  }
-  default:
-    break;
-  }
-
   if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
     Value *Address         = EmitScalarExpr(E->getArg(0));
     Value *RW              = EmitScalarExpr(E->getArg(1));
@@ -7891,7 +7919,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
   }
 
   auto SISDMap = makeArrayRef(AArch64SISDIntrinsicMap);
-  const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
+  const ARMVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
       SISDMap, BuiltinID, AArch64SISDIntrinsicsProvenSorted);
 
   if (Builtin) {
@@ -8731,8 +8759,8 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
 
   // Not all intrinsics handled by the common case work for AArch64 yet, so only
   // defer to common code if it's been added to our special map.
-  Builtin = findNeonIntrinsicInMap(AArch64SIMDIntrinsicMap, BuiltinID,
-                                   AArch64SIMDIntrinsicsProvenSorted);
+  Builtin = findARMVectorIntrinsicInMap(AArch64SIMDIntrinsicMap, BuiltinID,
+                                        AArch64SIMDIntrinsicsProvenSorted);
 
   if (Builtin)
     return EmitCommonNeonBuiltinExpr(

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index e470becbe426..440b088330ef 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3904,6 +3904,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::Value *EmitSVEPredicateCast(llvm::Value *Pred, llvm::VectorType *VTy);
   llvm::Value *EmitSVEMaskedLoad(llvm::Type *ReturnTy,
                                  SmallVectorImpl<llvm::Value *> &Ops);
+  llvm::Value *EmitAArch64SVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
 
   llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
                                       llvm::Triple::ArchType Arch);

diff  --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp
index 9eb4c01a9358..1f342df74a91 100644
--- a/clang/utils/TableGen/SveEmitter.cpp
+++ b/clang/utils/TableGen/SveEmitter.cpp
@@ -29,6 +29,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/Error.h"
+#include "clang/Basic/AArch64SVETypeFlags.h"
 #include <string>
 #include <sstream>
 #include <set>
@@ -36,26 +37,535 @@
 
 using namespace llvm;
 
-//===----------------------------------------------------------------------===//
-// SVEEmitter
-//===----------------------------------------------------------------------===//
+enum ClassKind {
+  ClassNone,
+  ClassS,     // signed/unsigned, e.g., "_s8", "_u8" suffix
+  ClassG,     // Overloaded name without type suffix
+};
+
+using TypeSpec = std::string;
+using SVETypeFlags = clang::SVETypeFlags;
 
 namespace {
 
+class SVEType {
+  TypeSpec TS;
+  bool Float, Signed, Immediate, Void, Constant, Pointer;
+  bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
+  unsigned Bitwidth, ElementBitwidth, NumVectors;
+
+public:
+  SVEType() : SVEType(TypeSpec(), 'v') {}
+
+  SVEType(TypeSpec TS, char CharMod)
+      : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
+        Constant(false), Pointer(false), DefaultType(false), IsScalable(true),
+        Predicate(false), PredicatePattern(false), PrefetchOp(false),
+        Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
+    if (!TS.empty())
+      applyTypespec();
+    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; }
+  bool isImmediate() const { return Immediate; }
+  bool isScalar() const { return NumVectors == 0; }
+  bool isVector() const { return NumVectors > 0; }
+  bool isScalableVector() const { return isVector() && IsScalable; }
+  bool isChar() const { return ElementBitwidth == 8; }
+  bool isVoid() const { return Void & !Pointer; }
+  bool isDefault() const { return DefaultType; }
+  bool isFloat() const { return Float; }
+  bool isInteger() const { return !Float && !Predicate; }
+  bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
+  bool isPredicateVector() const { return Predicate; }
+  bool isPredicatePattern() const { return PredicatePattern; }
+  bool isPrefetchOp() const { return PrefetchOp; }
+  bool isConstant() const { return Constant; }
+  unsigned getElementSizeInBits() const { return ElementBitwidth; }
+  unsigned getNumVectors() const { return NumVectors; }
+
+  unsigned getNumElements() const {
+    assert(ElementBitwidth != ~0U);
+    return Bitwidth / ElementBitwidth;
+  }
+  unsigned getSizeInBits() const {
+    return Bitwidth;
+  }
+
+  /// Return the string representation of a type, which is an encoded
+  /// string for passing to the BUILTIN() macro in Builtins.def.
+  std::string builtin_str() const;
+
+private:
+  /// Creates the type based on the typespec string in TS.
+  void applyTypespec();
+
+  /// Applies a prototype modifier to the type.
+  void applyModifier(char Mod);
+};
+
+
+class SVEEmitter;
+
+/// The main grunt class. This represents an instantiation of an intrinsic with
+/// a particular typespec and prototype.
+class Intrinsic {
+  /// The unmangled name.
+  std::string Name;
+
+  /// The name of the corresponding LLVM IR intrinsic.
+  std::string LLVMName;
+
+  /// Intrinsic prototype.
+  std::string Proto;
+
+  /// The base type spec for this intrinsic.
+  TypeSpec BaseTypeSpec;
+
+  /// The base class kind. Most intrinsics use ClassS, which has full type
+  /// info for integers (_s32/_u32), or ClassG which is used for overloaded
+  /// intrinsics.
+  ClassKind Class;
+
+  /// The architectural #ifdef guard.
+  std::string Guard;
+
+  /// The types of return value [0] and parameters [1..].
+  std::vector<SVEType> Types;
+
+  /// The "base type", which is VarType('d', BaseTypeSpec).
+  SVEType BaseType;
+
+  /// The type of the memory element
+  enum MemEltType {
+    MemEltTypeDefault,
+    MemEltTypeInt8,
+    MemEltTypeInt16,
+    MemEltTypeInt32,
+    MemEltTypeInt64,
+    MemEltTypeInvalid
+  } MemEltTy;
+
+  SVETypeFlags Flags;
+
+public:
+  /// The type of predication.
+  enum MergeType {
+    MergeNone,
+    MergeAny,
+    MergeOp1,
+    MergeZero,
+    MergeAnyExp,
+    MergeZeroExp,
+    MergeInvalid
+  } Merge;
+
+  Intrinsic(StringRef Name, StringRef Proto, int64_t MT, int64_t MET,
+            StringRef LLVMName, SVETypeFlags 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'),
+        MemEltTy(MemEltType(MET)), 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()=default;
+
+  std::string getName() const { return Name; }
+  std::string getLLVMName() const { return LLVMName; }
+  std::string getProto() const { return Proto; }
+  TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
+  SVEType getBaseType() const { return BaseType; }
+
+  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; }
+
+  SVETypeFlags getFlags() const { return Flags; }
+  bool isFlagSet(uint64_t Flag) const { return Flags.isFlagSet(Flag);}
+
+  int64_t getMemEltTypeEnum() const {
+    int64_t METEnum = (MemEltTy << SVETypeFlags::MemEltTypeOffset);
+    assert((METEnum &~ SVETypeFlags::MemEltTypeMask) == 0 && "Bad MemEltTy");
+    return METEnum;
+  }
+
+  /// Return the type string for a BUILTIN() macro in Builtins.def.
+  std::string getBuiltinTypeStr();
+
+  /// Return the name, mangled with type information. The name is mangled for
+  /// ClassS, so will add type suffixes such as _u32/_s32.
+  std::string getMangledName() const { return mangleName(ClassS); }
+
+  /// Returns true if the intrinsic is overloaded, in that it should also generate
+  /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
+  /// 'svld1_u32(..)'.
+  static bool isOverloadedIntrinsic(StringRef Name) {
+    auto BrOpen = Name.find("[");
+    auto BrClose = Name.find(']');
+    return BrOpen != std::string::npos && BrClose != std::string::npos;
+  }
+
+  /// Emits the intrinsic declaration to the ostream.
+  void emitIntrinsic(raw_ostream &OS) const;
+
+private:
+  std::string getMergeSuffix() const;
+  std::string mangleName(ClassKind LocalCK) const;
+  std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
+                                   std::string Proto) const;
+};
+
 class SVEEmitter {
+private:
+  RecordKeeper &Records;
+
 public:
-  // run - Emit arm_sve.h
-  void run(raw_ostream &o);
+  SVEEmitter(RecordKeeper &R) : Records(R) {}
+
+  /// Emit arm_sve.h.
+  void createHeader(raw_ostream &o);
+
+  /// Emit all the __builtin prototypes and code needed by Sema.
+  void createBuiltins(raw_ostream &o);
+
+  /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
+  void createCodeGenMap(raw_ostream &o);
+
+  /// Create intrinsic and add it to \p Out
+  void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
 };
 
 } // end anonymous namespace
 
 
+//===----------------------------------------------------------------------===//
+// Type implementation
+//===----------------------------------------------------------------------===//
+
+unsigned SVEType::getTypeFlags() const {
+  if (isFloat()) {
+    switch (ElementBitwidth) {
+    case 16: return SVETypeFlags::Float16;
+    case 32: return SVETypeFlags::Float32;
+    case 64: return SVETypeFlags::Float64;
+    default: llvm_unreachable("Unhandled float element bitwidth!");
+    }
+  }
+
+  if (isPredicateVector()) {
+    switch (ElementBitwidth) {
+    case 8:  return SVETypeFlags::Bool8;
+    case 16: return SVETypeFlags::Bool16;
+    case 32: return SVETypeFlags::Bool32;
+    case 64: return SVETypeFlags::Bool64;
+    default: llvm_unreachable("Unhandled predicate element bitwidth!");
+    }
+  }
+
+  switch (ElementBitwidth) {
+  case 8:  return SVETypeFlags::Int8;
+  case 16: return SVETypeFlags::Int16;
+  case 32: return SVETypeFlags::Int32;
+  case 64: return SVETypeFlags::Int64;
+  default: llvm_unreachable("Unhandled integer element bitwidth!");
+  }
+}
+
+std::string SVEType::builtin_str() const {
+  std::string S;
+  if (isVoid())
+    return "v";
+
+  if (isVoidPointer())
+    S += "v";
+  else if (!Float)
+    switch (ElementBitwidth) {
+    case 1: S += "b"; break;
+    case 8: S += "c"; break;
+    case 16: S += "s"; break;
+    case 32: S += "i"; break;
+    case 64: S += "Wi"; break;
+    case 128: S += "LLLi"; break;
+    default: llvm_unreachable("Unhandled case!");
+    }
+  else
+    switch (ElementBitwidth) {
+    case 16: S += "h"; break;
+    case 32: S += "f"; break;
+    case 64: S += "d"; break;
+    default: llvm_unreachable("Unhandled case!");
+    }
+
+  if (!isFloat()) {
+    if ((isChar() || isPointer()) && !isVoidPointer()) {
+      // Make chars and typed pointers explicitly signed.
+      if (Signed)
+        S = "S" + S;
+      else if (!Signed)
+        S = "U" + S;
+    } else if (!isVoidPointer() && !Signed) {
+      S = "U" + S;
+    }
+  }
+
+  // Constant indices are "int", but have the "constant expression" modifier.
+  if (isImmediate()) {
+    assert(!isFloat() && "fp immediates are not supported");
+    S = "I" + S;
+  }
+
+  if (isScalar()) {
+    if (Constant) S += "C";
+    if (Pointer) S += "*";
+    return S;
+  }
+
+  assert(isScalableVector() && "Unsupported type");
+  return "q" + utostr(getNumElements() * NumVectors) + S;
+}
+
+void SVEType::applyTypespec() {
+  for (char I : TS) {
+    switch (I) {
+    case 'P':
+      Predicate = true;
+      ElementBitwidth = 1;
+      break;
+    case 'U':
+      Signed = false;
+      break;
+    case 'c':
+      ElementBitwidth = 8;
+      break;
+    case 's':
+      ElementBitwidth = 16;
+      break;
+    case 'i':
+      ElementBitwidth = 32;
+      break;
+    case 'l':
+      ElementBitwidth = 64;
+      break;
+    case 'h':
+      Float = true;
+      ElementBitwidth = 16;
+      break;
+    case 'f':
+      Float = true;
+      ElementBitwidth = 32;
+      break;
+    case 'd':
+      Float = true;
+      ElementBitwidth = 64;
+      break;
+    default:
+      llvm_unreachable("Unhandled type code!");
+    }
+  }
+  assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
+}
+
+void SVEType::applyModifier(char Mod) {
+  switch (Mod) {
+  case 'v':
+    Void = true;
+    break;
+  case 'd':
+    DefaultType = true;
+    break;
+  case 'c':
+    Constant = true;
+    LLVM_FALLTHROUGH;
+  case 'p':
+    Pointer = true;
+    Bitwidth = ElementBitwidth;
+    NumVectors = 0;
+    break;
+  case 'P':
+    Signed = true;
+    Float = false;
+    Predicate = true;
+    Bitwidth = 16;
+    ElementBitwidth = 1;
+    break;
+  default:
+    llvm_unreachable("Unhandled character!");
+  }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Intrinsic implementation
+//===----------------------------------------------------------------------===//
+
+std::string Intrinsic::getBuiltinTypeStr() {
+  std::string S;
+
+  SVEType RetT = getReturnType();
+  // Since the return value must be one type, return a vector type of the
+  // appropriate width which we will bitcast.  An exception is made for
+  // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
+  // fashion, storing them to a pointer arg.
+  if (RetT.getNumVectors() > 1) {
+    S += "vv*"; // void result with void* first argument
+  } else
+    S += RetT.builtin_str();
+
+  for (unsigned I = 0; I < getNumParams(); ++I)
+    S += getParamType(I).builtin_str();
+
+  return S;
+}
+
+std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
+                                            std::string Proto) const {
+  std::string Ret = Name;
+  while (Ret.find('{') != std::string::npos) {
+    size_t Pos = Ret.find('{');
+    size_t End = Ret.find('}');
+    unsigned NumChars = End - Pos + 1;
+    assert(NumChars == 3 && "Unexpected template argument");
+
+    SVEType T;
+    char C = Ret[Pos+1];
+    switch(C) {
+    default:
+      llvm_unreachable("Unknown predication specifier");
+    case 'd':
+      T = SVEType(TS, 'd');
+      break;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+      T = SVEType(TS, Proto[C - '0']);
+      break;
+    }
+
+    // Replace templated arg with the right suffix (e.g. u32)
+    std::string TypeCode;
+    if (T.isInteger())
+      TypeCode = T.isSigned() ? 's' : 'u';
+    else if (T.isPredicateVector())
+      TypeCode = 'b';
+    else
+      TypeCode = 'f';
+    Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
+  }
+
+  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();
+
+  if (LocalCK == ClassG) {
+    // Remove the square brackets and everything in between.
+    while (S.find("[") != std::string::npos) {
+      auto Start = S.find("[");
+      auto End = S.find(']');
+      S.erase(Start, (End-Start)+1);
+    }
+  } else {
+    // Remove the square brackets.
+    while (S.find("[") != std::string::npos) {
+      auto BrPos = S.find('[');
+      if (BrPos != std::string::npos)
+        S.erase(BrPos, 1);
+      BrPos = S.find(']');
+      if (BrPos != std::string::npos)
+        S.erase(BrPos, 1);
+    }
+  }
+
+  // Replace all {d} like expressions with e.g. 'u32'
+  return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
+         getMergeSuffix();
+}
+
+void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
+  // Use the preprocessor to enable the non-overloaded builtins.
+  if (getClassKind() != ClassG || getProto().size() <= 1) {
+    OS << "#define " << mangleName(getClassKind())
+       << "(...) __builtin_sve_" << mangleName(ClassS)
+       << "(__VA_ARGS__)\n";
+  } else {
+    llvm_unreachable("Not yet implemented. Overloaded intrinsics will follow "
+                     "in a future patch");
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // SVEEmitter implementation
 //===----------------------------------------------------------------------===//
+void SVEEmitter::createIntrinsic(
+    Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
+  StringRef Name = R->getValueAsString("Name");
+  StringRef Proto = R->getValueAsString("Prototype");
+  StringRef Types = R->getValueAsString("Types");
+  StringRef Guard = R->getValueAsString("ArchGuard");
+  StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
+  int64_t Merge = R->getValueAsInt("Merge");
+  std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
+  int64_t MemEltType = R->getValueAsInt("MemEltType");
+
+  int64_t Flags = 0;
+  for (auto FlagRec : FlagsList)
+    Flags |= FlagRec->getValueAsInt("Value");
+
+  // Extract type specs from string
+  SmallVector<TypeSpec, 8> TypeSpecs;
+  TypeSpec Acc;
+  for (char I : Types) {
+    Acc.push_back(I);
+    if (islower(I)) {
+      TypeSpecs.push_back(TypeSpec(Acc));
+      Acc.clear();
+    }
+  }
+
+  // Remove duplicate type specs.
+  std::sort(TypeSpecs.begin(), TypeSpecs.end());
+  TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
+                  TypeSpecs.end());
 
-void SVEEmitter::run(raw_ostream &OS) {
+  // Create an Intrinsic for each type spec.
+  for (auto TS : TypeSpecs) {
+    Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, MemEltType,
+                                              LLVMName, Flags, TS, ClassS,
+                                              *this, Guard));
+  }
+}
+
+void SVEEmitter::createHeader(raw_ostream &OS) {
   OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
         "-----------------------------------===\n"
         " *\n"
@@ -77,7 +587,9 @@ void SVEEmitter::run(raw_ostream &OS) {
   OS << "#else\n\n";
 
   OS << "#include <stdint.h>\n\n";
-  OS << "#ifndef  __cplusplus\n";
+  OS << "#ifdef  __cplusplus\n";
+  OS << "extern \"C\" {\n";
+  OS << "#else\n";
   OS << "#include <stdbool.h>\n";
   OS << "#endif\n\n";
 
@@ -99,25 +611,120 @@ void SVEEmitter::run(raw_ostream &OS) {
   OS << "typedef __SVFloat64_t svfloat64_t;\n";
   OS << "typedef __SVBool_t  svbool_t;\n\n";
 
-  OS << "#define svld1_u8(...) __builtin_sve_svld1_u8(__VA_ARGS__)\n";
-  OS << "#define svld1_u16(...) __builtin_sve_svld1_u16(__VA_ARGS__)\n";
-  OS << "#define svld1_u32(...) __builtin_sve_svld1_u32(__VA_ARGS__)\n";
-  OS << "#define svld1_u64(...) __builtin_sve_svld1_u64(__VA_ARGS__)\n";
-  OS << "#define svld1_s8(...) __builtin_sve_svld1_s8(__VA_ARGS__)\n";
-  OS << "#define svld1_s16(...) __builtin_sve_svld1_s16(__VA_ARGS__)\n";
-  OS << "#define svld1_s32(...) __builtin_sve_svld1_s32(__VA_ARGS__)\n";
-  OS << "#define svld1_s64(...) __builtin_sve_svld1_s64(__VA_ARGS__)\n";
-  OS << "#define svld1_f16(...) __builtin_sve_svld1_f16(__VA_ARGS__)\n";
-  OS << "#define svld1_f32(...) __builtin_sve_svld1_f32(__VA_ARGS__)\n";
-  OS << "#define svld1_f64(...) __builtin_sve_svld1_f64(__VA_ARGS__)\n";
-
-  OS << "#endif /*__ARM_FEATURE_SVE */\n";
+  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+  for (auto *R : RV)
+    createIntrinsic(R, Defs);
+
+  // Sort intrinsics in header file by following order/priority:
+  // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
+  // - Class (is intrinsic overloaded or not)
+  // - Intrinsic name
+  std::stable_sort(
+      Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
+                                   const std::unique_ptr<Intrinsic> &B) {
+        return A->getGuard() < B->getGuard() ||
+               (unsigned)A->getClassKind() < (unsigned)B->getClassKind() ||
+               A->getName() < B->getName();
+      });
+
+  StringRef InGuard = "";
+  for (auto &I : Defs) {
+    // Emit #endif/#if pair if needed.
+    if (I->getGuard() != InGuard) {
+      if (!InGuard.empty())
+        OS << "#endif  //" << InGuard << "\n";
+      InGuard = I->getGuard();
+      if (!InGuard.empty())
+        OS << "\n#if " << InGuard << "\n";
+    }
+
+    // Actually emit the intrinsic declaration.
+    I->emitIntrinsic(OS);
+  }
+
+  if (!InGuard.empty())
+    OS << "#endif  //" << InGuard << "\n";
+
+  OS << "#ifdef __cplusplus\n";
+  OS << "} // extern \"C\"\n";
+  OS << "#endif\n\n";
+  OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
   OS << "#endif /* __ARM_SVE_H */\n";
 }
 
+void SVEEmitter::createBuiltins(raw_ostream &OS) {
+  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+  for (auto *R : RV)
+    createIntrinsic(R, Defs);
+
+  // The mappings must be sorted based on BuiltinID.
+  llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
+                      const std::unique_ptr<Intrinsic> &B) {
+    return A->getMangledName() < B->getMangledName();
+  });
+
+  OS << "#ifdef GET_SVE_BUILTINS\n";
+  for (auto &Def : Defs) {
+    // Only create BUILTINs for non-overloaded intrinsics, as overloaded
+    // declarations only live in the header file.
+    if (Def->getClassKind() != ClassG)
+      OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
+         << Def->getBuiltinTypeStr() << "\", \"n\")\n";
+  }
+  OS << "#endif\n\n";
+}
+
+void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
+  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+  for (auto *R : RV)
+    createIntrinsic(R, Defs);
+
+  // The mappings must be sorted based on BuiltinID.
+  llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
+                      const std::unique_ptr<Intrinsic> &B) {
+    return A->getMangledName() < B->getMangledName();
+  });
+
+  OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
+  for (auto &Def : Defs) {
+    // Builtins only exist for non-overloaded intrinsics, overloaded
+    // declarations only live in the header file.
+    if (Def->getClassKind() == ClassG)
+      continue;
+
+    assert(!Def->isFlagSet(SVETypeFlags::EltTypeMask) &&
+           !Def->isFlagSet(SVETypeFlags::MemEltTypeMask) &&
+           "Unexpected mask value");
+    uint64_t Flags = Def->getFlags().getBits() |
+                     Def->getBaseType().getTypeFlags() |
+                     Def->getMemEltTypeEnum();
+    auto FlagString = std::to_string(Flags);
+
+    std::string LLVMName = Def->getLLVMName();
+    std::string Builtin = Def->getMangledName();
+    if (!LLVMName.empty())
+      OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
+         << "),\n";
+    else
+      OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
+  }
+  OS << "#endif\n\n";
+}
+
 namespace clang {
 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
-  SVEEmitter().run(OS);
+  SVEEmitter(Records).createHeader(OS);
+}
+
+void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
+  SVEEmitter(Records).createBuiltins(OS);
+}
+
+void EmitSveCodeGenMap(RecordKeeper &Records, raw_ostream &OS) {
+  SVEEmitter(Records).createCodeGenMap(OS);
 }
 
 } // End namespace clang

diff  --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index b0f9120416bc..3d61a9bf8e6e 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -71,6 +71,8 @@ enum ActionType {
   GenArmMveBuiltinCG,
   GenArmMveBuiltinAliases,
   GenArmSveHeader,
+  GenArmSveBuiltins,
+  GenArmSveCodeGenMap,
   GenArmCdeHeader,
   GenArmCdeBuiltinDef,
   GenArmCdeBuiltinSema,
@@ -188,6 +190,10 @@ cl::opt<ActionType> Action(
                    "Generate ARM NEON tests for clang"),
         clEnumValN(GenArmSveHeader, "gen-arm-sve-header",
                    "Generate arm_sve.h for clang"),
+        clEnumValN(GenArmSveBuiltins, "gen-arm-sve-builtins",
+                   "Generate arm_sve_builtins.inc for clang"),
+        clEnumValN(GenArmSveCodeGenMap, "gen-arm-sve-codegenmap",
+                   "Generate arm_sve_codegenmap.inc for clang"),
         clEnumValN(GenArmMveHeader, "gen-arm-mve-header",
                    "Generate arm_mve.h for clang"),
         clEnumValN(GenArmMveBuiltinDef, "gen-arm-mve-builtin-def",
@@ -372,6 +378,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
   case GenArmSveHeader:
     EmitSveHeader(Records, OS);
     break;
+  case GenArmSveBuiltins:
+    EmitSveBuiltins(Records, OS);
+    break;
+  case GenArmSveCodeGenMap:
+    EmitSveCodeGenMap(Records, OS);
+    break;
   case GenArmCdeHeader:
     EmitCdeHeader(Records, OS);
     break;

diff  --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index 3ff6b26c4052..fb19dcc7588d 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -92,6 +92,8 @@ void EmitNeonSema2(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 void EmitNeonTest2(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 
 void EmitSveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSveBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSveCodeGenMap(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 
 void EmitMveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 void EmitMveBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);


        


More information about the cfe-commits mailing list