diff options
author | serge-sans-paille <sguelton@redhat.com> | 2021-10-19 11:23:27 +0200 |
---|---|---|
committer | serge-sans-paille <sguelton@redhat.com> | 2021-11-02 09:53:49 +0100 |
commit | 6bfc85c217e443ecbde37b142a01dc7925792edc (patch) | |
tree | f52aaab2bb68921c8ffb77583aec48e5287a45c5 /clang/lib/CodeGen/CodeGenFunction.cpp | |
parent | 48677f58b06cfb8715902173c5bc3d1764d7c8c6 (diff) | |
download | llvm-6bfc85c217e443ecbde37b142a01dc7925792edc.zip llvm-6bfc85c217e443ecbde37b142a01dc7925792edc.tar.gz llvm-6bfc85c217e443ecbde37b142a01dc7925792edc.tar.bz2 |
Fix inline builtin handling in case of redefinition
Basically, inline builtin definition are shadowed by externally visible
redefinition. This matches GCC behavior.
The implementation has to workaround the fact that:
1. inline builtin are renamed at callsite during codegen, but
2. they may be shadowed by a later external definition
As a consequence, during codegen, we need to walk redecls and eventually rewrite
some call sites, which is totally inelegant.
Differential Revision: https://reviews.llvm.org/D112059
Diffstat (limited to 'clang/lib/CodeGen/CodeGenFunction.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index fc4540f..c3c2899 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1299,18 +1299,40 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // When generating code for a builtin with an inline declaration, use a // mangled name to hold the actual body, while keeping an external definition // in case the function pointer is referenced somewhere. - if (FD->isInlineBuiltinDeclaration() && Fn) { - std::string FDInlineName = (Fn->getName() + ".inline").str(); - llvm::Module *M = Fn->getParent(); - llvm::Function *Clone = M->getFunction(FDInlineName); - if (!Clone) { - Clone = llvm::Function::Create(Fn->getFunctionType(), - llvm::GlobalValue::InternalLinkage, - Fn->getAddressSpace(), FDInlineName, M); - Clone->addFnAttr(llvm::Attribute::AlwaysInline); + if (Fn) { + if (FD->isInlineBuiltinDeclaration()) { + std::string FDInlineName = (Fn->getName() + ".inline").str(); + llvm::Module *M = Fn->getParent(); + llvm::Function *Clone = M->getFunction(FDInlineName); + if (!Clone) { + Clone = llvm::Function::Create(Fn->getFunctionType(), + llvm::GlobalValue::InternalLinkage, + Fn->getAddressSpace(), FDInlineName, M); + Clone->addFnAttr(llvm::Attribute::AlwaysInline); + } + Fn->setLinkage(llvm::GlobalValue::ExternalLinkage); + Fn = Clone; + } + + // Detect the unusual situation where an inline version is shadowed by a + // non-inline version. In that case we should pick the external one + // everywhere. That's GCC behavior too. Unfortunately, I cannot find a way + // to detect that situation before we reach codegen, so do some late + // replacement. + else { + for (const FunctionDecl *PD = FD->getPreviousDecl(); PD; + PD = PD->getPreviousDecl()) { + if (LLVM_UNLIKELY(PD->isInlineBuiltinDeclaration())) { + std::string FDInlineName = (Fn->getName() + ".inline").str(); + llvm::Module *M = Fn->getParent(); + if (llvm::Function *Clone = M->getFunction(FDInlineName)) { + Clone->replaceAllUsesWith(Fn); + Clone->eraseFromParent(); + } + break; + } + } } - Fn->setLinkage(llvm::GlobalValue::ExternalLinkage); - Fn = Clone; } // Check if we should generate debug info for this function. |