[cfe-commits] r69045 - in /cfe/trunk: lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h test/CodeGen/inline.c

Chris Lattner sabre at nondot.org
Tue Apr 14 09:44:36 PDT 2009


Author: lattner
Date: Tue Apr 14 11:44:36 2009
New Revision: 69045

URL: http://llvm.org/viewvc/llvm-project?rev=69045&view=rev
Log:
implement codegen support for __attribute((__gnuc_inline__)),
pulling some attribute munging stuff into GetLinkageForFunction.

This should fix PR3986

Modified:
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/test/CodeGen/inline.c

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=69045&r1=69044&r2=69045&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Apr 14 11:44:36 2009
@@ -221,19 +221,34 @@
   gv->setSection("llvm.metadata");
 }
 
-static CodeGenModule::GVALinkage GetLinkageForFunction(const FunctionDecl *FD) {
+static CodeGenModule::GVALinkage
+GetLinkageForFunction(const FunctionDecl *FD, const LangOptions &Features) {
   // "static" and attr(always_inline) functions get internal linkage.
   if (FD->getStorageClass() == FunctionDecl::Static ||
       FD->hasAttr<AlwaysInlineAttr>())
     return CodeGenModule::GVA_Internal;
 
-  if (FD->isInline()) {
-    if (FD->getStorageClass() == FunctionDecl::Extern)
-      return CodeGenModule::GVA_ExternInline;
-    return CodeGenModule::GVA_Inline;
-  }
+  if (!FD->isInline())
+    return CodeGenModule::GVA_Normal;
+  
+  if (FD->getStorageClass() == FunctionDecl::Extern)
+    return CodeGenModule::GVA_ExternInline;
 
-  return CodeGenModule::GVA_Normal;
+  // If the inline function explicitly has the GNU inline attribute on it, then
+  // force to GNUC semantics, regardless of language.
+  if (FD->hasAttr<GNUCInlineAttr>())
+    return CodeGenModule::GVA_GNUCInline;
+  
+  // The definition of inline changes based on the language.  Note that we
+  // have already handled "static inline" above, with the GVA_Internal case.
+  if (Features.CPlusPlus)
+    return CodeGenModule::GVA_CXXInline;
+  
+  if (Features.C99)
+    return CodeGenModule::GVA_C99Inline;
+  
+  // Otherwise, this is the GNU inline extension in K&R and GNU C89 mode.
+  return CodeGenModule::GVA_GNUCInline;
 }
 
 /// SetFunctionDefinitionAttributes - Set attributes for a global.
@@ -243,7 +258,7 @@
 /// EmitGlobalVarDefinition for variables).
 void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D,
                                                     llvm::GlobalValue *GV) {
-  GVALinkage Linkage = GetLinkageForFunction(D);
+  GVALinkage Linkage = GetLinkageForFunction(D, Features);
 
   if (Linkage == GVA_Internal) {
     GV->setLinkage(llvm::Function::InternalLinkage);
@@ -256,27 +271,23 @@
     // strongest linkage type we can give an inline function: we don't have to
     // codegen the definition at all, yet we know that it is "ODR".
     GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
-  } else if (Linkage == GVA_Inline) {
-    // The definition of inline changes based on the language.  Note that we
-    // have already handled "static inline" above, with the GVA_Internal case.
-    if (Features.CPlusPlus) {
-      // In C++, the compiler has to emit a definition in every translation unit
-      // that references the function.  We should use linkonce_odr because
-      // a) if all references in this translation unit are optimized away, we
-      // don't need to codegen it.  b) if the function persists, it needs to be
-      // merged with other definitions. c) C++ has the ODR, so we know the
-      // definition is dependable.
-      GV->setLinkage(llvm::Function::LinkOnceODRLinkage);
-    } else if (Features.C99) {
-      // In C99 mode, 'inline' functions are guaranteed to have a strong
-      // definition somewhere else, so we can use available_externally linkage.
-      GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
-    } else {
-      // In C89 mode, an 'inline' function may only occur in one translation
-      // unit in the program, but may be extern'd in others.  Give it strong
-      // external linkage.
-      GV->setLinkage(llvm::Function::ExternalLinkage);
-    }
+  } else if (Linkage == GVA_CXXInline) {
+    // In C++, the compiler has to emit a definition in every translation unit
+    // that references the function.  We should use linkonce_odr because
+    // a) if all references in this translation unit are optimized away, we
+    // don't need to codegen it.  b) if the function persists, it needs to be
+    // merged with other definitions. c) C++ has the ODR, so we know the
+    // definition is dependable.
+    GV->setLinkage(llvm::Function::LinkOnceODRLinkage);
+  } else if (Linkage == GVA_C99Inline) {
+    // In C99 mode, 'inline' functions are guaranteed to have a strong
+    // definition somewhere else, so we can use available_externally linkage.
+    GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
+  } else if (Linkage == GVA_GNUCInline) {
+    // In C89 mode, an 'inline' function may only occur in one translation
+    // unit in the program, but may be extern'd in others.  Give it strong
+    // external linkage.
+    GV->setLinkage(llvm::Function::ExternalLinkage);
   } else {
     GV->setLinkage(llvm::Function::ExternalLinkage);
   }
@@ -466,17 +477,13 @@
     if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
       return false;
 
-    GVALinkage Linkage = GetLinkageForFunction(FD);
+    GVALinkage Linkage = GetLinkageForFunction(FD, Features);
     
     // static, static inline, always_inline, and extern inline functions can
-    // always be deferred.
-    if (Linkage == GVA_Internal || Linkage == GVA_ExternInline)
+    // always be deferred.  Normal inline functions can be deferred in C99/C++.
+    if (Linkage == GVA_Internal || Linkage == GVA_ExternInline ||
+        Linkage == GVA_C99Inline || Linkage == GVA_CXXInline)
       return true;
-
-    // inline functions can be deferred unless we're in C89 mode.
-    if (Linkage == GVA_Inline && (Features.C99 || Features.CPlusPlus))
-      return true;
-    
     return false;
   }
   

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=69045&r1=69044&r2=69045&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Apr 14 11:44:36 2009
@@ -314,8 +314,10 @@
 
   enum GVALinkage {
     GVA_Internal,
-    GVA_Inline,
     GVA_ExternInline,
+    GVA_GNUCInline,
+    GVA_C99Inline,
+    GVA_CXXInline,
     GVA_Normal
   };
   

