Skip to content

Commit 8930ba9

Browse files
authored
[clang][FMV] Allow declaration of function versions in namespaces. (#93044)
Fixes the following bug: namespace Name { int __attribute((target_version("default"))) foo() { return 0; } } namespace Name { int __attribute((target_version("sve"))) foo() { return 1; } } int bar() { return Name::foo(); } error: redefinition of 'foo' int __attribute((target_version("sve"))) foo() { return 1; } note: previous definition is here int __attribute((target_version("default"))) foo() { return 0; } While fixing this I also found that in the absence of default version declaration, the one we implicitly create has incorrect mangling if we are in a namespace: namespace OtherName { int __attribute((target_version("sve"))) foo() { return 2; } } int baz() { return OtherName::foo(); } In this example instead of creating a declaration for the symbol @_ZN9OtherName3fooEv.default we are creating one for the symbol @_Z3foov.default (the namespace mangling prefix is omitted). This has now been fixed.
1 parent bf4d99e commit 8930ba9

File tree

4 files changed

+108
-3
lines changed

4 files changed

+108
-3
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4150,7 +4150,7 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
41504150
}
41514151

41524152
static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) {
4153-
DeclContext *DeclCtx = FD->getASTContext().getTranslationUnitDecl();
4153+
auto *DeclCtx = const_cast<DeclContext *>(FD->getDeclContext());
41544154
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
41554155
StorageClass SC = FD->getStorageClass();
41564156
DeclarationName Name = FD->getNameInfo().getName();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11868,8 +11868,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
1186811868
return false;
1186911869

1187011870
if (!OldDecl || !OldDecl->getAsFunction() ||
11871-
OldDecl->getDeclContext()->getRedeclContext() !=
11872-
NewFD->getDeclContext()->getRedeclContext()) {
11871+
!OldDecl->getDeclContext()->getRedeclContext()->Equals(
11872+
NewFD->getDeclContext()->getRedeclContext())) {
1187311873
// If there's no previous declaration, AND this isn't attempting to cause
1187411874
// multiversioning, this isn't an error condition.
1187511875
if (MVKind == MultiVersionKind::None)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5
2+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck %s
3+
4+
namespace Name {
5+
int __attribute((target_version("default"))) foo() { return 0; }
6+
}
7+
8+
namespace Name {
9+
int __attribute((target_version("sve"))) foo() { return 1; }
10+
}
11+
12+
int bar() { return Name::foo(); }
13+
14+
namespace OtherName {
15+
int __attribute((target_version("sve"))) foo() { return 2; }
16+
}
17+
18+
int baz() { return OtherName::foo(); }
19+
20+
//.
21+
// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
22+
// CHECK: @_ZN4Name3fooEv.ifunc = weak_odr alias i32 (), ptr @_ZN4Name3fooEv
23+
// CHECK: @_ZN9OtherName3fooEv.ifunc = weak_odr alias i32 (), ptr @_ZN9OtherName3fooEv
24+
// CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver
25+
// CHECK: @_ZN9OtherName3fooEv = weak_odr ifunc i32 (), ptr @_ZN9OtherName3fooEv.resolver
26+
//.
27+
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
28+
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
29+
// CHECK-NEXT: [[ENTRY:.*:]]
30+
// CHECK-NEXT: ret i32 0
31+
//
32+
//
33+
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve(
34+
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
35+
// CHECK-NEXT: [[ENTRY:.*:]]
36+
// CHECK-NEXT: ret i32 1
37+
//
38+
//
39+
// CHECK-LABEL: define dso_local noundef i32 @_Z3barv(
40+
// CHECK-SAME: ) #[[ATTR0]] {
41+
// CHECK-NEXT: [[ENTRY:.*:]]
42+
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN4Name3fooEv()
43+
// CHECK-NEXT: ret i32 [[CALL]]
44+
//
45+
//
46+
// CHECK-LABEL: define weak_odr ptr @_ZN4Name3fooEv.resolver() comdat {
47+
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
48+
// CHECK-NEXT: call void @__init_cpu_features_resolver()
49+
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
50+
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824
51+
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824
52+
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
53+
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
54+
// CHECK: [[RESOLVER_RETURN]]:
55+
// CHECK-NEXT: ret ptr @_ZN4Name3fooEv._Msve
56+
// CHECK: [[RESOLVER_ELSE]]:
57+
// CHECK-NEXT: ret ptr @_ZN4Name3fooEv.default
58+
//
59+
//
60+
// CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve(
61+
// CHECK-SAME: ) #[[ATTR1]] {
62+
// CHECK-NEXT: [[ENTRY:.*:]]
63+
// CHECK-NEXT: ret i32 2
64+
//
65+
//
66+
// CHECK-LABEL: define dso_local noundef i32 @_Z3bazv(
67+
// CHECK-SAME: ) #[[ATTR0]] {
68+
// CHECK-NEXT: [[ENTRY:.*:]]
69+
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN9OtherName3fooEv()
70+
// CHECK-NEXT: ret i32 [[CALL]]
71+
//
72+
//
73+
// CHECK-LABEL: define weak_odr ptr @_ZN9OtherName3fooEv.resolver() comdat {
74+
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
75+
// CHECK-NEXT: call void @__init_cpu_features_resolver()
76+
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
77+
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824
78+
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824
79+
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
80+
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
81+
// CHECK: [[RESOLVER_RETURN]]:
82+
// CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv._Msve
83+
// CHECK: [[RESOLVER_ELSE]]:
84+
// CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv.default
85+
//
86+
//.
87+
// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
88+
// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
89+
// CHECK: attributes #[[ATTR2:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
90+
//.
91+
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
92+
// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
93+
//.

clang/test/Sema/fmv-namespace.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify %s
2+
// expected-no-diagnostics
3+
4+
namespace Name {
5+
int __attribute((target_version("default"))) foo() { return 0; }
6+
}
7+
8+
namespace Name {
9+
int __attribute((target_version("sve"))) foo() { return 1; }
10+
}
11+
12+
int bar() { return Name::foo(); }

0 commit comments

Comments
 (0)