diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index de758cbe679dc..33b1d58bb5b09 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 a1e5f20f7dbe2..9ba0d108e3281 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -93,6 +93,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector &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 e4d6a02386da5..b15ab6fbcf492 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 2b301130ef7b7..7e7b2b395f7d6 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(CI)) { if (TargetDecl && TargetDecl->hasAttr()) 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(TargetDecl)) { + if (!cast(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(TargetDecl), Loc}); + else { + llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage( + GlobalDecl(cast(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 652f519d82488..df8482f407451 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 22b2b314c316c..85e0b9715ac10 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -485,6 +485,14 @@ class CodeGenModule : public CodeGenTypeCache { typedef std::pair 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, 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 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 0000000000000..3d8ff3985cb0f --- /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@+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 0000000000000..4314bbdd30619 --- /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@+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 0000000000000..061a7a8c2da9d --- /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 0000000000000..3f495002606d4 --- /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@+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 0000000000000..05aac88697127 --- /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@+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 0000000000000..f2259adb01848 --- /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@+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 0000000000000..dccc7a4d8cdd2 --- /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@+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); +} diff --git a/clang/test/CodeGen/PowerPC/musttail.c b/clang/test/CodeGen/PowerPC/musttail.c new file mode 100644 index 0000000000000..e3129263d2460 --- /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@+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); +}