This patch implements something on the line of Eli's comment:
>Oh, also, if you want to get something into 3.0 quickly, just hacking
>clang so it doesn't emit the definition at all in situations like
>PR9614 would be more obviously acceptable.
I now think that this is the correct fix given how bad the code snippet
is. What the patch does is try to detect cases where the external
functions "cannot" be equivalent to available_externally one we are
about to emit.
Cheers,
Rafael
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 03fb181..56a6d84 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,61 @@ 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;
+ // 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.
+ if (isTriviallyRecursiveViaAsm(F))
+ return false;
+ if (F->hasAttr<AlwaysInlineAttr>())
+ return true;
+ if (CodeGenOpts.OptimizationLevel == 0)
+ return false;
+ return true;
+}
+
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
@@ -868,10 +924,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 8e38a89..dbc6a87 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 0000000..9e863d7
--- /dev/null
+++ b/test/CodeGen/pr9614.c
@@ -0,0 +1,13 @@
+// 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: define i32 @f()
+// CHECK: %call = call i32 @foo()
+// CHECK: ret i32 %call
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits