Hi aadg, rnk, rsmith, rjmccall,

Space on stack allocated for unused structures returned by functions was unused
even when it's lifetime didn't intersect with lifetime of any other objects that
could use the same space.

The test added also checks for named and auto objects.  It seems to make sense
to have this all in one place.

REPOSITORY
  rL LLVM

http://reviews.llvm.org/D9743

Files:
  lib/CodeGen/CGCall.cpp
  test/CodeGenCXX/stack-reuse.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3077,10 +3077,18 @@
   // If the call returns a temporary with struct return, create a temporary
   // alloca to hold the result, unless one is given to us.
   llvm::Value *SRetPtr = nullptr;
+  size_t UnusedReturnSize = 0;
   if (RetAI.isIndirect() || RetAI.isInAlloca()) {
     SRetPtr = ReturnValue.getValue();
-    if (!SRetPtr)
+    if (!SRetPtr) {
       SRetPtr = CreateMemTemp(RetTy);
+      if (HaveInsertPoint()) {
+        uint64_t size =
+            CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(RetTy));
+        if (EmitLifetimeStart(size, SRetPtr))
+          UnusedReturnSize = size;
+      }
+    }
     if (IRFunctionArgs.hasSRetArg()) {
       IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr;
     } else {
@@ -3412,6 +3420,10 @@
   // insertion point; this allows the rest of IRgen to discard
   // unreachable code.
   if (CS.doesNotReturn()) {
+    if (UnusedReturnSize)
+      EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize),
+                      SRetPtr);
+
     Builder.CreateUnreachable();
     Builder.ClearInsertionPoint();
 
@@ -3440,8 +3452,13 @@
   RValue Ret = [&] {
     switch (RetAI.getKind()) {
     case ABIArgInfo::InAlloca:
-    case ABIArgInfo::Indirect:
-      return convertTempToRValue(SRetPtr, RetTy, SourceLocation());
+    case ABIArgInfo::Indirect: {
+      RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
+      if (UnusedReturnSize)
+        EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize),
+                        SRetPtr);
+      return ret;
+    }
 
     case ABIArgInfo::Ignore:
       // If we are ignoring an argument that had a result, make sure to
Index: test/CodeGenCXX/stack-reuse.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/stack-reuse.cpp
@@ -0,0 +1,132 @@
+// RUN: %clang -target armv7l-unknown-linux-gnueabihf -O3 -S %s -o - -emit-llvm | FileCheck %s --check-prefix=LIFETIME
+// RUN: %clang -target armv7l-unknown-linux-gnueabihf -O3 -S %s -o - | FileCheck %s --check-prefix=ASM
+
+// Stack should be reused when possible, no need to allocate two separate slots
+// if they have disjoint lifetime.
+
+// Sizes of objects are related to previously existed threshold of 32.  In case
+// of S_large stack size is rounded to 40 bytes.
+
+// 32B
+struct S_small {
+  int a[8];
+};
+
+// 36B
+struct S_large {
+  int a[9];
+};
+
+extern S_small foo_small();
+extern S_large foo_large();
+extern void bar_small(S_small*);
+extern void bar_large(S_large*);
+
+// Prevent mangling of function names.
+extern "C" {
+
+void small_rvoed_unnamed_temporary_object() {
+// LIFETIME-LABEL: define void @small_rvoed_unnamed_temporary_object
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+
+// ASM-LABEL: small_rvoed_unnamed_temporary_object:
+// ASM: .pad #32
+
+  foo_small();
+  foo_small();
+}
+
+void large_rvoed_unnamed_temporary_object() {
+// LIFETIME-LABEL: define void @large_rvoed_unnamed_temporary_object
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+
+// ASM-LABEL: large_rvoed_unnamed_temporary_object:
+// ASM: .pad #40
+
+  foo_large();
+  foo_large();
+}
+
+void small_rvoed_named_temporary_object() {
+// LIFETIME-LABEL: define void @small_rvoed_named_temporary_object
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+
+// ASM-LABEL: small_rvoed_named_temporary_object:
+// ASM: .pad #32
+
+  {
+    S_small s = foo_small();
+  }
+  {
+    S_small s = foo_small();
+  }
+}
+
+void large_rvoed_named_temporary_object() {
+// LIFETIME-LABEL: define void @large_rvoed_named_temporary_object
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+
+// ASM-LABEL: large_rvoed_named_temporary_object:
+// ASM: .pad #40
+
+  {
+    S_large s = foo_large();
+  }
+  {
+    S_large s = foo_large();
+  }
+}
+
+void small_auto_object() {
+// LIFETIME-LABEL: define void @small_auto_object
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+
+// ASM-LABEL: small_auto_object:
+// ASM: .pad #32
+
+  {
+    S_small s;
+    bar_small(&s);
+  }
+  {
+    S_small s;
+    bar_small(&s);
+  }
+}
+
+void large_auto_object() {
+// LIFETIME-LABEL: define void @large_auto_object
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+// LIFETIME: call void @llvm.lifetime.start
+// LIFETIME: call void @llvm.lifetime.end
+
+// ASM-LABEL: large_auto_object:
+// ASM: .pad #40
+
+  {
+    S_large s;
+    bar_large(&s);
+  }
+  {
+    S_large s;
+    bar_large(&s);
+  }
+}
+
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to