]> granicus.if.org Git - clang/commitdiff
Track whether an AggValueSlot is potentially aliased, and do not
authorJohn McCall <rjmccall@apple.com>
Thu, 25 Aug 2011 23:04:34 +0000 (23:04 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 25 Aug 2011 23:04:34 +0000 (23:04 +0000)
emit call results into potentially aliased slots.  This allows us
to properly mark indirect return slots as noalias, at the cost
of requiring an extra memcpy when assigning an aggregate call
result into a l-value.  It also brings us into compliance with
the x86-64 ABI.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138599 91177308-0d34-0410-b5e6-96231b3b80d8

17 files changed:
lib/CodeGen/CGCall.cpp
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGStmt.cpp
lib/CodeGen/CGValue.h
lib/CodeGen/CodeGenFunction.h
test/CodeGen/arm-arguments.c
test/CodeGen/arm-vector-arguments.c
test/CodeGen/blocks.c
test/CodeGen/x86_32-arguments-darwin.c
test/CodeGen/x86_64-arguments.c
test/CodeGenCXX/temporaries.cpp
test/CodeGenCXX/x86_32-arguments.cpp

index dc3e702d6a38a54ba5a157c37adf8b14cfe0a986..846e1aa3934d26ffe42aefa37d6ea36efb6d6a8b 100644 (file)
@@ -907,6 +907,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
   // Name the struct return argument.
   if (CGM.ReturnTypeUsesSRet(FI)) {
     AI->setName("agg.result");
+    AI->addAttr(llvm::Attribute::NoAlias);
     ++AI;
   }
 
index 8e46fcd3ed5229d405a45e7fdd64df3db06bf9d1..8bdfbf1231eb6ad3c7cd497fe58bc2491a399e2a 100644 (file)
@@ -401,7 +401,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
   AggValueSlot AggSlot =
     AggValueSlot::forAddr(V, Qualifiers(),
                           AggValueSlot::IsDestructed,
-                          AggValueSlot::DoesNotNeedGCBarriers);
+                          AggValueSlot::DoesNotNeedGCBarriers,
+                          AggValueSlot::IsNotAliased);
 
   CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
   
@@ -441,7 +442,8 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
       AggValueSlot Slot =
         AggValueSlot::forAddr(Dest, LHS.getQuals(),
                               AggValueSlot::IsDestructed,
-                              AggValueSlot::DoesNotNeedGCBarriers);
+                              AggValueSlot::DoesNotNeedGCBarriers,
+                              AggValueSlot::IsNotAliased);
       
       CGF.EmitAggExpr(MemberInit->getInit(), Slot);
     }
@@ -1330,7 +1332,8 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
   AggValueSlot AggSlot =
     AggValueSlot::forAddr(ThisPtr, Qualifiers(),
                           AggValueSlot::IsDestructed,
-                          AggValueSlot::DoesNotNeedGCBarriers);
+                          AggValueSlot::DoesNotNeedGCBarriers,
+                          AggValueSlot::IsNotAliased);
 
   EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
 
index 609542c9c6e13458339150023230b0caa2508b9d..5fa99a513adcd653b0005c8a5a0545c15e5208d2 100644 (file)
@@ -1046,7 +1046,8 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
     // TODO: how can we delay here if D is captured by its initializer?
     EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
                                               AggValueSlot::IsDestructed,
-                                         AggValueSlot::DoesNotNeedGCBarriers));
+                                         AggValueSlot::DoesNotNeedGCBarriers,
+                                              AggValueSlot::IsNotAliased));
   }
 }
 
index f4bed7952700e444dbffb5c1286735fbed74eee5..e4c327b3ab62e01ea3b1fb84401e4059b083101b 100644 (file)
@@ -47,7 +47,8 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
     CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile());
   } else {
     CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
-                                          AggValueSlot::DoesNotNeedGCBarriers));
+                                          AggValueSlot::DoesNotNeedGCBarriers,
+                                                  AggValueSlot::IsNotAliased));
   }
 }
 
index da892c7715ed4f0724a719f3d8c698348ab579e9..1ed24ccd65fafd2254d3d31736722713907df915 100644 (file)
@@ -360,7 +360,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
         = AggValueSlot::IsDestructed_t(InitializedDecl != 0);
       AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(),
                                       isDestructed,
