Revert "[SVE] Auto-generate builtins and header for svld1."

This reverts commit 8b409eabaf.

Reverting this patch for now because it breaks some buildbots.
This commit is contained in:
Sander de Smalen 2020-03-16 15:22:15 +00:00
parent 5c261c9c45
commit 6ce537ccfc
12 changed files with 73 additions and 924 deletions

View File

@ -1,67 +0,0 @@
//===- 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

View File

@ -99,6 +99,19 @@ 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, "")

View File

@ -1,20 +0,0 @@
//===--- 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

View File

@ -60,12 +60,7 @@ 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)

View File

@ -41,22 +41,11 @@ 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

View File

@ -12,110 +12,3 @@
// 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]>;

View File

@ -26,10 +26,6 @@ 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) \

View File

@ -23,7 +23,6 @@
#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"
@ -4577,7 +4576,7 @@ enum {
};
namespace {
struct ARMVectorIntrinsicInfo {
struct NeonIntrinsicInfo {
const char *NameHint;
unsigned BuiltinID;
unsigned LLVMIntrinsic;
@ -4587,7 +4586,7 @@ struct ARMVectorIntrinsicInfo {
bool operator<(unsigned RHSBuiltinID) const {
return BuiltinID < RHSBuiltinID;
}
bool operator<(const ARMVectorIntrinsicInfo &TE) const {
bool operator<(const NeonIntrinsicInfo &TE) const {
return BuiltinID < TE.BuiltinID;
}
};
@ -4605,7 +4604,7 @@ struct ARMVectorIntrinsicInfo {
Intrinsic::LLVMIntrinsic, Intrinsic::AltLLVMIntrinsic, \
TypeModifier }
static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
static const NeonIntrinsicInfo 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),
@ -4886,7 +4885,7 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP0(vzipq_v)
};
static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP1(vabs_v, aarch64_neon_abs, 0),
NEONMAP1(vabsq_v, aarch64_neon_abs, 0),
NEONMAP0(vaddhn_v),
@ -5055,7 +5054,7 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP0(vtstq_v),
};
static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = {
static const NeonIntrinsicInfo AArch64SISDIntrinsicMap[] = {
NEONMAP1(vabdd_f64, aarch64_sisd_fabd, Add1ArgType),
NEONMAP1(vabds_f32, aarch64_sisd_fabd, Add1ArgType),
NEONMAP1(vabsd_s64, aarch64_neon_abs, Add1ArgType),
@ -5285,32 +5284,15 @@ static const ARMVectorIntrinsicInfo 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 ARMVectorIntrinsicInfo *
findARMVectorIntrinsicInMap(ArrayRef<ARMVectorIntrinsicInfo> IntrinsicMap,
unsigned BuiltinID, bool &MapProvenSorted) {
static const NeonIntrinsicInfo *
findNeonIntrinsicInMap(ArrayRef<NeonIntrinsicInfo> IntrinsicMap,
unsigned BuiltinID, bool &MapProvenSorted) {
#ifndef NDEBUG
if (!MapProvenSorted) {
@ -5319,8 +5301,7 @@ findARMVectorIntrinsicInMap(ArrayRef<ARMVectorIntrinsicInfo> IntrinsicMap,
}
#endif
const ARMVectorIntrinsicInfo *Builtin =
llvm::lower_bound(IntrinsicMap, BuiltinID);
const NeonIntrinsicInfo *Builtin = llvm::lower_bound(IntrinsicMap, BuiltinID);
if (Builtin != IntrinsicMap.end() && Builtin->BuiltinID == BuiltinID)
return Builtin;
@ -5367,9 +5348,10 @@ Function *CodeGenFunction::LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
return CGM.getIntrinsic(IntrinsicID, Tys);
}
static Value *EmitCommonNeonSISDBuiltinExpr(
CodeGenFunction &CGF, const ARMVectorIntrinsicInfo &SISDInfo,
SmallVectorImpl<Value *> &Ops, const CallExpr *E) {
static Value *EmitCommonNeonSISDBuiltinExpr(CodeGenFunction &CGF,
const NeonIntrinsicInfo &SISDInfo,
SmallVectorImpl<Value *> &Ops,
const CallExpr *E) {
unsigned BuiltinID = SISDInfo.BuiltinID;
unsigned int Int = SISDInfo.LLVMIntrinsic;
unsigned Modifier = SISDInfo.TypeModifier;
@ -6882,7 +6864,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 ARMVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
IntrinsicMap, BuiltinID, NEONSIMDIntrinsicsProvenSorted);
if (Builtin)
return EmitCommonNeonBuiltinExpr(
@ -7454,40 +7436,9 @@ 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;
@ -7521,6 +7472,27 @@ 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));
@ -7919,7 +7891,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
auto SISDMap = makeArrayRef(AArch64SISDIntrinsicMap);
const ARMVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
SISDMap, BuiltinID, AArch64SISDIntrinsicsProvenSorted);
if (Builtin) {
@ -8759,8 +8731,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 = findARMVectorIntrinsicInMap(AArch64SIMDIntrinsicMap, BuiltinID,
AArch64SIMDIntrinsicsProvenSorted);
Builtin = findNeonIntrinsicInMap(AArch64SIMDIntrinsicMap, BuiltinID,
AArch64SIMDIntrinsicsProvenSorted);
if (Builtin)
return EmitCommonNeonBuiltinExpr(

View File

@ -3904,7 +3904,6 @@ public:
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);

View File

@ -29,7 +29,6 @@
#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>
@ -37,535 +36,26 @@
using namespace llvm;
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;
//===----------------------------------------------------------------------===//
// SVEEmitter
//===----------------------------------------------------------------------===//
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:
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);
// run - Emit arm_sve.h
void run(raw_ostream &o);
};
} // 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());
// 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) {
void SVEEmitter::run(raw_ostream &OS) {
OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
"-----------------------------------===\n"
" *\n"
@ -587,9 +77,7 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "#else\n\n";
OS << "#include <stdint.h>\n\n";
OS << "#ifdef __cplusplus\n";
OS << "extern \"C\" {\n";
OS << "#else\n";
OS << "#ifndef __cplusplus\n";
OS << "#include <stdbool.h>\n";
OS << "#endif\n\n";
@ -611,120 +99,25 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "typedef __SVFloat64_t svfloat64_t;\n";
OS << "typedef __SVBool_t svbool_t;\n\n";
SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
for (auto *R : RV)
createIntrinsic(R, Defs);
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";
// 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_FEATURE_SVE */\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(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);
SVEEmitter().run(OS);
}
} // End namespace clang

View File

@ -71,8 +71,6 @@ enum ActionType {
GenArmMveBuiltinCG,
GenArmMveBuiltinAliases,
GenArmSveHeader,
GenArmSveBuiltins,
GenArmSveCodeGenMap,
GenArmCdeHeader,
GenArmCdeBuiltinDef,
GenArmCdeBuiltinSema,
@ -190,10 +188,6 @@ 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",
@ -378,12 +372,6 @@ 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;

View File

@ -92,8 +92,6 @@ 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);