diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -39,6 +39,8 @@ // A -> "reference" to __builtin_va_list // V -> Vector, followed by the number of elements and the base type. // q -> Scalable vector, followed by the number of elements and the base type. +// Q -> target builtin type, followed by a character to distinguish the builtin type +// Qa -> AArch64 svcount_t builtin type. // E -> ext_vector, followed by the number of elements and the base type. // X -> _Complex, followed by the base type. // Y -> ptrdiff_t diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -53,6 +53,7 @@ // Typespec modifiers // ------------------ // P: boolean +// Qa: svcount // U: unsigned // Prototype modifiers @@ -120,6 +121,9 @@ // Y: const pointer to uint32_t // Z: const pointer to uint64_t +// Prototype modifiers added for SVE2p1 +// }: svcount_t + class MergeType { int Value = val; string Suffix = suffix; @@ -2107,6 +2111,7 @@ let TargetGuard = "sve2p1" in { def SVFCLAMP : SInst<"svclamp[_{d}]", "dddd", "hfd", MergeNone, "aarch64_sve_fclamp", [], []>; + def SVPTRUE_COUNT : SInst<"svptrue_{d}", "}v", "QacQasQaiQal", MergeNone, "aarch64_sve_ptrue_{d}", [IsOverloadNone], []>; } let TargetGuard = "sve2p1" in { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11455,6 +11455,17 @@ Type = Context.getScalableVectorType(ElementType, NumElements); break; } + case 'Q': { + switch (*Str++) { + case 'a': { + Type = Context.SveCountTy; + break; + } + default: + llvm_unreachable("Unexpected target builtin type"); + } + break; + } case 'V': { char *End; unsigned NumElements = strtoul(Str, &End, 10); diff --git a/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_ptrue.c b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_ptrue.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_ptrue.c @@ -0,0 +1,62 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK + +#include + +// CHECK-LABEL: @test_svptrue_c8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c8() +// CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svptrue_c8v( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c8() +// CPP-CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +svcount_t test_svptrue_c8(void) { + return svptrue_c8(); +} + +// CHECK-LABEL: @test_svptrue_c16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c16() +// CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z16test_svptrue_c16v( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c16() +// CPP-CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +svcount_t test_svptrue_c16(void) { + return svptrue_c16(); +} + +// CHECK-LABEL: @test_svptrue_c32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c32() +// CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z16test_svptrue_c32v( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c32() +// CPP-CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +svcount_t test_svptrue_c32(void) { + return svptrue_c32(); +} + +// CHECK-LABEL: @test_svptrue_c64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c64() +// CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z16test_svptrue_c64v( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c64() +// CPP-CHECK-NEXT: ret target("aarch64.svcount") [[TMP0]] +// +svcount_t test_svptrue_c64(void) { + return svptrue_c64(); +} diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -66,7 +66,8 @@ class SVEType { TypeSpec TS; bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat; - bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp; + bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp, + Svcount; unsigned Bitwidth, ElementBitwidth, NumVectors; public: @@ -76,7 +77,8 @@ : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), Constant(false), Pointer(false), BFloat(false), DefaultType(false), IsScalable(true), Predicate(false), PredicatePattern(false), - PrefetchOp(false), Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) { + PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U), + NumVectors(1) { if (!TS.empty()) applyTypespec(); applyModifier(CharMod); @@ -95,13 +97,16 @@ bool isFloat() const { return Float && !BFloat; } bool isBFloat() const { return BFloat && !Float; } bool isFloatingPoint() const { return Float || BFloat; } - bool isInteger() const { return !isFloatingPoint() && !Predicate; } + bool isInteger() const { + return !isFloatingPoint() && !Predicate && !Svcount; + } bool isScalarPredicate() const { return !isFloatingPoint() && Predicate && NumVectors == 0; } bool isPredicateVector() const { return Predicate; } bool isPredicatePattern() const { return PredicatePattern; } bool isPrefetchOp() const { return PrefetchOp; } + bool isSvcount() const { return Svcount; } bool isConstant() const { return Constant; } unsigned getElementSizeInBits() const { return ElementBitwidth; } unsigned getNumVectors() const { return NumVectors; } @@ -203,6 +208,9 @@ /// ClassS, so will add type suffixes such as _u32/_s32. std::string getMangledName() const { return mangleName(ClassS); } + /// As above, but mangles the LLVM name instead. + std::string getMangledLLVMName() const { return mangleLLVMName(); } + /// 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(..)'. @@ -233,6 +241,7 @@ private: std::string getMergeSuffix() const { return MergeSuffix; } std::string mangleName(ClassKind LocalCK) const; + std::string mangleLLVMName() const; std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, std::string Proto) const; }; @@ -366,6 +375,9 @@ if (isScalarPredicate()) return "b"; + if (isSvcount()) + return "Qa"; + if (isVoidPointer()) S += "v"; else if (!isFloatingPoint()) @@ -429,13 +441,15 @@ if (Void) S += "void"; else { - if (isScalableVector()) + if (isScalableVector() || isSvcount()) S += "sv"; if (!Signed && !isFloatingPoint()) S += "u"; if (Float) S += "float"; + else if (isSvcount()) + S += "count"; else if (isScalarPredicate() || isPredicateVector()) S += "bool"; else if (isBFloat()) @@ -443,7 +457,7 @@ else S += "int"; - if (!isScalarPredicate() && !isPredicateVector()) + if (!isScalarPredicate() && !isPredicateVector() && !isSvcount()) S += utostr(ElementBitwidth); if (!isScalableVector() && isVector()) S += "x" + utostr(getNumElements()); @@ -461,8 +475,15 @@ return S; } void SVEType::applyTypespec() { - for (char I : TS) { - switch (I) { + for (size_t I = 0; I < TS.size(); I++) { + switch (TS[I]) { + case 'Q': + if (TS[I + 1] == 'a') { + Svcount = true; + I++; + } else + llvm_unreachable("Unknow Modifier"); + break; case 'P': Predicate = true; break; @@ -554,6 +575,7 @@ Float = false; BFloat = false; Predicate = true; + Svcount = false; Bitwidth = 16; ElementBitwidth = 1; break; @@ -593,18 +615,21 @@ break; case 'u': Predicate = false; + Svcount = false; Signed = false; Float = false; BFloat = false; break; case 'x': Predicate = false; + Svcount = false; Signed = true; Float = false; BFloat = false; break; case 'i': Predicate = false; + Svcount = false; Float = false; BFloat = false; ElementBitwidth = Bitwidth = 64; @@ -614,6 +639,7 @@ break; case 'I': Predicate = false; + Svcount = false; Float = false; BFloat = false; ElementBitwidth = Bitwidth = 32; @@ -624,6 +650,7 @@ break; case 'J': Predicate = false; + Svcount = false; Float = false; BFloat = false; ElementBitwidth = Bitwidth = 32; @@ -634,6 +661,7 @@ break; case 'k': Predicate = false; + Svcount = false; Signed = true; Float = false; BFloat = false; @@ -642,6 +670,7 @@ break; case 'l': Predicate = false; + Svcount = false; Signed = true; Float = false; BFloat = false; @@ -650,6 +679,7 @@ break; case 'm': Predicate = false; + Svcount = false; Signed = false; Float = false; BFloat = false; @@ -658,6 +688,7 @@ break; case 'n': Predicate = false; + Svcount = false; Signed = false; Float = false; BFloat = false; @@ -696,17 +727,20 @@ break; case 'O': Predicate = false; + Svcount = false; Float = true; ElementBitwidth = 16; break; case 'M': Predicate = false; + Svcount = false; Float = true; BFloat = false; ElementBitwidth = 32; break; case 'N': Predicate = false; + Svcount = false; Float = true; ElementBitwidth = 64; break; @@ -800,6 +834,14 @@ NumVectors = 0; Signed = false; break; + case '}': + Predicate = false; + Signed = true; + Svcount = true; + NumVectors = 0; + Float = false; + BFloat = false; + break; default: llvm_unreachable("Unhandled character!"); } @@ -880,6 +922,8 @@ std::string TypeCode; if (T.isInteger()) TypeCode = T.isSigned() ? 's' : 'u'; + else if (T.isSvcount()) + TypeCode = 'c'; else if (T.isPredicateVector()) TypeCode = 'b'; else if (T.isBFloat()) @@ -892,6 +936,13 @@ return Ret; } +std::string Intrinsic::mangleLLVMName() const { + std::string S = getLLVMName(); + + // Replace all {d} like expressions with e.g. 'u32' + return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()); +} + std::string Intrinsic::mangleName(ClassKind LocalCK) const { std::string S = getName(); @@ -960,7 +1011,7 @@ return encodeEltType("EltTyBFloat16"); } - if (T.isPredicateVector()) { + if (T.isPredicateVector() || T.isSvcount()) { switch (T.getElementSizeInBits()) { case 8: return encodeEltType("EltTyBool8"); @@ -1016,9 +1067,10 @@ // Extract type specs from string SmallVector TypeSpecs; TypeSpec Acc; - for (char I : Types) { - Acc.push_back(I); - if (islower(I)) { + for (size_t I = 0; I < Types.size(); I++) { + Acc.push_back(Types[I]); + if (islower(Types[I]) && !(Types[I] == 'a' && Types[I - 1] == 'Q')) { + // 'a' is also part of Q modifier. Q is target builtin type. TypeSpecs.push_back(TypeSpec(Acc)); Acc.clear(); } @@ -1148,6 +1200,8 @@ OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n"; OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n"; + OS << "typedef __SVCount_t svcount_t;\n\n"; + OS << "enum svpattern\n"; OS << "{\n"; OS << " SV_POW2 = 0,\n"; @@ -1303,7 +1357,7 @@ uint64_t Flags = Def->getFlags(); auto FlagString = std::to_string(Flags); - std::string LLVMName = Def->getLLVMName(); + std::string LLVMName = Def->getMangledLLVMName(); std::string Builtin = Def->getMangledName(); if (!LLVMName.empty()) OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString