r247465 - Always_inline codegen rewrite.

Evgeniy Stepanov via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 11 13:29:08 PDT 2015


Author: eugenis
Date: Fri Sep 11 15:29:07 2015
New Revision: 247465

URL: http://llvm.org/viewvc/llvm-project?rev=247465&view=rev
Log:
Always_inline codegen rewrite.

Current implementation may end up emitting an undefined reference for
an "inline __attribute__((always_inline))" function by generating an
"available_externally alwaysinline" IR function for it and then failing to
inline all the calls. This happens when a call to such function is in dead
code. As the inliner is an SCC pass, it does not process dead code.

Libc++ relies on the compiler never emitting such undefined reference.

With this patch, we emit a pair of
1. internal alwaysinline definition (called F.alwaysinline)
2a. A stub F() { musttail call F.alwaysinline }
  -- or, depending on the linkage --
2b. A declaration of F.

The frontend ensures that F.inlinefunction is only used for direct
calls, and the stub is used for everything else (taking the address of
the function, really). Declaration (2b) is emitted in the case when
"inline" is meant for inlining only (like __gnu_inline__ and some
other cases).

This approach, among other nice properties, ensures that alwaysinline
functions are always internal, making it impossible for a direct call
to such function to produce an undefined symbol reference.

This patch is based on ideas by Chandler Carruth and Richard Smith.

Added:
    cfe/trunk/test/CodeGen/always_inline-unused.c
    cfe/trunk/test/CodeGen/always_inline-wrappers.c
    cfe/trunk/test/CodeGenCXX/alwaysinline.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/test/CodeGen/always-inline.c
    cfe/trunk/test/CodeGen/always_inline.c
    cfe/trunk/test/CodeGen/function-attributes.c
    cfe/trunk/test/CodeGen/pr9614.c
    cfe/trunk/test/Frontend/optimization-remark-line-directive.c
    cfe/trunk/test/Frontend/optimization-remark.c
    cfe/trunk/test/Modules/cxx-irgen.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Fri Sep 11 15:29:07 2015
@@ -109,6 +109,9 @@ bool CodeGenModule::TryEmitBaseDestructo
       D->getType()->getAs<FunctionType>()->getCallConv())
     return true;
 
+  if (BaseD->hasAttr<AlwaysInlineAttr>())
+    return true;
+
   return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
                                   GlobalDecl(BaseD, Dtor_Base),
                                   false);
@@ -161,14 +164,7 @@ bool CodeGenModule::TryEmitDefinitionAsA
 
   // Instead of creating as alias to a linkonce_odr, replace all of the uses
   // of the aliasee.
-  if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
-     (TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
-      !TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
-    // FIXME: An extern template instantiation will create functions with
-    // linkage "AvailableExternally". In libc++, some classes also define
-    // members with attribute "AlwaysInline" and expect no reference to
-    // be generated. It is desirable to reenable this optimisation after
-    // corresponding LLVM changes.
+  if (llvm::GlobalValue::isDiscardableIfUnused(Linkage)) {
     Replacements[MangledName] = Aliasee;
     return false;
   }

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Fri Sep 11 15:29:07 2015
@@ -1557,7 +1557,7 @@ void CodeGenFunction::EmitDestructorBody
     // -fapple-kext must inline any call to this dtor into
     // the caller's body.
     if (getLangOpts().AppleKext)
-      CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
+      CGM.AddAlwaysInlineFunction(CurFn);
 
     break;
   }

Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Fri Sep 11 15:29:07 2015
@@ -2114,7 +2114,7 @@ emitTaskPrivateMappingFunction(CodeGenMo
       ".omp_task_privates_map.", &CGM.getModule());
   CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, TaskPrivatesMapFnInfo,
                                 TaskPrivatesMap);
