Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ Bug Fixes in This Version
cast chain. (#GH149967).
- Fixed a crash with incompatible pointer to integer conversions in designated
initializers involving string literals. (#GH154046)
- Clang now emits a frontend error when a function marked with the `flatten` attribute
calls another function that requires target features not enabled in the caller. This
prevents a fatal error in the backend.

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ 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">;
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5261,9 +5261,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<AlwaysInlineAttr>() &&
(TargetDecl->hasAttr<TargetAttr>() ||
(CurFuncDecl && CurFuncDecl->hasAttr<TargetAttr>())))
if ((TargetDecl->hasAttr<AlwaysInlineAttr>() &&
(TargetDecl->hasAttr<TargetAttr>() ||
(CurFuncDecl && CurFuncDecl->hasAttr<TargetAttr>()))) ||
(CurFuncDecl && CurFuncDecl->hasAttr<FlattenAttr>() &&
(CurFuncDecl->hasAttr<TargetAttr>() ||
TargetDecl->hasAttr<TargetAttr>())))
checkTargetFeatures(Loc, FD);
}

Expand Down
45 changes: 31 additions & 14 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2827,6 +2827,9 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
if (!FD)
return;

bool IsAlwaysInline = TargetDecl->hasAttr<AlwaysInlineAttr>();
bool IsFlatten = FD && FD->hasAttr<FlattenAttr>();

// 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.
Expand Down Expand Up @@ -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<TargetAttr>()) {
llvm::StringMap<bool> 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();
}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions clang/test/CodeGen/target-features-error-3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -verify -o /dev/null

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'}}
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/target-features-error-4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -verify -o /dev/null

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'}}
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/target-features-error-5.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -target-feature +sse4.1 -emit-llvm -verify -o /dev/null

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'}}
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/target-features-no-error-2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -verify -o /dev/null

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("sse4.1"), flatten)) bar() {
return foo(); // expected-no-diagnostics
}
Loading