-                                      AggValueSlot::DoesNotNeedGCBarriers);
+                                      AggValueSlot::DoesNotNeedGCBarriers,
+                                      AggValueSlot::IsNotAliased);
     }
     
     if (InitializedDecl) {
index 4a151fcfb88ee7de6d4fc25826dd0f636f6045ee..c42c87b1ac810effffc074ac8a0a9e5ff7dbdf58 100644 (file)
@@ -35,11 +35,18 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
   AggValueSlot Dest;
   bool IgnoreResult;
 
+  /// We want to use 'dest' as the return slot except under two
+  /// conditions:
+  ///   - The destination slot requires garbage collection, so we
+  ///     need to use the GC API.
+  ///   - The destination slot is potentially aliased.
+  bool shouldUseDestForReturnSlot() const {
+    return !(Dest.requiresGCollection() || Dest.isPotentiallyAliased());
+  }
+
   ReturnValueSlot getReturnValueSlot() const {
-    // If the destination slot requires garbage collection, we can't
-    // use the real return value slot, because we have to use the GC
-    // API.
-    if (Dest.requiresGCollection()) return ReturnValueSlot();
+    if (!shouldUseDestForReturnSlot())
+      return ReturnValueSlot();
 
     return ReturnValueSlot(Dest.getAddr(), Dest.isVolatile());
   }
@@ -69,7 +76,7 @@ public:
   void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false);
   void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false);
 
-  void EmitGCMove(const Expr *E, RValue Src);
+  void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
 
   AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
     if (CGF.getLangOptions().getGCMode() && TypeRequiresGCollection(T))
@@ -179,23 +186,27 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
   return Record->hasObjectMember();
 }
 
-/// \brief Perform the final move to DestPtr if RequiresGCollection is set.
+/// \brief Perform the final move to DestPtr if for some reason
+/// getReturnValueSlot() didn't use it directly.
 ///
 /// The idea is that you do something like this:
 ///   RValue Result = EmitSomething(..., getReturnValueSlot());
-///   EmitGCMove(E, Result);
-/// If GC doesn't interfere, this will cause the result to be emitted
-/// directly into the return value slot.  If GC does interfere, a final
-/// move will be performed.
-void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) {
-  if (Dest.requiresGCollection()) {
-    CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType());
-    llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
-    llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
-    CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(),
-                                                    Src.getAggregateAddr(),
-                                                    SizeVal);
+///   EmitMoveFromReturnSlot(E, Result);
+///
+/// If nothing interferes, this will cause the result to be emitted
+/// directly into the return value slot.  Otherwise, a final move
+/// will be performed.
+void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) {
+  if (shouldUseDestForReturnSlot()) {
+    // Logically, Dest.getAddr() should equal Src.getAggregateAddr().
+    // The possibility of undef rvalues complicates that a lot,
+    // though, so we can't really assert.
+    return;
   }
+
+  // Otherwise, do a final copy, 
+  assert(Dest.getAddr() != Src.getAggregateAddr());
+  EmitFinalDestCopy(E, Src, /*Ignore*/ true);
 }
 
 /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
@@ -316,7 +327,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
     LValue LV = CGF.EmitLValue(E->getSubExpr());
     assert(LV.isPropertyRef());
     RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
-    EmitGCMove(E, RV);
+    EmitMoveFromReturnSlot(E, RV);
     break;
   }
 
@@ -381,12 +392,12 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
   }
 
   RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot());
-  EmitGCMove(E, RV);
+  EmitMoveFromReturnSlot(E, RV);
 }
 
 void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
   RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot());
-  EmitGCMove(E, RV);
+  EmitMoveFromReturnSlot(E, RV);
 }
 
 void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
@@ -600,6 +611,7 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
     CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV,
                                                AggValueSlot::IsDestructed,
                                       AggValueSlot::DoesNotNeedGCBarriers,
+                                               AggValueSlot::IsNotAliased,
                                                Dest.isZeroed()));
   } else if (LV.isSimple()) {
     CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
index 83a42fb9c51156dc886568bc81f0120e574aed37..179dc75b31daa224eab1ad1df5a9e078f217a2eb 100644 (file)
@@ -820,7 +820,8 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
                                     LoadObjCSelf(), Ivar, 0);
       EmitAggExpr(IvarInit->getInit(),
                   AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed,
-                                          AggValueSlot::DoesNotNeedGCBarriers));
+                                          AggValueSlot::DoesNotNeedGCBarriers,
+                                          AggValueSlot::IsNotAliased));
     }
     // constructor returns 'self'.
     CodeGenTypes &Types = CGM.getTypes();