-  TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
+  CGM.AddAlwaysInlineFunction(TaskPrivatesMap);
   CodeGenFunction CGF(CGM);
   CGF.disableDebugInfo();
   CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskPrivatesMap,

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Sep 11 15:29:07 2015
@@ -448,6 +448,103 @@ void CodeGenModule::Release() {
   EmitVersionIdentMetadata();
 
   EmitTargetMetadata();
+
+  RewriteAlwaysInlineFunctions();
+}
+
+void CodeGenModule::AddAlwaysInlineFunction(llvm::Function *Fn) {
+  AlwaysInlineFunctions.push_back(Fn);
+}
+
+/// Find all uses of GV that are not direct calls or invokes.
+static void FindNonDirectCallUses(llvm::GlobalValue *GV,
+                                  llvm::SmallVectorImpl<llvm::Use *> *Uses) {
+  llvm::GlobalValue::use_iterator UI = GV->use_begin(), E = GV->use_end();
+  for (; UI != E;) {
+    llvm::Use &U = *UI;
+    ++UI;
+
+    llvm::CallSite CS(U.getUser());
+    bool isDirectCall = (CS.isCall() || CS.isInvoke()) && CS.isCallee(&U);
+    if (!isDirectCall)
+      Uses->push_back(&U);
+  }
+}
+
+/// Replace a list of uses.
+static void ReplaceUsesWith(const llvm::SmallVectorImpl<llvm::Use *> &Uses,
+                            llvm::GlobalValue *V,
+                            llvm::GlobalValue *Replacement) {
+  for (llvm::Use *U : Uses) {
+    auto *C = dyn_cast<llvm::Constant>(U->getUser());
+    if (C && !isa<llvm::GlobalValue>(C))
+      C->handleOperandChange(V, Replacement, U);
+    else
+      U->set(Replacement);
+  }
+}
+
+void CodeGenModule::RewriteAlwaysInlineFunction(llvm::Function *Fn) {
+  std::string Name = Fn->getName();
+  std::string InlineName = Name + ".alwaysinline";
+  Fn->setName(InlineName);
+
+  llvm::SmallVector<llvm::Use *, 8> NonDirectCallUses;
+  Fn->removeDeadConstantUsers();
+  FindNonDirectCallUses(Fn, &NonDirectCallUses);
+  // Do not create the wrapper if there are no non-direct call uses, and we are
+  // not required to emit an external definition.
+  if (NonDirectCallUses.empty() && Fn->isDiscardableIfUnused())
+    return;
+
+  llvm::FunctionType *FT = Fn->getFunctionType();
+  llvm::LLVMContext &Ctx = getModule().getContext();
+  llvm::Function *StubFn =
+      llvm::Function::Create(FT, Fn->getLinkage(), Name, &getModule());
+  assert(StubFn->getName() == Name && "name was uniqued!");
+
+  // Insert the stub immediately after the original function. Helps with the
+  // fragile tests, among other things.
+  StubFn->removeFromParent();
+  TheModule.getFunctionList().insertAfter(Fn, StubFn);
+
+  StubFn->copyAttributesFrom(Fn);
+  StubFn->setPersonalityFn(nullptr);
+
+  // AvailableExternally functions are replaced with a declaration.
+  // Everyone else gets a wrapper that musttail-calls the original function.
+  if (Fn->hasAvailableExternallyLinkage()) {
+    StubFn->setLinkage(llvm::GlobalValue::ExternalLinkage);
+  } else {
+    llvm::BasicBlock *BB = llvm::BasicBlock::Create(Ctx, "entry", StubFn);
+    std::vector<llvm::Value *> Args;
+    for (llvm::Function::arg_iterator ai = StubFn->arg_begin();
+         ai != StubFn->arg_end(); ++ai)
+      Args.push_back(&*ai);
+    llvm::CallInst *CI = llvm::CallInst::Create(Fn, Args, "", BB);
+    CI->setCallingConv(Fn->getCallingConv());
+    CI->setTailCallKind(llvm::CallInst::TCK_MustTail);
+    CI->setAttributes(Fn->getAttributes());
+    if (FT->getReturnType()->isVoidTy())
+      llvm::ReturnInst::Create(Ctx, BB);
+    else
+      llvm::ReturnInst::Create(Ctx, CI, BB);
+  }
+
+  if (Fn->hasComdat())
+    StubFn->setComdat(Fn->getComdat());
+
+  ReplaceUsesWith(NonDirectCallUses, Fn, StubFn);
+}
+
+void CodeGenModule::RewriteAlwaysInlineFunctions() {
+  for (llvm::Function *Fn : AlwaysInlineFunctions) {
+    RewriteAlwaysInlineFunction(Fn);
+    Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
+    Fn->addFnAttr(llvm::Attribute::AlwaysInline);
+    Fn->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
+    Fn->setVisibility(llvm::GlobalValue::DefaultVisibility);
+  }
 }
 
 void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
