Skip to content

[PowerPC] Diagnose musttail instead of crash inside backend #93267

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
merged 4 commits into from
Jul 8, 2024
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
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ def warn_target_unrecognized_env : Warning<
def err_target_unsupported_abi_with_fpu : Error<
"'%0' ABI is not supported with FPU">;

def err_ppc_impossible_musttail: Error<
"'musttail' attribute for this call is impossible because %select{"
"long calls can not be tail called on PPC|"
"indirect calls can not be tail called on PPC|"
"external calls can not be tail called on PPC}0"
>;
def err_aix_musttail_unsupported: Error<
"'musttail' attribute is not supported on AIX">;

// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
def err_file_modified : Error<
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasQuadwordAtomics = true;
} else if (Feature == "+aix-shared-lib-tls-model-opt") {
HasAIXShLibTLSModelOpt = true;
} else if (Feature == "+longcall") {
UseLongCalls = true;
}
// TODO: Finish this list and add an assert that we've handled them
// all.
Expand Down Expand Up @@ -728,6 +730,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
.Case("isa-v31-instructions", IsISA3_1)
.Case("quadword-atomics", HasQuadwordAtomics)
.Case("aix-shared-lib-tls-model-opt", HasAIXShLibTLSModelOpt)
.Case("longcall", UseLongCalls)
.Default(false);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
bool IsISA3_1 = false;
bool HasQuadwordAtomics = false;
bool HasAIXShLibTLSModelOpt = false;
bool UseLongCalls = false;

protected:
std::string ABI;
Expand Down
29 changes: 28 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5751,8 +5751,35 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
else if (IsMustTail)
else if (IsMustTail) {
if (getTarget().getTriple().isPPC()) {
if (getTarget().getTriple().isOSAIX())
CGM.getDiags().Report(Loc, diag::err_aix_musttail_unsupported);
else if (!getTarget().hasFeature("pcrelative-memops")) {
if (getTarget().hasFeature("longcall"))
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail) << 0;
else if (Call->isIndirectCall())
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail) << 1;
else if (isa_and_nonnull<FunctionDecl>(TargetDecl)) {
if (!cast<FunctionDecl>(TargetDecl)->isDefined())
// The undefined callee may be a forward declaration. Without
// knowning all symbols in the module, we won't know the symbol is
// defined or not. Collect all these symbols for later diagnosing.
CGM.addUndefinedGlobalForTailCall(
{cast<FunctionDecl>(TargetDecl), Loc});
else {
llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(
GlobalDecl(cast<FunctionDecl>(TargetDecl)));
if (llvm::GlobalValue::isWeakForLinker(Linkage) ||
llvm::GlobalValue::isDiscardableIfUnused(Linkage))
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail)
<< 2;
}
}
}
}
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
}
}

// Add metadata for calls to MSAllocator functions
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,21 @@ void CodeGenModule::Release() {
// that might affect the DLL storage class or the visibility, and
// before anything that might act on these.
setVisibilityFromDLLStorageClass(LangOpts, getModule());

// Check the tail call symbols are truly undefined.
if (getTriple().isPPC() && !MustTailCallUndefinedGlobals.empty()) {
for (auto &I : MustTailCallUndefinedGlobals) {
if (!I.first->isDefined())
getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
else {
StringRef MangledName = getMangledName(GlobalDecl(I.first));
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (!Entry || Entry->isWeakForLinker() ||
Entry->isDeclarationForLinker())
getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
}
}
}
}

void CodeGenModule::EmitOpenCLMetadata() {
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,14 @@ class CodeGenModule : public CodeGenTypeCache {
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
GlobalInitData;

// When a tail call is performed on an "undefined" symbol, on PPC without pc
// relative feature, the tail call is not allowed. In "EmitCall" for such
// tail calls, the "undefined" symbols may be forward declarations, their
// definitions are provided in the module after the callsites. For such tail
// calls, diagnose message should not be emitted.
llvm::SmallSetVector<std::pair<const FunctionDecl *, SourceLocation>, 4>
MustTailCallUndefinedGlobals;

struct GlobalInitPriorityCmp {
bool operator()(const GlobalInitData &LHS,
const GlobalInitData &RHS) const {
Expand Down Expand Up @@ -1647,6 +1655,11 @@ class CodeGenModule : public CodeGenTypeCache {
return getTriple().isSPIRVLogical();
}

void addUndefinedGlobalForTailCall(
std::pair<const FunctionDecl *, SourceLocation> Global) {
MustTailCallUndefinedGlobals.insert(Global);
}

private:
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;

Expand Down
12 changes: 12 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-forward-declaration-inline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify

inline int func2(int i);
int external_call2(int i) {
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return func2(i);
}

inline int func2(int i) {
return 0;
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-forward-declaration-weak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify

int func2(int i);
int external_call2(int i) {
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return func2(i);
}

__attribute__((weak)) int func2(int i) {
return 0;
}
11 changes: 11 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-forward-declaration.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good

int func2(int i);
int external_call2(int i) {
// good-no-diagnostics
[[clang::musttail]] return func2(i);
}
int func2(int i) {
return 0;
}
8 changes: 8 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-indirect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc-unknown-linux-gnu -o /dev/null -emit-llvm -verify

void name(int *params) {
auto fn = (void (*)(int *))1;
// expected-error@+1 {{'musttail' attribute for this call is impossible because indirect calls can not be tail called on PPC}}
[[clang::musttail]] return fn(params);
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-inline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify

inline int foo(int x) {
return x;
}

int bar(int x)
{
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return foo(1);
}
10 changes: 10 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-undefined.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify

int foo(int x);

int bar(int x)
{
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return foo(x);
}
13 changes: 13 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-weak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=linux
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=linux

__attribute__((weak)) int func2(int i) {
return 0;
}
int external_call2(int i) {
// linux-error@+2 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
// aix-error@+1 {{'musttail' attribute is not supported on AIX}}
[[clang::musttail]] return func2(i);
}
20 changes: 20 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +pcrelative-memops -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +longcall -o /dev/null -emit-llvm -verify=longcall
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +pcrelative-memops -target-feature +longcall -o /dev/null -emit-llvm -verify=good

int foo(int x) {
return x;
}

int bar(int x)
{
// good-no-diagnostics
// longcall-error@+2 {{'musttail' attribute for this call is impossible because long calls can not be tail called on PPC}}
// aix-error@+1 {{'musttail' attribute is not supported on AIX}}
[[clang::musttail]] return foo(1);
}
Loading