index b7b127fc502f620f03058a30c16fc891841a3f01..461a173f53d146b3dbb401c2fcb51db9d6500fb1 100644 (file)
@@ -786,7 +786,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
   } else {
     EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(),
                                           AggValueSlot::IsDestructed,
-                                          AggValueSlot::DoesNotNeedGCBarriers));
+                                          AggValueSlot::DoesNotNeedGCBarriers,
+                                          AggValueSlot::IsNotAliased));
   }
 
   EmitBranchThroughCleanup(ReturnBlock);
index dda9693f42cd0750ddaf3f56b6de4195ebc0ffca..c448949d134d27c65d96d8cafb9eeb14e4aec5c5 100644 (file)
@@ -347,9 +347,14 @@ class AggValueSlot {
   /// be set.
   bool ZeroedFlag : 1;
 
+  /// AliasedFlag - This generally defaults to false, but can be true
+  /// if the memory is known not to be aliased.
+  bool AliasedFlag : 1;
+
 public:
-  enum IsZeroed_t { IsNotZeroed, IsZeroed };
+  enum IsAliased_t { IsNotAliased, IsAliased };
   enum IsDestructed_t { IsNotDestructed, IsDestructed };
+  enum IsZeroed_t { IsNotZeroed, IsZeroed };
   enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
 
   /// ignored - Returns an aggregate value slot indicating that the
@@ -358,7 +363,10 @@ public:
     AggValueSlot AV;
     AV.Addr = 0;
     AV.Quals = Qualifiers();
-    AV.LifetimeFlag = AV.RequiresGCollection = AV.ZeroedFlag = 0;
+    AV.LifetimeFlag = AV.RequiresGCollection = AV.ZeroedFlag = false;
+
+    // If there's ever an address here, it will be a temporary.
+    AV.AliasedFlag = false;
     return AV;
   }
 
@@ -375,6 +383,7 @@ public:
   static AggValueSlot forAddr(llvm::Value *addr, Qualifiers quals,
                               IsDestructed_t isDestructed,
                               NeedsGCBarriers_t needsGC,
+                              IsAliased_t isAliased = IsAliased,
                               IsZeroed_t isZeroed = IsNotZeroed) {
     AggValueSlot AV;
     AV.Addr = addr;
@@ -382,14 +391,16 @@ public:
     AV.LifetimeFlag = isDestructed;
     AV.RequiresGCollection = needsGC;
     AV.ZeroedFlag = isZeroed;
+    AV.AliasedFlag = isAliased;
     return AV;
   }
 
   static AggValueSlot forLValue(LValue LV, IsDestructed_t isDestructed,
                                 NeedsGCBarriers_t needsGC,
+                                IsAliased_t isAliased = IsAliased,
                                 IsZeroed_t isZeroed = IsNotZeroed) {
     return forAddr(LV.getAddress(), LV.getQuals(),
-                   isDestructed, needsGC, isZeroed);
+                   isDestructed, needsGC, isAliased, isZeroed);
   }
 
   IsDestructed_t isLifetimeExternallyManaged() const {
@@ -421,6 +432,10 @@ public:
     return Addr == 0;
   }
 
+  IsAliased_t isPotentiallyAliased() const {
+    return IsAliased_t(AliasedFlag);
+  }
+
   RValue asRValue() const {
     return RValue::getAggregate(getAddr(), isVolatile());
   }
index 2d47301ec5162c7c286da8d7102c75a05d030233..36dcffcd4c02e55ab075745088caf658f7f2a7a5 100644 (file)
@@ -1466,7 +1466,8 @@ public:
   AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") {
     return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(),
                                  AggValueSlot::IsNotDestructed,
-                                 AggValueSlot::DoesNotNeedGCBarriers);
+                                 AggValueSlot::DoesNotNeedGCBarriers,
+                                 AggValueSlot::IsNotAliased);
   }
 
   /// Emit a cast to void* in the appropriate address space.
index 081bc89dcda75eee4276d4a5b4d86d14d92a7836..3ae3b8ecd21fbdacd47c509dbdb192f9eda15647 100644 (file)
@@ -28,13 +28,13 @@ struct s4 { struct s4_0 { int f0; } f0; };
 struct s4 f4(void) {}
 
 // APCS-GNU: define void @f5(
