diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ecd2f9eb2881..3a1abd4c7892b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2234,7 +2234,8 @@ class Sema final { bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum); bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); - void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D); + void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap); bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b55f433a8be76..72393bea62052 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2065,8 +2065,11 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } - if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType()) - checkRVVTypeSupport(Ty, Loc, D); + if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType() && FD) { + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + checkRVVTypeSupport(Ty, Loc, D, CallerFeatureMap); + } // Don't allow SVE types in functions without a SVE target. if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 0844958133093..447e73686b4f3 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5760,57 +5760,6 @@ static bool CheckInvalidVLENandLMUL(const TargetInfo &TI, CallExpr *TheCall, bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { - // CodeGenFunction can also detect this, but this gives a better error - // message. - bool FeatureMissing = false; - SmallVector ReqFeatures; - StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); - Features.split(ReqFeatures, ',', -1, false); - - // Check if each required feature is included - for (StringRef F : ReqFeatures) { - SmallVector ReqOpFeatures; - F.split(ReqOpFeatures, '|'); - - if (llvm::none_of(ReqOpFeatures, - [&TI](StringRef OF) { return TI.hasFeature(OF); })) { - std::string FeatureStrs; - bool IsExtension = true; - for (StringRef OF : ReqOpFeatures) { - // If the feature is 64bit, alter the string so it will print better in - // the diagnostic. - if (OF == "64bit") { - assert(ReqOpFeatures.size() == 1 && "Expected '64bit' to be alone"); - OF = "RV64"; - IsExtension = false; - } - if (OF == "32bit") { - assert(ReqOpFeatures.size() == 1 && "Expected '32bit' to be alone"); - OF = "RV32"; - IsExtension = false; - } - - // Convert features like "zbr" and "experimental-zbr" to "Zbr". - OF.consume_front("experimental-"); - std::string FeatureStr = OF.str(); - FeatureStr[0] = std::toupper(FeatureStr[0]); - // Combine strings. - FeatureStrs += FeatureStrs.empty() ? "" : ", "; - FeatureStrs += "'"; - FeatureStrs += FeatureStr; - FeatureStrs += "'"; - } - // Error message - FeatureMissing = true; - Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) - << IsExtension - << TheCall->getSourceRange() << StringRef(FeatureStrs); - } - } - - if (FeatureMissing) - return true; - // vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx, // vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*. switch (BuiltinID) { @@ -6714,36 +6663,35 @@ bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, return false; } -void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D) { - const TargetInfo &TI = Context.getTargetInfo(); - +void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap) { ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(Ty->castAs()); unsigned EltSize = Context.getTypeSize(Info.ElementType); unsigned MinElts = Info.EC.getKnownMinValue(); if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Double) && - !TI.hasFeature("zve64d")) + !FeatureMap.lookup("zve64d")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d"; // (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at // least zve64x else if (((EltSize == 64 && Info.ElementType->isIntegerType()) || MinElts == 1) && - !TI.hasFeature("zve64x")) + !FeatureMap.lookup("zve64x")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x"; - else if (Info.ElementType->isFloat16Type() && !TI.hasFeature("zvfh") && - !TI.hasFeature("zvfhmin")) + else if (Info.ElementType->isFloat16Type() && !FeatureMap.lookup("zvfh") && + !FeatureMap.lookup("zvfhmin")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfh or zvfhmin"; else if (Info.ElementType->isBFloat16Type() && - !TI.hasFeature("experimental-zvfbfmin")) + !FeatureMap.lookup("experimental-zvfbfmin")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin"; else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Float) && - !TI.hasFeature("zve32f")) + !FeatureMap.lookup("zve32f")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f"; // Given that caller already checked isRVVType() before calling this function, // if we don't have at least zve32x supported, then we need to emit error. - else if (!TI.hasFeature("zve32x")) + else if (!FeatureMap.lookup("zve32x")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x"; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 66aad2592cb38..8b44d24f5273a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8962,8 +8962,13 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } } - if (T->isRVVSizelessBuiltinType()) - checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext)); + if (T->isRVVSizelessBuiltinType() && isa(CurContext)) { + const FunctionDecl *FD = cast(CurContext); + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext), + CallerFeatureMap); + } } /// Perform semantic checking on a newly-created variable diff --git a/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c b/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c index 35d6973818d01..b303d71304bf3 100644 --- a/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c +++ b/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c @@ -2,6 +2,28 @@ // RUN: not %clang_cc1 -triple riscv64 -target-feature +zifencei -target-feature +m -target-feature +a \ // RUN: -emit-llvm %s 2>&1 | FileCheck %s +#include + +void test_builtin() { +// CHECK: error: '__builtin_rvv_vsetvli' needs target feature zve32x + __riscv_vsetvl_e8m8(1); +} + +void test_rvv_i32_type() { +// CHECK: error: RISC-V type 'vint32m1_t' (aka '__rvv_int32m1_t') requires the 'zve32x' extension + vint32m1_t v; +} + +void test_rvv_f32_type() { +// CHECK: error: RISC-V type 'vfloat32m1_t' (aka '__rvv_float32m1_t') requires the 'zve32f' extension + vfloat32m1_t v; +} + +void test_rvv_f64_type() { +// CHECK: error: RISC-V type 'vfloat64m1_t' (aka '__rvv_float64m1_t') requires the 'zve64d' extension + vfloat64m1_t v; +} + // CHECK: error: duplicate 'arch=' in the 'target' attribute string; __attribute__((target("arch=rv64gc;arch=rv64gc_zbb"))) void testMultiArchSelectLast() {} // CHECK: error: duplicate 'cpu=' in the 'target' attribute string; diff --git a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c index f216eaf735b4a..1f8682179ea81 100644 --- a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c +++ b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c @@ -4,6 +4,8 @@ // RUN: -target-feature -relax -target-feature -zfa \ // RUN: -emit-llvm %s -o - | FileCheck %s +#include + // CHECK-LABEL: define dso_local void @testDefault // CHECK-SAME: () #0 { void testDefault() {} @@ -35,6 +37,34 @@ testAttrFullArchAndAttrCpu() {} // CHECK-SAME: () #8 { __attribute__((target("cpu=sifive-u54"))) void testAttrCpuOnly() {} +__attribute__((target("arch=+zve32x"))) +void test_builtin_w_zve32x() { +// CHECK-LABEL: test_builtin_w_zve32x +// CHECK-SAME: #9 + __riscv_vsetvl_e8m8(1); +} + +__attribute__((target("arch=+zve32x"))) +void test_rvv_i32_type_w_zve32x() { +// CHECK-LABEL: test_rvv_i32_type_w_zve32x +// CHECK-SAME: #9 + vint32m1_t v; +} + +__attribute__((target("arch=+zve32f"))) +void test_rvv_f32_type_w_zve32f() { +// CHECK-LABEL: test_rvv_f32_type_w_zve32f +// CHECK-SAME: #11 + vfloat32m1_t v; +} + +__attribute__((target("arch=+zve64d"))) +void test_rvv_f64_type_w_zve64d() { +// CHECK-LABEL: test_rvv_f64_type_w_zve64d +// CHECK-SAME: #12 + vfloat64m1_t v; +} + //. // CHECK: attributes #0 = { {{.*}}"target-features"="+64bit,+a,+m,+save-restore,+zifencei,-relax,-zbb,-zfa" } // CHECK: attributes #1 = { {{.*}}"target-cpu"="rocket-rv64" "target-features"="+64bit,+a,+d,+f,+m,+save-restore,+v,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-relax,-zbb,-zfa" "tune-cpu"="generic-rv64" } @@ -46,3 +76,6 @@ __attribute__((target("cpu=sifive-u54"))) void testAttrCpuOnly() {} // CHECK: attributes #6 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+m,+save-restore,+zbb,+zifencei,-relax,-zfa" } // CHECK: attributes #7 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+m,+save-restore,{{(-[[:alnum:]-]+)(,-[[:alnum:]-]+)*}}" } // CHECK: attributes #8 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+c,+d,+f,+m,+save-restore,+zicsr,+zifencei,{{(-[[:alnum:]-]+)(,-[[:alnum:]-]+)*}}" } +// CHECK: attributes #9 = { {{.*}}"target-features"="+64bit,+a,+m,+save-restore,+zicsr,+zifencei,+zve32x,+zvl32b,-relax,-zbb,-zfa" } +// CHECK: attributes #11 = { {{.*}}"target-features"="+64bit,+a,+f,+m,+save-restore,+zicsr,+zifencei,+zve32f,+zve32x,+zvl32b,-relax,-zbb,-zfa" } +// CHECK: attributes #12 = { {{.*}}"target-features"="+64bit,+a,+d,+f,+m,+save-restore,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl32b,+zvl64b,-relax,-zbb,-zfa" } diff --git a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c index ecf090a128aac..bad68504fab05 100644 --- a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c +++ b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c @@ -1,6 +1,6 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py -// RUN: %clang_cc1 -triple riscv32 -target-feature +zbb -verify %s -o - +// RUN: %clang_cc1 -triple riscv32 -target-feature +zbb -S -verify %s -o - unsigned int orc_b_64(unsigned int a) { - return __builtin_riscv_orc_b_64(a); // expected-error {{builtin requires: 'RV64'}} + return __builtin_riscv_orc_b_64(a); // expected-error {{'__builtin_riscv_orc_b_64' needs target feature zbb,64bit}} } diff --git a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c index d2e3e76043aef..a256bf75b031c 100644 --- a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c +++ b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c @@ -1,14 +1,10 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py -// RUN: %clang_cc1 -triple riscv64 -target-feature +zbkb -verify %s -o - +// RUN: %clang_cc1 -triple riscv64 -target-feature +zbkb -S -verify %s -o - #include -uint32_t zip(uint32_t rs1) +uint32_t zip_unzip(uint32_t rs1) { - return __builtin_riscv_zip_32(rs1); // expected-error {{builtin requires: 'RV32'}} -} - -uint32_t unzip(uint32_t rs1) -{ - return __builtin_riscv_unzip_32(rs1); // expected-error {{builtin requires: 'RV32'}} + (void)__builtin_riscv_zip_32(rs1); // expected-error {{'__builtin_riscv_zip_32' needs target feature zbkb,32bit}} + return __builtin_riscv_unzip_32(rs1); // expected-error {{'__builtin_riscv_unzip_32' needs target feature zbkb,32bit}} } diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c index 6ec9b05799769..ecb6c5f270257 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c @@ -11,7 +11,7 @@ // CHECK-RV64V-NEXT: ret i32 [[CONV]] // -// CHECK-RV64-ERR: error: builtin requires at least one of the following extensions: 'Zve32x' +// CHECK-RV64-ERR: error: '__builtin_rvv_vsetvli' needs target feature zve32x int test() { return __builtin_rvv_vsetvli(1, 0, 0); diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp b/clang/utils/TableGen/RISCVVEmitter.cpp index 8513174c88bfc..5e41ef9f9d268 100644 --- a/clang/utils/TableGen/RISCVVEmitter.cpp +++ b/clang/utils/TableGen/RISCVVEmitter.cpp @@ -334,10 +334,6 @@ void RVVEmitter::createHeader(raw_ostream &OS) { OS << "#include \n"; OS << "#include \n\n"; - OS << "#ifndef __riscv_vector\n"; - OS << "#error \"Vector intrinsics require the vector extension.\"\n"; - OS << "#endif\n\n"; - OS << "#ifdef __cplusplus\n"; OS << "extern \"C\" {\n"; OS << "#endif\n\n";