Skip to content

[clang][FMV] Do not omit explicit default target_version attribute. #96628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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: 1 addition & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3786,8 +3786,7 @@ class Sema final : public SemaBase {
StringRef Name);

bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);
bool checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
StringRef &Str, bool &isDefault);
bool checkTargetVersionAttr(SourceLocation Loc, Decl *D, StringRef Str);
bool checkTargetClonesAttrString(
SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal,
Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault,
Expand Down
45 changes: 18 additions & 27 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11465,6 +11465,10 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
// otherwise it is treated as a normal function.
if (TA && !TA->isDefaultVersion())
return false;
// The target_version attribute only causes Multiversioning if this
// declaration is NOT the default version.
if (TVA && TVA->isDefaultVersion())
return false;

if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
FD->setInvalidDecl();
Expand Down Expand Up @@ -11498,11 +11502,9 @@ static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {

if (MVKindTo == MultiVersionKind::None &&
(MVKindFrom == MultiVersionKind::TargetVersion ||
MVKindFrom == MultiVersionKind::TargetClones)) {
To->setIsMultiVersion();
MVKindFrom == MultiVersionKind::TargetClones))
To->addAttr(TargetVersionAttr::CreateImplicit(
To->getASTContext(), "default", To->getSourceRange()));
}
}

static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
Expand All @@ -11523,10 +11525,16 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
// If the old decl is NOT MultiVersioned yet, and we don't cause that
// to change, this is a simple redeclaration.
if ((NewTA && !NewTA->isDefaultVersion() &&
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) ||
(NewTVA && !NewTVA->isDefaultVersion() &&
(!OldTVA || OldTVA->getName() == NewTVA->getName())))
if (NewTA && !NewTA->isDefaultVersion() &&
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
return false;

// The target_version attribute only causes Multiversioning if this
// declaration is NOT the default version. Moreover, the old declaration
// must be the default version (either explicitly via the attribute,
// or implicitly without it).
if (NewTVA &&
(NewTVA->isDefaultVersion() || (OldTVA && !OldTVA->isDefaultVersion())))
return false;

// Otherwise, this decl causes MultiVersioning.
Expand All @@ -11543,8 +11551,7 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
}

// If this is 'default', permit the forward declaration.
if ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
(NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) {
if (NewTA && NewTA->isDefaultVersion() && !OldTA) {
Redeclaration = true;
OldDecl = OldFD;
OldFD->setIsMultiVersion();
Expand Down Expand Up @@ -11947,24 +11954,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,

FunctionDecl *OldFD = OldDecl->getAsFunction();

if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) {
if (NewTVA || !OldFD->getAttr<TargetVersionAttr>())
return false;
if (!NewFD->getType()->getAs<FunctionProtoType>()) {
// Multiversion declaration doesn't have prototype.
S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto);
NewFD->setInvalidDecl();
} else {
// No "target_version" attribute is equivalent to "default" attribute.
NewFD->addAttr(TargetVersionAttr::CreateImplicit(
S.Context, "default", NewFD->getSourceRange()));
NewFD->setIsMultiVersion();
OldFD->setIsMultiVersion();
OldDecl = OldFD;
Redeclaration = true;
}
return true;
}
if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None)
return false;

// Multiversioned redeclarations aren't allowed to omit the attribute, except
// for target_clones and target_version.
Expand Down
16 changes: 5 additions & 11 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3029,12 +3029,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {

// Check Target Version attrs
bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
StringRef &AttrStr, bool &isDefault) {
StringRef AttrStr) {
enum FirstParam { Unsupported };
enum SecondParam { None };
enum ThirdParam { Target, TargetClones, TargetVersion };
if (AttrStr.trim() == "default")
isDefault = true;
llvm::SmallVector<StringRef, 8> Features;
AttrStr.split(Features, "+");
for (auto &CurFeature : Features) {
Expand All @@ -3054,16 +3052,12 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
bool isDefault = false;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
S.checkTargetVersionAttr(LiteralLoc, D, Str, isDefault))
S.checkTargetVersionAttr(LiteralLoc, D, Str))
return;
// Do not create default only target_version attribute
if (!isDefault) {
TargetVersionAttr *NewAttr =
::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}
TargetVersionAttr *NewAttr =
::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}