-// APCS-GNU: struct.s5* sret
+// APCS-GNU: struct.s5* noalias sret
 // AAPCS: define arm_aapcscc i32 @f5()
 struct s5 { struct { } f0; int f1; };
 struct s5 f5(void) {}
 
 // APCS-GNU: define void @f6(
-// APCS-GNU: struct.s6* sret
+// APCS-GNU: struct.s6* noalias sret
 // AAPCS: define arm_aapcscc i32 @f6()
 struct s6 { int f0[1]; };
 struct s6 f6(void) {}
@@ -45,7 +45,7 @@ struct s7 { struct { int : 0; } f0; };
 struct s7 f7(void) {}
 
 // APCS-GNU: define void @f8(
-// APCS-GNU: struct.s8* sret
+// APCS-GNU: struct.s8* noalias sret
 // AAPCS: define arm_aapcscc void @f8()
 struct s8 { struct { int : 0; } f0[1]; };
 struct s8 f8(void) {}
@@ -61,7 +61,7 @@ struct s10 { int f0; int : 0; int : 0; };
 struct s10 f10(void) {}
 
 // APCS-GNU: define void @f11(
-// APCS-GNU: struct.s11* sret
+// APCS-GNU: struct.s11* noalias sret
 // AAPCS: define arm_aapcscc i32 @f11()
 struct s11 { int : 0; int f0; };
 struct s11 f11(void) {}
@@ -72,7 +72,7 @@ union u12 { char f0; short f1; int f2; };
 union u12 f12(void) {}
 
 // APCS-GNU: define void @f13(
-// APCS-GNU: struct.s13* sret
+// APCS-GNU: struct.s13* noalias sret
 
 // FIXME: This should return a float.
 // AAPCS-FIXME: darm_aapcscc efine float @f13()
@@ -80,7 +80,7 @@ struct s13 { float f0; };
 struct s13 f13(void) {}
 
 // APCS-GNU: define void @f14(
-// APCS-GNU: union.u14* sret
+// APCS-GNU: union.u14* noalias sret
 // AAPCS: define arm_aapcscc i32 @f14()
 union u14 { float f0; };
 union u14 f14(void) {}
@@ -104,13 +104,13 @@ struct s18 { short f0; char f1 : 4; };
 struct s18 f18(void) {}
 
 // APCS-GNU: define void @f19(
-// APCS-GNU: struct.s19* sret
+// APCS-GNU: struct.s19* noalias sret
 // AAPCS: define arm_aapcscc i32 @f19()
 struct s19 { int f0; struct s8 f1; };
 struct s19 f19(void) {}
 
 // APCS-GNU: define void @f20(
-// APCS-GNU: struct.s20* sret
+// APCS-GNU: struct.s20* noalias sret
 // AAPCS: define arm_aapcscc i32 @f20()
 struct s20 { struct s8 f1; int f0; };
 struct s20 f20(void) {}
@@ -128,10 +128,10 @@ struct s21 f21(void) {}
 // APCS-GNU: define i128 @f27()
 // AAPCS: define arm_aapcscc i16 @f22()
 // AAPCS: define arm_aapcscc i32 @f23()
-// AAPCS: define arm_aapcscc void @f24({{.*}} sret
-// AAPCS: define arm_aapcscc void @f25({{.*}} sret
-// AAPCS: define arm_aapcscc void @f26({{.*}} sret
-// AAPCS: define arm_aapcscc void @f27({{.*}} sret
+// AAPCS: define arm_aapcscc void @f24({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f25({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f26({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f27({{.*}} noalias sret
 _Complex char       f22(void) {}
 _Complex short      f23(void) {}
 _Complex int        f24(void) {}
@@ -149,7 +149,7 @@ struct s28 f28() {}
 struct s29 { _Complex short f0; };
 struct s29 f29() {}
 
-// APCS-GNU: define void @f30({{.*}} sret
-// AAPCS: define arm_aapcscc void @f30({{.*}} sret
+// APCS-GNU: define void @f30({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f30({{.*}} noalias sret
 struct s30 { _Complex int f0; };
 struct s30 f30() {}
index c5ac0a7ad1b7dc060c43fb35bee6df59f5d07887..6bfb2f48a7f16084347e8eed7f5213ae50b0ced8 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <arm_neon.h>
 
