aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CodeGenFunction.cpp
diff options
context:
space:
mode:
authorserge-sans-paille <sguelton@redhat.com>2021-10-19 11:23:27 +0200
committerserge-sans-paille <sguelton@redhat.com>2021-11-02 09:53:49 +0100
commit6bfc85c217e443ecbde37b142a01dc7925792edc (patch)
treef52aaab2bb68921c8ffb77583aec48e5287a45c5 /clang/lib/CodeGen/CodeGenFunction.cpp
parent48677f58b06cfb8715902173c5bc3d1764d7c8c6 (diff)
downloadllvm-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.cpp44
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.