static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
88 changes: 44 additions & 44 deletions clang/test/CodeGen/attr-target-version.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_default
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: ret i32 111
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_c._Mssbs
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
Expand Down Expand Up @@ -637,22 +630,18 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@recur
// CHECK-LABEL: define {{[^@]+}}@fmv_default
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @reca()
// CHECK-NEXT: ret void
// CHECK-NEXT: ret i32 111
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@main
// CHECK-LABEL: define {{[^@]+}}@recur
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NEXT: call void @recur()
// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NEXT: ret i32 [[CALL]]
// CHECK-NEXT: call void @reca()
// CHECK-NEXT: ret void
//
//
// CHECK: Function Attrs: noinline nounwind optnone
Expand Down Expand Up @@ -818,6 +807,17 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@main
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NEXT: call void @recur()
// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NEXT: ret i32 [[CALL]]
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_inline._Mf64mmMpmullMsha1
// CHECK-SAME: () #[[ATTR22:[0-9]+]] {
// CHECK-NEXT: entry:
Expand Down Expand Up @@ -1020,20 +1020,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_default
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 111
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_c
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret void
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@goo
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
Expand All @@ -1053,22 +1039,25 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@recur
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_c
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: call void @reca()
// CHECK-NOFMV-NEXT: ret void
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@main
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_default
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NOFMV-NEXT: call void @recur()
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
// CHECK-NOFMV-NEXT: ret i32 111
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@recur
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: call void @reca()
// CHECK-NOFMV-NEXT: ret void
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
Expand All @@ -1089,31 +1078,42 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_default_def
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_default_def
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 1
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_default_def
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_forward_default_def
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 1
// CHECK-NOFMV-NEXT: ret i32 0
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_forward_default_def
// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 0
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls
// CHECK-NOFMV-LABEL: define {{[^@]+}}@main
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 0
// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NOFMV-NEXT: call void @recur()
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_default_def
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 1
//
//.
// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+flagm,+fp-armv8,+fp16fml,+fullfp16,+neon,+rand,-v9.5a" }
Expand Down
60 changes: 47 additions & 13 deletions clang/test/CodeGenCXX/fmv-namespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,26 @@ int __attribute((target_version("sve"))) foo() { return 2; }

int baz() { return OtherName::foo(); }

namespace Foo {
int bar();
__attribute((target_version("default"))) int bar() { return 0; }
__attribute((target_version("mops"))) int bar() { return 1; }
}

//.
// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
// CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver
// CHECK: @_ZN9OtherName3fooEv = weak_odr ifunc i32 (), ptr @_ZN9OtherName3fooEv.resolver
// CHECK: @_ZN3Foo3barEv = weak_odr ifunc i32 (), ptr @_ZN3Foo3barEv.resolver
//.
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve(
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 1
//
//
// CHECK-LABEL: define dso_local noundef i32 @_Z3barv(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN4Name3fooEv()
// CHECK-NEXT: ret i32 [[CALL]]
Expand All @@ -56,13 +57,13 @@ int baz() { return OtherName::foo(); }
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 2
//
//
// CHECK-LABEL: define dso_local noundef i32 @_Z3bazv(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN9OtherName3fooEv()
// CHECK-NEXT: ret i32 [[CALL]]
Expand All @@ -81,10 +82,43 @@ int baz() { return OtherName::foo(); }
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv.default
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv.default(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv._Mmops(
// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 1
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define weak_odr ptr @_ZN3Foo3barEv.resolver() comdat {
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 576460752303423488
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 576460752303423488
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
// CHECK: [[RESOLVER_RETURN]]:
// CHECK-NEXT: ret ptr @_ZN3Foo3barEv._Mmops
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN3Foo3barEv.default
//
//.
// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
// CHECK: attributes #[[ATTR2:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR2]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mops" }
// CHECK: attributes #[[ATTR3:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
//.
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
Expand Down
Loading
Loading