Modified: cfe/trunk/test/CodeGen/inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/inline.c?rev=69045&r1=69044&r2=69045&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/inline.c (original)
+++ cfe/trunk/test/CodeGen/inline.c Tue Apr 14 11:44:36 2009
@@ -1,21 +1,27 @@
+// RUN: echo "C89 tests:" &&
 // RUN: clang %s -emit-llvm -S -o %t -std=c89 &&
 // RUN: grep "define available_externally i32 @ei()" %t &&
 // RUN: grep "define i32 @foo()" %t &&
 // RUN: grep "define i32 @bar()" %t &&
 // RUN: grep "define void @unreferenced1()" %t &&
 // RUN: not grep unreferenced2 %t &&
+// RUN: grep "define void @gnu_inline()" %t &&
 
+// RUN: echo "\nC99 tests:" &&
 // RUN: clang %s -emit-llvm -S -o %t -std=c99 &&
 // RUN: grep "define available_externally i32 @ei()" %t &&
 // RUN: grep "define available_externally i32 @foo()" %t &&
 // RUN: grep "define i32 @bar()" %t &&
 // RUN: not grep unreferenced %t &&
+// RUN: grep "define void @gnu_inline()" %t &&
 
+// RUN: echo "\nC++ tests:" &&
 // RUN: clang %s -emit-llvm -S -o %t -std=c++98 &&
 // RUN: grep "define available_externally i32 @_Z2eiv()" %t &&
 // RUN: grep "define linkonce_odr i32 @_Z3foov()" %t &&
 // RUN: grep "define i32 @_Z3barv()" %t &&
-// RUN: not grep unreferenced %t
+// RUN: not grep unreferenced %t &&
+// RUN: grep "define void @_Z10gnu_inlinev()" %t
 
 extern inline int ei() { return 123; }
 
@@ -29,3 +35,4 @@
 inline void unreferenced1() {}
 extern inline void unreferenced2() {}
 
+__inline __attribute((__gnuc_inline__)) void gnu_inline() {}





More information about the cfe-commits mailing list