diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8a8db27490f06..d8f0a6e4f421d 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -287,6 +287,10 @@ def err_function_needs_feature : Error< "always_inline function %1 requires target feature '%2', but would " "be inlined into function %0 that is compiled without support for '%2'">; +def err_flatten_function_needs_feature + : Error<"flatten function %0 calls %1 which requires target feature '%2', " + "but the caller is compiled without support for '%2'">; + let CategoryName = "Codegen ABI Check" in { def err_function_always_inline_attribute_mismatch : Error< "always_inline function %1 and its caller %0 have mismatching %2 attributes">; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index b959982809911..a40e1f02e0417 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5243,9 +5243,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // since otherwise we could be making a conditional call after a check for // the proper cpu features (and it won't cause code generation issues due to // function based code generation). - if (TargetDecl->hasAttr() && - (TargetDecl->hasAttr() || - (CurFuncDecl && CurFuncDecl->hasAttr()))) + if ((TargetDecl->hasAttr() && + (TargetDecl->hasAttr() || + (CurFuncDecl && CurFuncDecl->hasAttr()))) || + (CurFuncDecl && CurFuncDecl->hasAttr() && + (CurFuncDecl->hasAttr() || + TargetDecl->hasAttr()))) checkTargetFeatures(Loc, FD); } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d077ee50856b7..2abe5cc4f9547 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2827,6 +2827,9 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc, if (!FD) return; + bool IsAlwaysInline = TargetDecl->hasAttr(); + bool IsFlatten = FD && FD->hasAttr(); + // Grab the required features for the call. For a builtin this is listed in // the td file with the default cpu, for an always_inline function this is any // listed cpu and any listed features. @@ -2869,25 +2872,39 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc, if (F.getValue()) ReqFeatures.push_back(F.getKey()); } - if (!llvm::all_of(ReqFeatures, [&](StringRef Feature) { - if (!CallerFeatureMap.lookup(Feature)) { - MissingFeature = Feature.str(); - return false; - } - return true; - }) && !IsHipStdPar) - CGM.getDiags().Report(Loc, diag::err_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; + if (!llvm::all_of(ReqFeatures, + [&](StringRef Feature) { + if (!CallerFeatureMap.lookup(Feature)) { + MissingFeature = Feature.str(); + return false; + } + return true; + }) && + !IsHipStdPar) { + if (IsAlwaysInline) + CGM.getDiags().Report(Loc, diag::err_function_needs_feature) + << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; + else if (IsFlatten) + CGM.getDiags().Report(Loc, diag::err_flatten_function_needs_feature) + << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; + } + } else if (!FD->isMultiVersion() && FD->hasAttr()) { llvm::StringMap CalleeFeatureMap; CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); for (const auto &F : CalleeFeatureMap) { - if (F.getValue() && (!CallerFeatureMap.lookup(F.getKey()) || - !CallerFeatureMap.find(F.getKey())->getValue()) && - !IsHipStdPar) - CGM.getDiags().Report(Loc, diag::err_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey(); + if (F.getValue() && + (!CallerFeatureMap.lookup(F.getKey()) || + !CallerFeatureMap.find(F.getKey())->getValue()) && + !IsHipStdPar) { + if (IsAlwaysInline) + CGM.getDiags().Report(Loc, diag::err_function_needs_feature) + << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey(); + else if (IsFlatten) + CGM.getDiags().Report(Loc, diag::err_flatten_function_needs_feature) + << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey(); + } } } } diff --git a/clang/test/CodeGen/target-features-error-3.c b/clang/test/CodeGen/target-features-error-3.c new file mode 100644 index 0000000000000..8ecc7369b4723 --- /dev/null +++ b/clang/test/CodeGen/target-features-error-3.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - + +typedef double __v2df __attribute__((__vector_size__(16))); + +__v2df __attribute__((target("sse4.1"))) foo() { + __v2df v = {0.0, 0.0}; + return __builtin_ia32_roundpd(v, 2); +} + +__v2df __attribute__((flatten)) bar() { + return foo(); // expected-error {{flatten function 'bar' calls 'foo' which requires target feature 'sse4.1', but the caller is compiled without support for 'sse4.1'}} +} diff --git a/clang/test/CodeGen/target-features-error-4.c b/clang/test/CodeGen/target-features-error-4.c new file mode 100644 index 0000000000000..a6c2cbf37f92b --- /dev/null +++ b/clang/test/CodeGen/target-features-error-4.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - + +typedef double __v2df __attribute__((__vector_size__(16))); + +__v2df __attribute__((target("sse4.1"))) foo() { + __v2df v = {0.0, 0.0}; + return __builtin_ia32_roundpd(v, 2); +} + +__v2df __attribute__((target("no-sse4.1"), flatten)) bar() { + return foo(); // expected-error {{flatten function 'bar' calls 'foo' which requires target feature 'sse4.1', but the caller is compiled without support for 'sse4.1'}} +} diff --git a/clang/test/CodeGen/target-features-error-5.c b/clang/test/CodeGen/target-features-error-5.c new file mode 100644 index 0000000000000..625a2ba2b7d67 --- /dev/null +++ b/clang/test/CodeGen/target-features-error-5.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -target-feature +sse4.1 -S -verify -o - + +typedef double __v2df __attribute__((__vector_size__(16))); + +__v2df foo() { + __v2df v = {0.0, 0.0}; + return __builtin_ia32_roundpd(v, 2); +} + +__v2df __attribute__((target("no-sse4.1"), flatten)) bar() { + return foo(); // expected-error {{flatten function 'bar' calls 'foo' which requires target feature 'sse4.1', but the caller is compiled without support for 'sse4.1'}} +}