[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