Skip to content

Commit b338e4d

Browse files
committed
[FMV][AArch64] Do not emit ifunc resolver on use.
It was raised in llvm#81494 that we are not generating correct code when there is no TU-local caller. The suggestion was to emit a resolver: * Whenever there is a use in the TU. * When the TU has a definition of the default version. See the comment for more details: llvm#81494 (comment) This got addressed with llvm#84405. Generating a resolver on use means that we may end up with multiple resolvers across different translation units. Those resolvers may not be the same because each translation unit may contain different version declarations (user's fault). Therefore the order of linking the final image determines which of these weak symbols gets selected, resulting in non consisted behavior. I am proposing to stop emitting a resolver on use and only do so in the translation unit which contains the default defition. This way we guarantee the existance of a single resolver. Now, when a versioned function is used we want to emit a declaration of the function symbol omitting the multiversion mangling. I have added a requirement to ACLE mandating that all the function versions are declared in the translation unit which contains the default definition: ARM-software/acle#328
1 parent d1c911f commit b338e4d

File tree

7 files changed

+764
-824
lines changed

7 files changed

+764
-824
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,8 +3772,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
37723772
// Forward declarations are emitted lazily on first use.
37733773
if (!FD->doesThisDeclarationHaveABody()) {
37743774
if (!FD->doesDeclarationForceExternallyVisibleDefinition() &&
3775-
(!FD->isMultiVersion() ||
3776-
!FD->getASTContext().getTargetInfo().getTriple().isAArch64()))
3775+
(!FD->isMultiVersion() || !getTarget().getTriple().isAArch64()))
37773776
return;
37783777

37793778
StringRef MangledName = getMangledName(GD);
@@ -4167,23 +4166,6 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
41674166
return llvm::GlobalValue::WeakODRLinkage;
41684167
}
41694168

4170-
static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) {
4171-
auto *DeclCtx = const_cast<DeclContext *>(FD->getDeclContext());
4172-
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
4173-
StorageClass SC = FD->getStorageClass();
4174-
DeclarationName Name = FD->getNameInfo().getName();
4175-
4176-
FunctionDecl *NewDecl =
4177-
FunctionDecl::Create(FD->getASTContext(), DeclCtx, FD->getBeginLoc(),
4178-
FD->getEndLoc(), Name, TInfo->getType(), TInfo, SC);
4179-
4180-
NewDecl->setIsMultiVersion();
4181-
NewDecl->addAttr(TargetVersionAttr::CreateImplicit(
4182-
NewDecl->getASTContext(), "default", NewDecl->getSourceRange()));
4183-
4184-
return NewDecl;
4185-
}
4186-
41874169
void CodeGenModule::emitMultiVersionFunctions() {
41884170
std::vector<GlobalDecl> MVFuncsToEmit;
41894171
MultiVersionFuncs.swap(MVFuncsToEmit);
@@ -4210,9 +4192,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
42104192
return cast<llvm::Function>(Func);
42114193
};
42124194

4213-
bool HasDefaultDecl = !FD->isTargetVersionMultiVersion();
4214-
bool ShouldEmitResolver =
4215-
!getContext().getTargetInfo().getTriple().isAArch64();
4195+
bool ShouldEmitResolver = !getTarget().getTriple().isAArch64();
42164196
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
42174197

42184198
getContext().forEachMultiversionedFunctionVersion(
@@ -4224,10 +4204,8 @@ void CodeGenModule::emitMultiVersionFunctions() {
42244204
llvm::Function *Func = createFunction(CurFD);
42254205
Options.emplace_back(Func, TA->getArchitecture(), Feats);
42264206
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
4227-
bool HasDefaultDef = TVA->isDefaultVersion() &&
4228-
CurFD->doesThisDeclarationHaveABody();
4229-
HasDefaultDecl |= TVA->isDefaultVersion();
4230-
ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef);
4207+
ShouldEmitResolver |= (TVA->isDefaultVersion() &&
4208+
CurFD->doesThisDeclarationHaveABody());
42314209
TVA->getFeatures(Feats);
42324210
llvm::Function *Func = createFunction(CurFD);
42334211
Options.emplace_back(Func, /*Architecture*/ "", Feats);
@@ -4258,13 +4236,6 @@ void CodeGenModule::emitMultiVersionFunctions() {
42584236
if (!ShouldEmitResolver)
42594237
continue;
42604238

4261-
if (!HasDefaultDecl) {
4262-
FunctionDecl *NewFD = createDefaultTargetVersionFrom(FD);
4263-
llvm::Function *Func = createFunction(NewFD);
4264-
llvm::SmallVector<StringRef, 1> Feats;
4265-
Options.emplace_back(Func, /*Architecture*/ "", Feats);
4266-
}
4267-
42684239
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
42694240
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
42704241
ResolverConstant = IFunc->getResolver();
@@ -4315,6 +4286,14 @@ void CodeGenModule::emitMultiVersionFunctions() {
43154286
emitMultiVersionFunctions();
43164287
}
43174288

4289+
static void replaceDeclarationWith(llvm::GlobalValue *Old,
4290+
llvm::Constant *New) {
4291+
assert(cast<llvm::Function>(Old)->isDeclaration() && "Not a declaration");
4292+
New->takeName(Old);
4293+
Old->replaceAllUsesWith(New);
4294+
Old->eraseFromParent();
4295+
}
4296+
43184297
void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
43194298
const auto *FD = cast<FunctionDecl>(GD.getDecl());
43204299
assert(FD && "Not a FunctionDecl?");
@@ -4419,12 +4398,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
44194398
// Fix up function declarations that were created for cpu_specific before
44204399
// cpu_dispatch was known
44214400
if (!isa<llvm::GlobalIFunc>(IFunc)) {
4422-
assert(cast<llvm::Function>(IFunc)->isDeclaration());
44234401
auto *GI = llvm::GlobalIFunc::create(DeclTy, 0, Linkage, "", ResolverFunc,
44244402
&getModule());
4425-
GI->takeName(IFunc);
4426-
IFunc->replaceAllUsesWith(GI);
4427-
IFunc->eraseFromParent();
4403+
replaceDeclarationWith(IFunc, GI);
44284404
IFunc = GI;
44294405
}
44304406

@@ -4454,7 +4430,8 @@ void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) {
44544430
}
44554431

44564432
/// If a dispatcher for the specified mangled name is not in the module, create
4457-
/// and return an llvm Function with the specified type.
4433+
/// and return it. The dispatcher is either an llvm Function with the specified
4434+
/// type, or a global ifunc.
44584435
llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
44594436
const auto *FD = cast<FunctionDecl>(GD.getDecl());
44604437
assert(FD && "Not a FunctionDecl?");
@@ -4482,8 +4459,15 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
44824459
ResolverName += ".resolver";
44834460
}
44844461

