[clang] c5b8146 - Reland D75470 [SVE] Auto-generate builtins and header for svld1.
Sander de Smalen via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 18 04:18:02 PDT 2020
Author: Sander de Smalen
Date: 2020-03-18T11:16:28Z
New Revision: c5b81466c2bcc194e5563f39f5be3638760b4849
URL: https://github.com/llvm/llvm-project/commit/c5b81466c2bcc194e5563f39f5be3638760b4849
DIFF: https://github.com/llvm/llvm-project/commit/c5b81466c2bcc194e5563f39f5be3638760b4849.diff
LOG: Reland D75470 [SVE] Auto-generate builtins and header for svld1.
Reworked the patch to avoid sharing a header (SVETypeFlags.h) between
include/clang/Basic and utils/TableGen/SveEmitter.cpp. Now the patch
generates the enum/flags which is included in TargetBuiltins.h.
Also renamed one of the SveEmitter options to be in line with MVE.
Summary:
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.
Added:
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/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..5eda48e8f250 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -60,7 +60,15 @@ 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_builtin_cg.inc -gen-arm-sve-builtin-codegen
+ SOURCE arm_sve.td
+ TARGET ClangARMSveBuiltinCG)
+clang_tablegen(arm_sve_typeflags.inc -gen-arm-sve-typeflags
+ SOURCE arm_sve.td
+ TARGET ClangARMSveTypeFlags)
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..fd339ef34e1e 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
@@ -149,6 +160,44 @@ namespace clang {
bool isQuad() const { return (Flags & QuadFlag) != 0; }
};
+ /// Flags to identify the types for overloaded SVE builtins.
+ class SVETypeFlags {
+ uint64_t Flags;
+
+ public:
+#define LLVM_GET_SVE_TYPEFLAGS
+#include "clang/Basic/arm_sve_typeflags.inc"
+#undef LLVM_GET_SVE_TYPEFLAGS
+
+ enum EltType {
+#define LLVM_GET_SVE_ELTTYPES
+#include "clang/Basic/arm_sve_typeflags.inc"
+#undef LLVM_GET_SVE_ELTTYPES
+ };
+
+ enum MemEltType {
+#define LLVM_GET_SVE_MEMELTTYPES
+#include "clang/Basic/arm_sve_typeflags.inc"
+#undef LLVM_GET_SVE_MEMELTTYPES
+ };
+
+ SVETypeFlags(uint64_t F) : Flags(F) {}
+ SVETypeFlags(EltType ET, bool IsUnsigned) : Flags(ET) {}
+
+ EltType getEltType() const {
+ return (EltType)((Flags & EltTypeMask) - FirstEltType);
+ }
+
+ MemEltType getMemEltType() const {
+ return (MemEltType)((Flags & MemEltTypeMask) - FirstMemEltType);
+ }
+
+ bool isLoad() const { return Flags & IsLoad; }
+
+ uint64_t getBits() const { return Flags; }
+ bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
+ };
+
/// Hexagon builtins
namespace Hexagon {
enum {
diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td
index 10417cdfcdea..012f639527c7 100644
--- a/clang/include/clang/Basic/arm_sve.td
+++ b/clang/include/clang/Basic/arm_sve.td
@@ -12,3 +12,128 @@
// 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 EltType<int val> {
+ int Value = val;
+}
+def EltTyInvalid : EltType<0>;
+def EltTyInt8 : EltType<1>;
+def EltTyInt16 : EltType<2>;
+def EltTyInt32 : EltType<3>;
+def EltTyInt64 : EltType<4>;
+def EltTyFloat16 : EltType<5>;
+def EltTyFloat32 : EltType<6>;
+def EltTyFloat64 : EltType<7>;
+def EltTyBool8 : EltType<8>;
+def EltTyBool16 : EltType<9>;
+def EltTyBool32 : EltType<10>;
+def EltTyBool64 : EltType<11>;
+
+class MemEltType<int val> {
+ int Value = val;
+}
+def MemEltTyDefault : MemEltType<0>;
+def MemEltTyInt8 : MemEltType<1>;
+def MemEltTyInt16 : MemEltType<2>;
+def MemEltTyInt32 : MemEltType<3>;
+def MemEltTyInt64 : MemEltType<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>;
+def FirstEltType : FlagType<0x00000001>;
+// : :
+// : :
+def EltTypeMask : FlagType<0x0000000f>;
+def FirstMemEltType : FlagType<0x00000010>;
+// : :
+// : :
+def MemEltTypeMask : FlagType<0x00000070>;
+def IsLoad : FlagType<0x00000080>;
+
+// Every intrinsic subclasses Inst.
+class Inst<string n, string p, string t, MergeType mt, string i,
+ list<FlagType> ft, MemEltType 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,
+ MemEltType 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 336c7491a5cc..74bb6900b19e 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..b0be1ecb5454 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4576,7 +4576,7 @@ enum {
};
namespace {
-struct NeonIntrinsicInfo {
+struct ARMVectorIntrinsicInfo {
const char *NameHint;
unsigned BuiltinID;
unsigned LLVMIntrinsic;
@@ -4586,7 +4586,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 +4604,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 +4885,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 +5054,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 +5284,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_builtin_cg.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 +5318,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 +5366,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 +6881,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 +7453,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 +7520,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 +7918,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 +8758,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..8b53e376cb0d 100644
--- a/clang/utils/TableGen/SveEmitter.cpp
+++ b/clang/utils/TableGen/SveEmitter.cpp
@@ -24,7 +24,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/TableGen/Record.h"
@@ -36,26 +36,533 @@
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;
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;
+
+ unsigned 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()=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; }
+
+ unsigned getFlags() const { return Flags; }
+ bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
+
+ /// 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;
+ llvm::StringMap<uint64_t> EltTypes;
+ llvm::StringMap<uint64_t> MemEltTypes;
+ llvm::StringMap<uint64_t> FlagTypes;
+
+ unsigned getTypeFlags(const SVEType &T);
public:
- // run - Emit arm_sve.h
- void run(raw_ostream &o);
+ SVEEmitter(RecordKeeper &R) : Records(R) {
+ for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
+ EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
+ for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
+ MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
+ for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
+ FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
+ }
+
+ /// 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 the SVETypeFlags used in CGBuiltins
+ void createTypeFlags(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 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())
+ 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
+ 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 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;
+ 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());
+
+ // 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));
+ }
+}
-void SVEEmitter::run(raw_ostream &OS) {
+void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
"-----------------------------------===\n"
" *\n"
@@ -77,7 +584,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 +608,136 @@ 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;
+
+ uint64_t Flags = Def->getFlags() | getTypeFlags(Def->getBaseType());
+ 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";
+}
+
+/// Create the SVETypeFlags used in CGBuiltins
+void SVEEmitter::createTypeFlags(raw_ostream &OS) {
+ OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
+ for (auto &KV : FlagTypes)
+ OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
+ for (auto &KV : EltTypes)
+ OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
+ for (auto &KV : MemEltTypes)
+ OS << " " << KV.getKey() << " = " << KV.getValue() << ",\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 EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createCodeGenMap(OS);
+}
+void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createTypeFlags(OS);
}
} // End namespace clang
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index b0f9120416bc..393cd840d189 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -71,6 +71,9 @@ enum ActionType {
GenArmMveBuiltinCG,
GenArmMveBuiltinAliases,
GenArmSveHeader,
+ GenArmSveBuiltins,
+ GenArmSveBuiltinCG,
+ GenArmSveTypeFlags,
GenArmCdeHeader,
GenArmCdeBuiltinDef,
GenArmCdeBuiltinSema,
@@ -188,6 +191,12 @@ 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(GenArmSveBuiltinCG, "gen-arm-sve-builtin-codegen",
+ "Generate arm_sve_builtin_cg_map.inc for clang"),
+ clEnumValN(GenArmSveTypeFlags, "gen-arm-sve-typeflags",
+ "Generate arm_sve_typeflags.inc for clang"),
clEnumValN(GenArmMveHeader, "gen-arm-mve-header",
"Generate arm_mve.h for clang"),
clEnumValN(GenArmMveBuiltinDef, "gen-arm-mve-builtin-def",
@@ -372,6 +381,15 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenArmSveHeader:
EmitSveHeader(Records, OS);
break;
+ case GenArmSveBuiltins:
+ EmitSveBuiltins(Records, OS);
+ break;
+ case GenArmSveBuiltinCG:
+ EmitSveBuiltinCG(Records, OS);
+ break;
+ case GenArmSveTypeFlags:
+ EmitSveTypeFlags(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..ee9d447c50e6 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -92,6 +92,9 @@ 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 EmitSveBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSveTypeFlags(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