diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2011-10-26 20:41:06 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2011-10-26 20:41:06 +0000 |
commit | a411d2f1ed4598a7a96a7befe07a9d9ee1a6efde (patch) | |
tree | b829ea5b2d3a94918477cca8a1362e1760e8d97b | |
parent | 29e627ad9679bd3aa274cbe464127fdaba6241ca (diff) |
Fix pr9614 by not emitting an available_externally function when it calls
itself via an asm label.
available_externally functions are supposed to correspond to an external
function, and that is not the case in the examples in pr9614.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143049 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 62 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 2 | ||||
-rw-r--r-- | test/CodeGen/pr9614.c | 15 |
3 files changed, 75 insertions, 4 deletions
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 03fb18177a..86378a9afa 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -29,6 +29,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -858,6 +859,62 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } } +namespace { + struct FunctionIsDirectlyRecursive : + public RecursiveASTVisitor<FunctionIsDirectlyRecursive> { + const StringRef Name; + bool Result; + FunctionIsDirectlyRecursive(const FunctionDecl *F) : + Name(F->getName()), Result(false) { + } + typedef RecursiveASTVisitor<FunctionIsDirectlyRecursive> Base; + + bool TraverseCallExpr(CallExpr *E) { + const Decl *D = E->getCalleeDecl(); + if (!D) + return true; + AsmLabelAttr *Attr = D->getAttr<AsmLabelAttr>(); + if (!Attr) + return true; + if (Name == Attr->getLabel()) { + Result = true; + return false; + } + return true; + } + }; +} + +// isTriviallyRecursiveViaAsm - Check if this function calls another +// decl that, because of the asm attribute, ends up pointing to itself. +bool +CodeGenModule::isTriviallyRecursiveViaAsm(const FunctionDecl *F) { + if (getCXXABI().getMangleContext().shouldMangleDeclName(F)) + return false; + + FunctionIsDirectlyRecursive Walker(F); + Walker.TraverseFunctionDecl(const_cast<FunctionDecl*>(F)); + return Walker.Result; +} + +bool +CodeGenModule::shouldEmitFunction(const FunctionDecl *F) { + if (getFunctionLinkage(F) != llvm::Function::AvailableExternallyLinkage) + return true; + if (F->hasAttr<AlwaysInlineAttr>()) + return true; + if (CodeGenOpts.OptimizationLevel == 0) + return false; + // PR9614. Avoid cases where the source code is lying to us. An available + // externally function should have an equivalent function somewhere else, + // but a function that calls itself is clearly not equivalent to the real + // implementation. + // This happens in glibc's btowc and in some configure checks. + if (isTriviallyRecursiveViaAsm(F)) + return false; + return true; +} + void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast<ValueDecl>(GD.getDecl()); @@ -868,10 +925,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // At -O0, don't generate IR for functions with available_externally // linkage. - if (CodeGenOpts.OptimizationLevel == 0 && - !Function->hasAttr<AlwaysInlineAttr>() && - getFunctionLinkage(Function) - == llvm::Function::AvailableExternallyLinkage) + if (!shouldEmitFunction(Function)) return; if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 8e38a89990..dbc6a87bd1 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -324,6 +324,8 @@ class CodeGenModule : public CodeGenTypeCache { void createOpenCLRuntime(); void createCUDARuntime(); + bool isTriviallyRecursiveViaAsm(const FunctionDecl *F); + bool shouldEmitFunction(const FunctionDecl *F); llvm::LLVMContext &VMContext; /// @name Cache for Blocks Runtime Globals diff --git a/test/CodeGen/pr9614.c b/test/CodeGen/pr9614.c new file mode 100644 index 0000000000..9cc7fa3bed --- /dev/null +++ b/test/CodeGen/pr9614.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +extern int foo_alias (void) __asm ("foo"); +inline int foo (void) { + return foo_alias (); +} +int f(void) { + return foo(); +} + +// CHECK-NOT: define +// CHECK: define i32 @f() +// CHECK: %call = call i32 @foo() +// CHECK: ret i32 %call +// CHECK-NOT: define |