4485-
// If the resolver has already been created, just return it.
4486-
if (llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName))
4462+
// If the resolver has already been created, just return it. This lookup may
4463+
// yield a function declaration instead of a resolver on AArch64. That is
4464+
// because we didn't know whether a resolver will be generated when we first
4465+
// encountered a use of the symbol named after this resolver. Therefore,
4466+
// targets which support ifuncs should not return here unless we actually
4467+
// found an ifunc.
4468+
llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName);
4469+
if (ResolverGV &&
4470+
(isa<llvm::GlobalIFunc>(ResolverGV) || !getTarget().supportsIFunc()))
44874471
return ResolverGV;
44884472

44894473
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
@@ -4509,7 +4493,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
45094493
"", Resolver, &getModule());
45104494
GIF->setName(ResolverName);
45114495
SetCommonAttributes(FD, GIF);
4512-
4496+
if (ResolverGV)
4497+
replaceDeclarationWith(ResolverGV, GIF);
45134498
return GIF;
45144499
}
45154500

@@ -4518,6 +4503,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
45184503
assert(isa<llvm::GlobalValue>(Resolver) &&
45194504
"Resolver should be created for the first time");
45204505
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
4506+
if (ResolverGV)
4507+
replaceDeclarationWith(ResolverGV, Resolver);
45214508
return Resolver;
45224509
}
45234510

@@ -4547,6 +4534,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
45474534
ForDefinition_t IsForDefinition) {
45484535
const Decl *D = GD.getDecl();
45494536

4537+
std::string NameWithoutMultiVersionMangling;
45504538
// Any attempts to use a MultiVersion function should result in retrieving
45514539
// the iFunc instead. Name Mangling will handle the rest of the changes.
45524540
if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D)) {
@@ -4568,14 +4556,24 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
45684556

45694557
if (FD->isMultiVersion()) {
45704558
UpdateMultiVersionNames(GD, FD, MangledName);
4571-
if (FD->getASTContext().getTargetInfo().getTriple().isAArch64() &&
4572-
!FD->isUsed())
4573-
AddDeferredMultiVersionResolverToEmit(GD);
4574-
else if (!IsForDefinition)
4575-
return GetOrCreateMultiVersionResolver(GD);
4559+
if (!IsForDefinition) {
4560+
// On AArch64 we do not immediatelly emit an ifunc resolver when a
4561+
// function is used. Instead we defer the emission until we see a
4562+
// default definition. In the meantime we just reference the symbol
4563+
// without FMV mangling (it may or may not be replaced later).
4564+
if (getTarget().getTriple().isAArch64()) {
4565+
AddDeferredMultiVersionResolverToEmit(GD);
4566+
NameWithoutMultiVersionMangling = getMangledNameImpl(
4567+
*this, GD, FD, /*OmitMultiVersionMangling=*/true);
4568+
} else
4569+
return GetOrCreateMultiVersionResolver(GD);
4570+
}
45764571
}
45774572
}
45784573

4574+
if (!NameWithoutMultiVersionMangling.empty())
4575+
MangledName = NameWithoutMultiVersionMangling;
4576+
45794577
// Lookup the entry, lazily creating it if necessary.
45804578
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
45814579
if (Entry) {

clang/test/CodeGen/aarch64-mixed-target-attributes.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,9 @@ __attribute__((target_version("jscvt"))) int default_def_with_version_decls(void
261261
// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" }
262262
// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+rdm,-v9.5a" }
263263
// CHECK: attributes #[[ATTR5:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dotprod,+fp-armv8,+neon,-v9.5a" }
264-
// CHECK: attributes #[[ATTR6:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+jsconv,+neon,-v9.5a" }
265-
// CHECK: attributes #[[ATTR7:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.5a" }
266-
// CHECK: attributes #[[ATTR8:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" }
264+
// CHECK: attributes #[[ATTR6:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.5a" }
265+
// CHECK: attributes #[[ATTR7:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" }
266+
// CHECK: attributes #[[ATTR8:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+jsconv,+neon,-v9.5a" }
267267
//.
268268
// CHECK-NOFMV: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" }
269269
//.

0 commit comments

Comments
 (0)