@@ -772,7 +869,7 @@ void CodeGenModule::SetLLVMFunctionAttri
              !F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
                                               llvm::Attribute::NoInline)) {
     // (noinline wins over always_inline, and we can't specify both in IR)
-    B.addAttribute(llvm::Attribute::AlwaysInline);
+    AddAlwaysInlineFunction(F);
   }
 
   if (D->hasAttr<ColdAttr>()) {

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri Sep 11 15:29:07 2015
@@ -489,6 +489,8 @@ private:
   /// MDNodes.
   llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap;
 
+  llvm::SmallVector<llvm::Function*, 8> AlwaysInlineFunctions;
+
 public:
   CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
                 const PreprocessorOptions &ppopts,
@@ -1131,6 +1133,8 @@ public:
   /// \breif Get the declaration of std::terminate for the platform.
   llvm::Constant *getTerminateFn();
 
+  void AddAlwaysInlineFunction(llvm::Function *Fn);
+
 private:
   llvm::Constant *
   GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
@@ -1226,6 +1230,12 @@ private:
   /// Emits target specific Metadata for global declarations.
   void EmitTargetMetadata();
 
+  /// Replaces alwaysinline functions with a pair of internal xxx.inlinefunction
+  /// for direct calls, and a stub for indirect calls, and rewrites all uses of
+  /// those.
+  void RewriteAlwaysInlineFunctions();
+  void RewriteAlwaysInlineFunction(llvm::Function *Fn);
+
   /// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
   /// .gcda files in a way that persists in .bc files.
   void EmitCoverageFile();

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Sep 11 15:29:07 2015
@@ -3311,6 +3311,9 @@ static StructorCodegen getCodegenToUse(C
   if (MD->getParent()->getNumVBases())
     return StructorCodegen::Emit;
 
+  if (MD->hasAttr<AlwaysInlineAttr>())
+    return StructorCodegen::Emit;
+
   GlobalDecl AliasDecl;
   if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
     AliasDecl = GlobalDecl(DD, Dtor_Complete);

Modified: cfe/trunk/test/CodeGen/always-inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/always-inline.c?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/always-inline.c (original)
+++ cfe/trunk/test/CodeGen/always-inline.c Fri Sep 11 15:29:07 2015
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -fno-inline -emit-llvm %s -o - | FileCheck %s
 
+// CHECK-LABEL: define void @i_want_bar()
 // CHECK-NOT: foo
+// CHECK: ret void
 
 void bar() {
 }

Added: cfe/trunk/test/CodeGen/always_inline-unused.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/always_inline-unused.c?rev=247465&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/always_inline-unused.c (added)
+++ cfe/trunk/test/CodeGen/always_inline-unused.c Fri Sep 11 15:29:07 2015
@@ -0,0 +1,31 @@
+// Test alwaysinline definitions w/o any non-direct-call uses.
+// None of the declarations are emitted. Stub are only emitted when the original
+// function can not be discarded.
+
+// RUN: %clang_cc1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s
+
+void __attribute__((__always_inline__)) f1() {}
+inline void __attribute__((__always_inline__)) f2() {}
+static inline void __attribute__((__always_inline__)) f3() {}
+inline void __attribute__((gnu_inline, __always_inline__)) f4() {}
+static inline void __attribute__((gnu_inline, __always_inline__)) f5() {}
+inline void __attribute__((visibility("hidden"), __always_inline__)) f6() {}
+inline void __attribute__((visibility("hidden"), gnu_inline, __always_inline__)) f7() {}
+
+void g() {
+  f1();
+  f2();
+  f3();
+  f4();
+  f5();
+  f6();
+  f7();
+}
+
+// CHECK: define void @f1()
+// CHECK-NOT: void @f2()
+// CHECK-NOT: void @f3()
+// CHECK: define void @f4()
+// CHECK-NOT: void @f5()
+// CHECK-NOT: void @f6()
+// CHECK: define hidden void @f7()

Added: cfe/trunk/test/CodeGen/always_inline-wrappers.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/always_inline-wrappers.c?rev=247465&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/always_inline-wrappers.c (added)
+++ cfe/trunk/test/CodeGen/always_inline-wrappers.c Fri Sep 11 15:29:07 2015
@@ -0,0 +1,108 @@
+// Test different kinds of alwaysinline definitions.
+
+// RUN: %clang_cc1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-INLINE
+// RUN: %clang_cc1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-USE
+// RUN: %clang_cc1 -disable-llvm-optzns -fno-inline -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -disable-llvm-optzns -fno-inline -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-USE
+
+void __attribute__((__always_inline__)) f1() {}
+inline void __attribute__((__always_inline__)) f2() {}
+static inline void __attribute__((__always_inline__)) f3() {}
+inline void __attribute__((gnu_inline, __always_inline__)) f4() {}
+static inline void __attribute__((gnu_inline, __always_inline__)) f5() {}
+inline void __attribute__((visibility("hidden"), __always_inline__)) f6() {}
+inline void __attribute__((visibility("hidden"), gnu_inline, __always_inline__)) f7() {}
+
+void g() {
+  f1();
+  f2();
+  f3();
+  f4();
+  f5();
+  f6();
+  f7();
+}
+
+void (*p)(void);
+void h() {
+  p = f1;
+  p = f2;
+  p = f3;
+  p = f4;
+  p = f5;
+  p = f6;
+  p = f7;
+}
+
+void (*const cp1)(void) = f1;
+void (*p1)(void) = f1;
+void (*p2)(int) = (void (*)(int))f1;
+
+void __attribute__((__always_inline__)) f8(void(*f)(void)) {}
+
+void call() {
+  f8(f1);
+}
+
+// CHECK-DAG: define internal void @f1.alwaysinline() #[[AI:[0-9]+]]
+// CHECK-DAG: define internal void @f2.alwaysinline() #[[AI_IH:[0-9]+]]
+// CHECK-DAG: define internal void @f3.alwaysinline() #[[AI_IH]]
+// CHECK-DAG: define internal void @f4.alwaysinline() #[[AI_IH]]
+// CHECK-DAG: define internal void @f5.alwaysinline() #[[AI_IH]]
+// CHECK-DAG: define internal void @f6.alwaysinline() #[[AI_IH]]
+// CHECK-DAG: define internal void @f7.alwaysinline() #[[AI_IH]]
+
+
+// CHECK-DAG: define void @f1() #[[NOAI:[01-9]+]]
+// CHECK-DAG: musttail call void @f1.alwaysinline()
+
+// CHECK-DAG: declare void @f2() #[[NOAI:[01-9]+]]
+
+// CHECK-DAG: define internal void @f3() #[[NOAI:[01-9]+]]
+// CHECK-DAG: musttail call void @f3.alwaysinline()
+
+// CHECK-DAG: define void @f4() #[[NOAI:[01-9]+]]
+// CHECK-DAG: musttail call void @f4.alwaysinline()
+
+// CHECK-DAG: define internal void @f5() #[[NOAI:[01-9]+]]
+// CHECK-DAG: musttail call void @f5.alwaysinline()
+
+// CHECK-DAG: declare hidden void @f6() #[[NOAI:[01-9]+]]
+
+// CHECK-DAG: define hidden void @f7() #[[NOAI:[01-9]+]]
+// CHECK-DAG: musttail call void @f7.alwaysinline()
+
+
+// CHECK-DAG: @cp1 = constant void ()* @f1, align
+// CHECK-DAG: @p1 = global void ()* @f1, align
+// CHECK-DAG: @p2 = global void (i32)* bitcast (void ()* @f1 to void (i32)*), align
+
+// CHECK: attributes #[[AI]] = {{.*alwaysinline.*}}
+// CHECK-INLINE: attributes #[[AI_IH]] = {{.*alwaysinline.*inlinehint.*}}
+// CHECK-NOT: attributes #[[NOAI]] = {{.*alwaysinline.*}}
+
+// CHECK-USE-LABEL: define void @g()
+// CHECK-USE-NEXT:   entry:
+// CHECK-USE-NEXT:     call void @f1.alwaysinline()
+// CHECK-USE-NEXT:     call void @f2.alwaysinline()
+// CHECK-USE-NEXT:     call void @f3.alwaysinline()
+// CHECK-USE-NEXT:     call void @f4.alwaysinline()
+// CHECK-USE-NEXT:     call void @f5.alwaysinline()
+// CHECK-USE-NEXT:     call void @f6.alwaysinline()
+// CHECK-USE-NEXT:     call void @f7.alwaysinline()
+// CHECK-USE-NEXT:     ret void
+
+// CHECK-USE-LABEL: define void @h()
+// CHECK-USE-NEXT:   entry:
+// CHECK-USE-NEXT:     store void ()* @f1,
+// CHECK-USE-NEXT:     store void ()* @f2,
+// CHECK-USE-NEXT:     store void ()* @f3,
+// CHECK-USE-NEXT:     store void ()* @f4,
+// CHECK-USE-NEXT:     store void ()* @f5,
+// CHECK-USE-NEXT:     store void ()* @f6,
+// CHECK-USE-NEXT:     store void ()* @f7,
+// CHECK-USE-NEXT:     ret void
+
+// CHECK-USE-LABEL:  define void @call()
+// CHECK-USE:           call void @f8.alwaysinline(void ()* @f1)
+// CHECK-USE:           ret void

Modified: cfe/trunk/test/CodeGen/always_inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/always_inline.c?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/always_inline.c (original)
+++ cfe/trunk/test/CodeGen/always_inline.c Fri Sep 11 15:29:07 2015
@@ -1,8 +1,5 @@
-// RUN: %clang -emit-llvm -S -o %t %s
-// RUN: not grep '@f0' %t
-// RUN: not grep 'call ' %t
-// RUN: %clang -mllvm -disable-llvm-optzns -emit-llvm -S -o %t %s
-// RUN: grep '@f0' %t | count 2
+// RUN: %clang -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -mllvm -disable-llvm-optzns -emit-llvm -S -o - %s | FileCheck %s --check-prefix=CHECK-NO-OPTZNS
 
 //static int f0() { 
 static int __attribute__((always_inline)) f0() { 
@@ -18,3 +15,14 @@ inline int f2() __attribute__((always_in
 int f2() { return 7; }
 int f3(void) { return f2(); }
 
+// CHECK-LABEL: define i32 @f1()
+// CHECK: ret i32 1
+// CHECK-LABEL: define i32 @f2()
+// CHECK: ret i32 7
+// CHECK-LABEL: define i32 @f3()
+// CHECK: ret i32 7
+
+// CHECK-NO-OPTZNS: define i32 @f3()
+// CHECK-NO-OPTZNS-NEXT: entry:
+// CHECK-NO-OPTZNS-NEXT:   call i32 @f2.alwaysinline()
+// CHECK-NO-OPTZNS-NEXT:   ret i32

Modified: cfe/trunk/test/CodeGen/function-attributes.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/function-attributes.c?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/function-attributes.c (original)
+++ cfe/trunk/test/CodeGen/function-attributes.c Fri Sep 11 15:29:07 2015
@@ -25,8 +25,8 @@ void f6(signed short x) { }
 
 void f7(unsigned short x) { }
 
-// CHECK-LABEL: define void @f8()
-// CHECK: [[AI:#[0-9]+]]
+// CHECK: define void @f8()
+// CHECK: [[NUW:#[0-9]+]]
 // CHECK: {
 void __attribute__((always_inline)) f8(void) { }
 
@@ -129,7 +129,6 @@ void f20(void) {
 }
 
 // CHECK: attributes [[NUW]] = { nounwind optsize readnone{{.*}} }
-// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize readnone{{.*}} }
 // CHECK: attributes [[ALIGN]] = { nounwind optsize readnone alignstack=16{{.*}} }
 // CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} }
 // CHECK: attributes [[NR]] = { noreturn nounwind optsize }

Modified: cfe/trunk/test/CodeGen/pr9614.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/pr9614.c?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/pr9614.c (original)
+++ cfe/trunk/test/CodeGen/pr9614.c Fri Sep 11 15:29:07 2015
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK0
+// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK1
 
 extern void foo_alias (void) __asm ("foo");
 inline void foo (void) {
@@ -24,7 +25,7 @@ extern inline __attribute__((__always_in
 
 void f(void) {
   foo();
-  abs(0);
+  int x = abs(0);
   strrchr_foo("", '.');
   prefetch();
   memchr("", '.', 0);
@@ -32,9 +33,10 @@ void f(void) {
 
 // CHECK-LABEL: define void @f()
 // CHECK: call void @foo()
-// CHECK: call i32 @abs(i32 0)
+// CHECK: call i32 @abs(
 // CHECK: call i8* @strrchr(
-// CHECK: call void @llvm.prefetch(
+// CHECK0: call void @llvm.prefetch(
+// CHECK1: call void @prefetch.alwaysinline(
 // CHECK: call i8* @memchr(
 // CHECK: ret void
 

Added: cfe/trunk/test/CodeGenCXX/alwaysinline.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/alwaysinline.cpp?rev=247465&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/alwaysinline.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/alwaysinline.cpp Fri Sep 11 15:29:07 2015
@@ -0,0 +1,68 @@
+// Test different kinds of alwaysinline *structor definitions.
+
+// RUN: %clang_cc1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-CALL
+
+// RUN: %clang_cc1 -mconstructor-aliases -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -mconstructor-aliases -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-CALL
+
+struct A1 {
+  __attribute__((__always_inline__)) A1() {}
+  __attribute__((__always_inline__)) ~A1() {}
+};
+
+void g1() {
+  A1 a1;
+}
+
+struct A2 {
+  inline __attribute__((__always_inline__)) A2() {}
+  inline __attribute__((__always_inline__)) ~A2() {}
+};
+
+void g2() {
+  A2 a2;
+}
+
+struct A3 {
+  inline __attribute__((gnu_inline, __always_inline__)) A3() {}
+  inline __attribute__((gnu_inline, __always_inline__)) ~A3() {}
+};
+
+void g3() {
+  A3 a3;
+}
+
+// CHECK-DAG: define internal void @_ZN2A1C1Ev.alwaysinline(%struct.A1* %this) unnamed_addr #[[AI:[01-9]+]]
+// CHECK-DAG: define internal void @_ZN2A1C2Ev.alwaysinline(%struct.A1* %this) unnamed_addr #[[AI]]
+// CHECK-DAG: define internal void @_ZN2A1D1Ev.alwaysinline(%struct.A1* %this) unnamed_addr #[[AI]]
+// CHECK-DAG: define internal void @_ZN2A1D2Ev.alwaysinline(%struct.A1* %this) unnamed_addr #[[AI]]
+
+// CHECK-DAG: define internal void @_ZN2A2C1Ev.alwaysinline(%struct.A2* %this) unnamed_addr #[[AIIH:[01-9]+]]
+// CHECK-DAG: define internal void @_ZN2A2C2Ev.alwaysinline(%struct.A2* %this) unnamed_addr #[[AIIH]]
+// CHECK-DAG: define internal void @_ZN2A2D1Ev.alwaysinline(%struct.A2* %this) unnamed_addr #[[AIIH]]
+// CHECK-DAG: define internal void @_ZN2A2D2Ev.alwaysinline(%struct.A2* %this) unnamed_addr #[[AIIH]]
+
+// CHECK-DAG: define internal void @_ZN2A3C1Ev.alwaysinline(%struct.A3* %this) unnamed_addr #[[AIIH]]
+// CHECK-DAG: define internal void @_ZN2A3C2Ev.alwaysinline(%struct.A3* %this) unnamed_addr #[[AIIH]]
+// CHECK-DAG: define internal void @_ZN2A3D1Ev.alwaysinline(%struct.A3* %this) unnamed_addr #[[AIIH]]
+// CHECK-DAG: define internal void @_ZN2A3D2Ev.alwaysinline(%struct.A3* %this) unnamed_addr #[[AIIH]]
+
+// CHECK-DAG: attributes #[[AI]] = {{.*alwaysinline.*}}
+// CHECK-DAG: attributes #[[AIIH]] = {{.*alwaysinline.*inlinehint.*}}
+// CHECK-NOT: attributes #[[NOAI]] = {{.*alwaysinline.*}}
+
+// CHECK-CALL-LABEL: define void @_Z2g1v()
+// CHECK-CALL:       call void @_ZN2A1C1Ev.alwaysinline
+// CHECK-CALL:       call void @_ZN2A1D1Ev.alwaysinline
+// CHECK-CALL:       ret void
+
+// CHECK-CALL-LABEL: define void @_Z2g2v()
+// CHECK-CALL:       call void @_ZN2A2C1Ev.alwaysinline
+// CHECK-CALL:       call void @_ZN2A2D1Ev.alwaysinline
+// CHECK-CALL:       ret void
+
+// CHECK-CALL-LABEL: define void @_Z2g3v()
+// CHECK-CALL:       call void @_ZN2A3C1Ev.alwaysinline
+// CHECK-CALL:       call void @_ZN2A3D1Ev.alwaysinline
+// CHECK-CALL:       ret void

Modified: cfe/trunk/test/Frontend/optimization-remark-line-directive.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/optimization-remark-line-directive.c?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/Frontend/optimization-remark-line-directive.c (original)
+++ cfe/trunk/test/Frontend/optimization-remark-line-directive.c Fri Sep 11 15:29:07 2015
@@ -5,8 +5,9 @@
 // RUN: %clang_cc1 %s -Rpass=inline -gline-tables-only -dwarf-column-info -emit-llvm-only -verify
 
 int foo(int x, int y) __attribute__((always_inline));
+// expected-remark at +1 {{foo.alwaysinline inlined into foo}}
 int foo(int x, int y) { return x + y; }
 
-// expected-remark at +2 {{foo inlined into bar}} expected-note at +2 {{could not determine the original source location for /bad/path/to/original.c:1230:25}}
+// expected-remark at +2 {{foo.alwaysinline inlined into bar}} expected-note at +2 {{could not determine the original source location for /bad/path/to/original.c:1230:25}}
 #line 1230 "/bad/path/to/original.c"
 int bar(int j) { return foo(j, j - 2); }

Modified: cfe/trunk/test/Frontend/optimization-remark.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/optimization-remark.c?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/Frontend/optimization-remark.c (original)
+++ cfe/trunk/test/Frontend/optimization-remark.c Fri Sep 11 15:29:07 2015
@@ -32,6 +32,8 @@
 // CHECK-NOT: !llvm.dbg.cu = !{
 
 int foo(int x, int y) __attribute__((always_inline));
+// expected-remark at +2 {{foo.alwaysinline should always be inlined}}
+// expected-remark at +1 {{foo.alwaysinline inlined into foo}}
 int foo(int x, int y) { return x + y; }
 
 float foz(int x, int y) __attribute__((noinline));
@@ -45,7 +47,7 @@ int bar(int j) {
 // expected-remark at +5 {{foz will not be inlined into bar}}
 // expected-remark at +4 {{foz should never be inlined}}
 // expected-remark at +3 {{foz will not be inlined into bar}}
-// expected-remark at +2 {{foo should always be inlined}}
-// expected-remark at +1 {{foo inlined into bar}}
+// expected-remark at +2 {{foo.alwaysinline should always be inlined}}
+// expected-remark at +1 {{foo.alwaysinline inlined into bar}}
   return foo(j, j - 2) * foz(j - 2, j);
 }

Modified: cfe/trunk/test/Modules/cxx-irgen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-irgen.cpp?rev=247465&r1=247464&r2=247465&view=diff
==============================================================================
--- cfe/trunk/test/Modules/cxx-irgen.cpp (original)
+++ cfe/trunk/test/Modules/cxx-irgen.cpp Fri Sep 11 15:29:07 2015
@@ -26,14 +26,14 @@ namespace EmitInlineMethods {
   };
 }
 
-// CHECK-DAG: define available_externally hidden {{.*}}{{signext i32|i32}} @_ZN1SIiE1gEv({{.*}} #[[ALWAYS_INLINE:.*]] align
+// CHECK-DAG: define internal i32 @_ZN1SIiE1gEv.alwaysinline() #[[ALWAYS_INLINE:.*]] align
 int a = S<int>::g();
 
 int b = h();
 
 // CHECK-DAG: define linkonce_odr {{.*}}{{signext i32|i32}} @_Z3minIiET_S0_S0_(i32
 int c = min(1, 2);
-// CHECK: define available_externally {{.*}}{{signext i32|i32}} @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
+// CHECK-DAG: define internal {{.*}}{{signext i32|i32}} @_ZN1SIiE1fEv.alwaysinline() #[[ALWAYS_INLINE]] align
 
 namespace ImplicitSpecialMembers {
   // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1BC2ERKS0_(




More information about the cfe-commits mailing list