-// CHECK: define void @f0(%struct.int8x16x2_t* sret %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+// CHECK: define void @f0(%struct.int8x16x2_t* noalias sret %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
 int8x16x2_t f0(int8x16_t a0, int8x16_t a1) {
   return vzipq_s8(a0, a1);
 }
@@ -24,7 +24,7 @@ typedef float T_float32x16 __attribute__ ((__vector_size__ (64)));
 T_float32x2 f1_0(T_float32x2 a0) { return a0; }
 // CHECK: define <4 x float> @f1_1(<4 x float> %{{.*}})
 T_float32x4 f1_1(T_float32x4 a0) { return a0; }
-// CHECK: define void @f1_2(<8 x float>* sret %{{.*}}, <8 x float> %{{.*}})
+// CHECK: define void @f1_2(<8 x float>* noalias sret %{{.*}}, <8 x float> %{{.*}})
 T_float32x8 f1_2(T_float32x8 a0) { return a0; }
-// CHECK: define void @f1_3(<16 x float>* sret %{{.*}}, <16 x float> %{{.*}})
+// CHECK: define void @f1_3(<16 x float>* noalias sret %{{.*}}, <16 x float> %{{.*}})
 T_float32x16 f1_3(T_float32x16 a0) { return a0; }
index b7b6a2d505efffcbfa846fccc1ee375fffe3dbc0..bef44c369015915f3656fad60b4230150db989fd 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o %t -fblocks
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - -fblocks | FileCheck %s
 void (^f)(void) = ^{};
 
 // rdar://6768379
@@ -12,7 +12,7 @@ struct s0 {
   int a[64];
 };
 
-// RUN: grep 'internal void @__f2_block_invoke_0(.struct.s0\* sret .*, .*, .* byval .*)' %t
+// CHECK: define internal void @__f2_block_invoke_0(%struct.s0* noalias sret {{%.*}}, i8* {{%.*}}, %struct.s0* byval align 4 {{.*}})
 struct s0 f2(struct s0 a0) {
   return ^(struct s0 a1){ return a1; }(a0);
 }
index 731d4f613f26876c2e634ac57d2743aaa93a694f..7727c43f6e8db6d06683e2d205fba2b336483ada 100644 (file)
@@ -71,7 +71,7 @@ struct s10 {
 // Small vectors and 1 x {i64,double} are returned in registers
 
 // CHECK: i32 @f11()
-// CHECK: void @f12(<2 x i32>* sret %agg.result)
+// CHECK: void @f12(<2 x i32>* noalias sret %agg.result)
 // CHECK: i64 @f13()
 // CHECK: i64 @f14()
 // CHECK: <2 x i64> @f15()
@@ -93,11 +93,11 @@ T16 f16(void) { while (1) {} }
 // 128-bits).
 
 // CHECK: i32 @f17()
-// CHECK: void @f18(%{{.*}}* sret %agg.result)
-// CHECK: void @f19(%{{.*}}* sret %agg.result)
-// CHECK: void @f20(%{{.*}}* sret %agg.result)
-// CHECK: void @f21(%{{.*}}* sret %agg.result)
-// CHECK: void @f22(%{{.*}}* sret %agg.result)
+// CHECK: void @f18(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f19(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f20(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f21(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f22(%{{.*}}* noalias sret %agg.result)
 struct { T11 a; } f17(void) { while (1) {} }
 struct { T12 a; } f18(void) { while (1) {} }
 struct { T13 a; } f19(void) { while (1) {} }
@@ -116,11 +116,11 @@ struct { struct {} a; struct { float a[1]; } b; } f25(void) { while (1) {} }
 
 // Small structures are handled recursively
 // CHECK: i32 @f26()
-// CHECK: void @f27(%struct.s27* sret %agg.result)
+// CHECK: void @f27(%struct.s27* noalias sret %agg.result)
 struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) { while (1) {} }
 struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { while (1) {} }
 
-// CHECK: void @f28(%struct.s28* sret %agg.result)
+// CHECK: void @f28(%struct.s28* noalias sret %agg.result)
 struct s28 { int a; int b[]; } f28(void) { while (1) {} }
 
 // CHECK: define i16 @f29()
