Skip to content

Commit afd0e6d

Browse files
author
Chen Zheng
authored
[PowerPC] Diagnose musttail instead of crash inside backend (#93267)
musttail is not often possible to be generated on PPC targets as when calling to a function defined in another module, PPC needs to restore the TOC pointer. To restore the TOC pointer, compiler needs to emit a nop after the call to let linker generate codes to restore TOC pointer. Tail call cannot generate expected call sequence for this case. To avoid the crash inside the compiler backend, a diagnosis is added in the frontend. Fixes #63214
1 parent cc5ba73 commit afd0e6d

14 files changed

+167
-1
lines changed

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,15 @@ def warn_target_unrecognized_env : Warning<
367367
def err_target_unsupported_abi_with_fpu : Error<
368368
"'%0' ABI is not supported with FPU">;
369369

370+
def err_ppc_impossible_musttail: Error<
371+
"'musttail' attribute for this call is impossible because %select{"
372+
"long calls can not be tail called on PPC|"
373+
"indirect calls can not be tail called on PPC|"
374+
"external calls can not be tail called on PPC}0"
375+
>;
376+
def err_aix_musttail_unsupported: Error<
377+
"'musttail' attribute is not supported on AIX">;
378+
370379
// Source manager
371380
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
372381
def err_file_modified : Error<

clang/lib/Basic/Targets/PPC.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
9393
HasQuadwordAtomics = true;
9494
} else if (Feature == "+aix-shared-lib-tls-model-opt") {
9595
HasAIXShLibTLSModelOpt = true;
96+
} else if (Feature == "+longcall") {
97+
UseLongCalls = true;
9698
}
9799
// TODO: Finish this list and add an assert that we've handled them
98100
// all.
@@ -728,6 +730,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
728730
.Case("isa-v31-instructions", IsISA3_1)
729731
.Case("quadword-atomics", HasQuadwordAtomics)
730732
.Case("aix-shared-lib-tls-model-opt", HasAIXShLibTLSModelOpt)
733+
.Case("longcall", UseLongCalls)
731734
.Default(false);
732735
}
733736

clang/lib/Basic/Targets/PPC.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
8282
bool IsISA3_1 = false;
8383
bool HasQuadwordAtomics = false;
8484
bool HasAIXShLibTLSModelOpt = false;
85+
bool UseLongCalls = false;
8586

8687
protected:
8788
std::string ABI;

clang/lib/CodeGen/CGCall.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5751,8 +5751,35 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
57515751
if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
57525752
if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
57535753
Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
5754-
else if (IsMustTail)
5754+
else if (IsMustTail) {
5755+
if (getTarget().getTriple().isPPC()) {
5756+
if (getTarget().getTriple().isOSAIX())
5757+
CGM.getDiags().Report(Loc, diag::err_aix_musttail_unsupported);
5758+
else if (!getTarget().hasFeature("pcrelative-memops")) {
5759+
if (getTarget().hasFeature("longcall"))
5760+
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail) << 0;
5761+
else if (Call->isIndirectCall())
5762+
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail) << 1;
5763+
else if (isa_and_nonnull<FunctionDecl>(TargetDecl)) {
5764+
if (!cast<FunctionDecl>(TargetDecl)->isDefined())
5765+
// The undefined callee may be a forward declaration. Without
5766+
// knowning all symbols in the module, we won't know the symbol is
5767+
// defined or not. Collect all these symbols for later diagnosing.
5768+
CGM.addUndefinedGlobalForTailCall(
5769+
{cast<FunctionDecl>(TargetDecl), Loc});
5770+
else {
5771+
llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(
5772+
GlobalDecl(cast<FunctionDecl>(TargetDecl)));
5773+
if (llvm::GlobalValue::isWeakForLinker(Linkage) ||
5774+
llvm::GlobalValue::isDiscardableIfUnused(Linkage))
5775+
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail)
5776+
<< 2;
5777+
}
5778+
}
5779+
}
5780+
}
57555781
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
5782+
}
57565783
}
57575784

