[clang] afd0e6d - [PowerPC] Diagnose musttail instead of crash inside backend (#93267)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 7 18:30:05 PDT 2024
Author: Chen Zheng
Date: 2024-07-08T09:30:01+08:00
New Revision: afd0e6d06ba05cf3cd8b0bb91b6506242de78a4d
URL: https://github.com/llvm/llvm-project/commit/afd0e6d06ba05cf3cd8b0bb91b6506242de78a4d
DIFF: https://github.com/llvm/llvm-project/commit/afd0e6d06ba05cf3cd8b0bb91b6506242de78a4d.diff
LOG: [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
Added:
clang/test/CodeGen/PowerPC/musttail-forward-declaration-inline.c
clang/test/CodeGen/PowerPC/musttail-forward-declaration-weak.c
clang/test/CodeGen/PowerPC/musttail-forward-declaration.c
clang/test/CodeGen/PowerPC/musttail-indirect.cpp
clang/test/CodeGen/PowerPC/musttail-inline.c
clang/test/CodeGen/PowerPC/musttail-undefined.c
clang/test/CodeGen/PowerPC/musttail-weak.c
clang/test/CodeGen/PowerPC/musttail.c
Modified:
clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/lib/Basic/Targets/PPC.cpp
clang/lib/Basic/Targets/PPC.h
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index de758cbe679dcf..33b1d58bb5b099 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -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<
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index 89c5566f7ad091..4ba4a49311d36b 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -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.
@@ -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);
}
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index e4d6a02386da58..b15ab6fbcf492f 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -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;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 2b301130ef7b70..7e7b2b395f7d63 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -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
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index dc9dd034dee7ba..44bc7fbfdd37e8 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -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() {
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 0444f9f8449f86..8b65348b879b65 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -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 {
@@ -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;
diff --git a/clang/test/CodeGen/PowerPC/musttail-forward-declaration-inline.c b/clang/test/CodeGen/PowerPC/musttail-forward-declaration-inline.c
new file mode 100644
index 00000000000000..3d8ff3985cb0f5
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-forward-declaration-inline.c
@@ -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 at +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;
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail-forward-declaration-weak.c b/clang/test/CodeGen/PowerPC/musttail-forward-declaration-weak.c
new file mode 100644
index 00000000000000..4314bbdd30619e
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-forward-declaration-weak.c
@@ -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 at +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;
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail-forward-declaration.c b/clang/test/CodeGen/PowerPC/musttail-forward-declaration.c
new file mode 100644
index 00000000000000..061a7a8c2da9d4
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-forward-declaration.c
@@ -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;
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail-indirect.cpp b/clang/test/CodeGen/PowerPC/musttail-indirect.cpp
new file mode 100644
index 00000000000000..3f495002606d47
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-indirect.cpp
@@ -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 at +1 {{'musttail' attribute for this call is impossible because indirect calls can not be tail called on PPC}}
+ [[clang::musttail]] return fn(params);
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail-inline.c b/clang/test/CodeGen/PowerPC/musttail-inline.c
new file mode 100644
index 00000000000000..05aac886971274
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-inline.c
@@ -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 at +1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
+ [[clang::musttail]] return foo(1);
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail-undefined.c b/clang/test/CodeGen/PowerPC/musttail-undefined.c
new file mode 100644
index 00000000000000..f2259adb018482
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-undefined.c
@@ -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 at +1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
+ [[clang::musttail]] return foo(x);
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail-weak.c b/clang/test/CodeGen/PowerPC/musttail-weak.c
new file mode 100644
index 00000000000000..dccc7a4d8cdd2c
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail-weak.c
@@ -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 at +2 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
+ // aix-error at +1 {{'musttail' attribute is not supported on AIX}}
+ [[clang::musttail]] return func2(i);
+}
diff --git a/clang/test/CodeGen/PowerPC/musttail.c b/clang/test/CodeGen/PowerPC/musttail.c
new file mode 100644
index 00000000000000..e3129263d24601
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/musttail.c
@@ -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 at +2 {{'musttail' attribute for this call is impossible because long calls can not be tail called on PPC}}
+ // aix-error at +1 {{'musttail' attribute is not supported on AIX}}
+ [[clang::musttail]] return foo(1);
+}
More information about the cfe-commits
mailing list