[PATCH] CodeGen: Emit globals with a constant initializer but no definition as available_externally.
Benjamin Kramer
benny.kra at gmail.com
Sat Nov 16 12:29:46 PST 2013
Turned assertions into checks.
Hi rjmccall, rsmith,
http://llvm-reviews.chandlerc.com/D1982
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D1982?vs=5169&id=5597#toc
Files:
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGenCXX/constexpr-available-externally.cpp
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -1304,6 +1304,16 @@
return !isTriviallyRecursive(F);
}
+bool CodeGenModule::shouldEmitGlobalVariable(const VarDecl *VD) {
+ if (GetLLVMLinkageVarDefinition(VD, /*isConstant=*/true) ==
+ llvm::Function::AvailableExternallyLinkage) {
+ assert(isTypeConstant(VD->getType(), /*ExcludeCtor=*/true) &&
+ "available_externally variable should be constant!");
+ return CodeGenOpts.OptimizationLevel != 0;
+ }
+ return true;
+}
+
/// If the type for the method's class was generated by
/// CGDebugInfo::createContextChain(), the cache contains only a
/// limited DIType without any declarations. Since EmitFunctionStart()
@@ -1354,8 +1364,13 @@
return EmitGlobalFunctionDefinition(GD);
}
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // At -O0, don't generate IR for vars with available_externally linkage.
+ if (!shouldEmitGlobalVariable(VD))
+ return;
+
return EmitGlobalVarDefinition(VD);
+ }
llvm_unreachable("Invalid argument to EmitGlobalDefinition()");
}
@@ -1607,6 +1622,17 @@
CXXThreadLocals.push_back(std::make_pair(D, GV));
setTLSMode(GV, *D);
}
+
+ // If the variable has an initializer but no definition we can emit it with
+ // available_externally linkage.
+ if (D->hasInit() && !D->hasDefinition(Context) &&
+ !D->getType().isVolatileQualified() &&
+ isTypeConstant(D->getType(), /*ExcludeCtor=*/true)) {
+ assert(GetLLVMLinkageVarDefinition(D, /*isConstant=*/true) ==
+ llvm::GlobalValue::AvailableExternallyLinkage &&
+ "Global variable should be available_externally!");
+ DeferredDeclsToEmit.push_back(D);
+ }
}
if (AddrSpace != Ty->getAddressSpace())
@@ -1890,6 +1916,16 @@
llvm::GlobalValue::LinkageTypes
CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
+ // Check for definitionless vars. We can emit them with available_externally
+ // linkage. We check this before calling GetGVALinkageForVariable because it
+ // can happen for explicit template instantiations that would cause an
+ // assertion failure otherwise.
+ if (D->hasInit() && !D->hasDefinition(Context)) {
+ assert(isTypeConstant(D->getType(), /*ExcludeCtor=*/true) &&
+ "Variable to be emitted as available externally must be constant!");
+ return llvm::GlobalValue::AvailableExternallyLinkage;
+ }
+
GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
if (Linkage == GVA_Internal)
return llvm::Function::InternalLinkage;
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -396,6 +396,7 @@
bool isTriviallyRecursive(const FunctionDecl *F);
bool shouldEmitFunction(GlobalDecl GD);
+ bool shouldEmitGlobalVariable(const VarDecl *D);
/// @name Cache for Blocks Runtime Globals
/// @{
Index: test/CodeGenCXX/constexpr-available-externally.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/constexpr-available-externally.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -emit-llvm -O1 -std=c++11 -disable-llvm-optzns -o - %s | FileCheck %s
+
+// PR17612
+// CHECK: @_ZN6Object3fooE = available_externally constant %struct.Literal { i32 1 }
+// CHECK: @_ZN6Object3barE = available_externally constant i32 42
+// CHECK: @_ZN3tplIiE4nposE = available_externally constant i32 -1
+// CHECK: @_ZN6Holder11threadlocalE = available_externally thread_local constant i32 1
+// CHECK-NOT: @_ZN1S1nE = available_externally
+// CHECK-NOT: @_ZN1B1aE = available_externally
+
+struct Literal {
+ int i;
+ constexpr Literal(int i) : i(i) {}
+};
+
+struct Object {
+ static constexpr Literal foo = Literal(1);
+ static const int bar = 42;
+};
+
+void bar(const int &);
+
+int f() {
+ Literal l = Object::foo;
+ bar(Object::bar);
+ return l.i;
+
+// CHECK-LABEL: @_Z1fv
+// CHECK: call void @llvm.memcpy{{[^(]*}}(i8* %{{[^,]*}}, i8* bitcast (%struct.Literal* @_ZN6Object3fooE to i8*)
+// CHECK: call void @_Z3barRKi(i32* @_ZN6Object3barE)
+}
+
+template <typename T>
+struct tpl {
+ static const T npos = -1;
+};
+
+template struct tpl<int>;
+
+void g() {
+ bar(tpl<int>::npos);
+// CHECK-LABEL: @_Z1gv
+// CHECK: call void @_Z3barRKi(i32* @_ZN3tplIiE4nposE)
+}
+
+constexpr int constone() { return 1; }
+struct Holder {
+ static const int thread_local threadlocal = constone();
+};
+const int *h() {
+ return &Holder::threadlocal;
+}
+
+struct S {
+ static constexpr volatile int n = 0;
+};
+const volatile void *j() {
+ return &S::n;
+}
+
+struct A {
+ mutable int n;
+};
+struct B {
+ static constexpr A a = { 0 };
+};
+const void *k() {
+ return &B::a;
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1982.5.patch
Type: text/x-patch
Size: 4990 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131116/b16824bc/attachment.bin>
More information about the cfe-commits
mailing list