57585785
// Add metadata for calls to MSAllocator functions

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,21 @@ void CodeGenModule::Release() {
13941394
// that might affect the DLL storage class or the visibility, and
13951395
// before anything that might act on these.
13961396
setVisibilityFromDLLStorageClass(LangOpts, getModule());
1397+
1398+
// Check the tail call symbols are truly undefined.
1399+
if (getTriple().isPPC() && !MustTailCallUndefinedGlobals.empty()) {
1400+
for (auto &I : MustTailCallUndefinedGlobals) {
1401+
if (!I.first->isDefined())
1402+
getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
1403+
else {
1404+
StringRef MangledName = getMangledName(GlobalDecl(I.first));
1405+
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
1406+
if (!Entry || Entry->isWeakForLinker() ||
1407+
Entry->isDeclarationForLinker())
1408+
getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
1409+
}
1410+
}
1411+
}
13971412
}
13981413

13991414
void CodeGenModule::EmitOpenCLMetadata() {

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,14 @@ class CodeGenModule : public CodeGenTypeCache {
485485
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
486486
GlobalInitData;
487487

488+
// When a tail call is performed on an "undefined" symbol, on PPC without pc
489+
// relative feature, the tail call is not allowed. In "EmitCall" for such
490+
// tail calls, the "undefined" symbols may be forward declarations, their
491+
// definitions are provided in the module after the callsites. For such tail
492+
// calls, diagnose message should not be emitted.
493+
llvm::SmallSetVector<std::pair<const FunctionDecl *, SourceLocation>, 4>
494+
MustTailCallUndefinedGlobals;
495+
488496
struct GlobalInitPriorityCmp {
489497
bool operator()(const GlobalInitData &LHS,
490498
const GlobalInitData &RHS) const {
@@ -1647,6 +1655,11 @@ class CodeGenModule : public CodeGenTypeCache {
16471655
return getTriple().isSPIRVLogical();
16481656
}
16491657

1658+
void addUndefinedGlobalForTailCall(
1659+
std::pair<const FunctionDecl *, SourceLocation> Global) {
1660+
MustTailCallUndefinedGlobals.insert(Global);
1661+
}
1662+
16501663
private:
16511664
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;
16521665

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
2+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
3+
4+
inline int func2(int i);
5+
int external_call2(int i) {
6+
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
7+
[[clang::musttail]] return func2(i);
8+
}
9+
10+
inline int func2(int i) {
11+
return 0;
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
2+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
3+
4+
int func2(int i);
5+
int external_call2(int i) {
6+
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
7+
[[clang::musttail]] return func2(i);
8+
}
9+
10+
__attribute__((weak)) int func2(int i) {
11+
return 0;
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
2+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
3+
4+
int func2(int i);
5+
int external_call2(int i) {
6+
// good-no-diagnostics
7+
[[clang::musttail]] return func2(i);
8+
}
9+
int func2(int i) {
10+
return 0;
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
2+
// RUN: %clang_cc1 %s -triple powerpc-unknown-linux-gnu -o /dev/null -emit-llvm -verify
3+
4+
void name(int *params) {
5+
auto fn = (void (*)(int *))1;
6+
// expected-error@+1 {{'musttail' attribute for this call is impossible because indirect calls can not be tail called on PPC}}
7+
[[clang::musttail]] return fn(params);
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
2+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
3+
4+
inline int foo(int x) {
5+
return x;
6+
}
7+
8+
int bar(int x)
9+
{
10+
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
11+
[[clang::musttail]] return foo(1);
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
2+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
3+
4+
int foo(int x);
5+
6+
int bar(int x)
7+
{
8+
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
9+
[[clang::musttail]] return foo(x);
10+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
2+
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
3+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=linux
4+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=linux
5+
6+
__attribute__((weak)) int func2(int i) {
7+
return 0;
8+
}
9+
int external_call2(int i) {
10+
// linux-error@+2 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
11+
// aix-error@+1 {{'musttail' attribute is not supported on AIX}}
12+
[[clang::musttail]] return func2(i);
13+
}

clang/test/CodeGen/PowerPC/musttail.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
2+
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
3+
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
4+
// RUN: %clang_cc1 %s -triple powerpc-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
5+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
6+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +pcrelative-memops -o /dev/null -emit-llvm -verify=good
7+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +longcall -o /dev/null -emit-llvm -verify=longcall
8+
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +pcrelative-memops -target-feature +longcall -o /dev/null -emit-llvm -verify=good
9+
10+
int foo(int x) {
11+
return x;
12+
}
13+
14+
int bar(int x)
15+
{
16+
// good-no-diagnostics
17+
// longcall-error@+2 {{'musttail' attribute for this call is impossible because long calls can not be tail called on PPC}}
18+
// aix-error@+1 {{'musttail' attribute is not supported on AIX}}
19+
[[clang::musttail]] return foo(1);
20+
}

0 commit comments

Comments
 (0)