@@ -150,7 +150,7 @@ struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while (
 // CHECK: define float @f37()
 struct s37 { float c[1][1]; } f37(void) { while (1) {} }
 
-// CHECK: define void @f38(%struct.s38* sret %agg.result)
+// CHECK: define void @f38(%struct.s38* noalias sret %agg.result)
 struct s38 { char a[3]; short b; } f38(void) { while (1) {} }
 
 // CHECK: define void @f39(%struct.s39* byval align 16 %x)
index 221c7d38a73d99e8aa00fe0fd6bf710c3fdd0e31..8571ac9655528052ff7d5912157ea6c54ca85a5a 100644 (file)
@@ -42,7 +42,7 @@ void f7(e7 a0) {
 
 // Test merging/passing of upper eightbyte with X87 class.
 //
-// CHECK: define void @f8_1(%union.u8* sret %agg.result)
+// CHECK: define void @f8_1(%union.u8* noalias sret %agg.result)
 // CHECK: define void @f8_2(%union.u8* byval align 16 %a0)
 union u8 {
   long double a;
@@ -58,7 +58,7 @@ struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
 struct s10 { int a; int b; int : 0; };
 void f10(struct s10 a0) {}
 
-// CHECK: define void @f11(%union.anon* sret %agg.result)
+// CHECK: define void @f11(%union.anon* noalias sret %agg.result)
 union { long double a; float b; } f11() { while (1) {} }
 
 // CHECK: define i32 @f12_0()
@@ -69,7 +69,7 @@ void f12_1(struct s12 a0) {}
 
 // Check that sret parameter is accounted for when checking available integer
 // registers.
-// CHECK: define void @f13(%struct.s13_0* sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval align 8 %e, i32 %f)
+// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval align 8 %e, i32 %f)
 
 struct s13_0 { long long f0[3]; };
 struct s13_1 { long long f0[2]; };
index 8aeca653da55e9f608f6e94362cf0e2b2a8048de..98e5ae3e6ee7d80518794377a5be42c37211d60b 100644 (file)
@@ -395,7 +395,7 @@ namespace Elision {
     // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]])
   }
 
-  // CHECK: define void @_ZN7Elision5test2Ev([[A]]* sret
+  // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret
   A test2() {
     // CHECK:      call void @_ZN7Elision3fooEv()
     // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]])
@@ -403,7 +403,7 @@ namespace Elision {
     return (foo(), A());
   }
 
-  // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* sret
+  // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret
   A test3(int v, A x) {
     if (v < 5)
     // CHECK:      call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]])
@@ -444,7 +444,7 @@ namespace Elision {
   }
 
   // rdar://problem/8433352
-  // CHECK: define void @_ZN7Elision5test5Ev([[A]]* sret
+  // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret
   struct B { A a; B(); };
   A test5() {
     // CHECK:      [[AT0:%.*]] = alloca [[A]], align 8
index 4d4339381dbe814fe5437ee6f606fb63cd60a664..1cbeb71b2285db90a0f2a2b1732b2fd7a7c90819 100644 (file)
@@ -6,7 +6,7 @@ struct S {
   short s;
 };
 
-// CHECK: define void @_Z1fv(%struct.S* sret %
+// CHECK: define void @_Z1fv(%struct.S* noalias sret %
 S f() { return S(); }
 // CHECK: define void @_Z1f1S(%struct.S*)
 void f(S) { }
@@ -18,7 +18,7 @@ public:
   double c;
 };
 
-// CHECK: define void @_Z1gv(%class.C* sret %
+// CHECK: define void @_Z1gv(%class.C* noalias sret %
 C g() { return C(); }
 
 // CHECK: define void @_Z1f1C(%class.C*) 
@@ -103,13 +103,13 @@ struct s7_1 { double x; };
 struct s7 : s7_0, s7_1 { };
 s7 f7() { return s7(); }
 
-// CHECK: define void @_Z2f8v(%struct.s8* sret %agg.result)
+// CHECK: define void @_Z2f8v(%struct.s8* noalias sret %agg.result)
 struct s8_0 { };
 struct s8_1 { double x; };
 struct s8 { s8_0 a; s8_1 b; };
 s8 f8() { return s8(); }
 
-// CHECK: define void @_Z2f9v(%struct.s9* sret %agg.result)
+// CHECK: define void @_Z2f9v(%struct.s9* noalias sret %agg.result)
 struct s9_0 { unsigned : 0; };
 struct s9_1 { double x; };
 struct s9 { s9_0 a; s9_1 b; };