From c594135b68e7c8264f4fa045684df9f029798fac Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 26 Oct 2011 20:41:06 +0000 Subject: [PATCH] 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. llvm-svn: 143049 --- clang/lib/CodeGen/CodeGenModule.cpp | 62 +++++++++++++++++++++++++++-- clang/lib/CodeGen/CodeGenModule.h | 2 + clang/test/CodeGen/pr9614.c | 15 +++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 clang/test/CodeGen/pr9614.c diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 03fb18177aa3..86378a9afa02 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/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 { + const StringRef Name; + bool Result; + FunctionIsDirectlyRecursive(const FunctionDecl *F) : + Name(F->getName()), Result(false) { + } + typedef RecursiveASTVisitor Base; + + bool TraverseCallExpr(CallExpr *E) { + const Decl *D = E->getCalleeDecl(); + if (!D) + return true; + AsmLabelAttr *Attr = D->getAttr(); + 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(F)); + return Walker.Result; +} + +bool +CodeGenModule::shouldEmitFunction(const FunctionDecl *F) { + if (getFunctionLinkage(F) != llvm::Function::AvailableExternallyLinkage) + return true; + if (F->hasAttr()) + 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(GD.getDecl()); @@ -868,10 +925,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { if (const FunctionDecl *Function = dyn_cast(D)) { // At -O0, don't generate IR for functions with available_externally // linkage. - if (CodeGenOpts.OptimizationLevel == 0 && - !Function->hasAttr() && - getFunctionLinkage(Function) - == llvm::Function::AvailableExternallyLinkage) + if (!shouldEmitFunction(Function)) return; if (const CXXMethodDecl *Method = dyn_cast(D)) { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 8e38a8999013..dbc6a87bd19b 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/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/clang/test/CodeGen/pr9614.c b/clang/test/CodeGen/pr9614.c new file mode 100644 index 000000000000..9cc7fa3bed8a --- /dev/null +++ b/clang/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