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 all commits
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 @@ -4533,8 +4533,7 @@ class Sema final : public SemaBase {
bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);

/// Check Target Version attrs
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
74 changes: 23 additions & 51 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11201,6 +11201,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 @@ -11234,18 +11238,16 @@ 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,
FunctionDecl *NewFD,
bool &Redeclaration,
NamedDecl *&OldDecl,
LookupResult &Previous) {
static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
FunctionDecl *NewFD,
bool &Redeclaration,
NamedDecl *&OldDecl,
LookupResult &Previous) {
assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion");

// The definitions should be allowed in any order. If we have discovered
Expand All @@ -11256,13 +11258,16 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
const auto *NewTA = NewFD->getAttr<TargetAttr>();
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *OldTA = OldFD->getAttr<TargetAttr>();
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.
if (NewTVA && NewTVA->isDefaultVersion())
return false;

// Otherwise, this decl causes MultiVersioning.
Expand All @@ -11279,8 +11284,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 @@ -11312,22 +11316,6 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
}
}

if (NewTVA) {
llvm::SmallVector<StringRef, 8> Feats;
OldTVA->getFeatures(Feats);
llvm::sort(Feats);
llvm::SmallVector<StringRef, 8> NewFeats;
NewTVA->getFeatures(NewFeats);
llvm::sort(NewFeats);

if (Feats == NewFeats) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
NewFD->setInvalidDecl();
return true;
}
}

for (const auto *FD : OldFD->redecls()) {
const auto *CurTA = FD->getAttr<TargetAttr>();
const auto *CurTVA = FD->getAttr<TargetVersionAttr>();
Expand Down Expand Up @@ -11683,24 +11671,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 All @@ -11717,8 +11689,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
switch (MVKind) {
case MultiVersionKind::Target:
case MultiVersionKind::TargetVersion:
return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration,
OldDecl, Previous);
return CheckDeclarationCausesMultiVersioning(
S, OldFD, NewFD, Redeclaration, OldDecl, Previous);
case MultiVersionKind::TargetClones:
if (OldFD->isUsed(false)) {
NewFD->setInvalidDecl();
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 @@ -3010,12 +3010,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
}

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 @@ -3035,16 +3033,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
Loading
Loading