<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Dec 14, 2015 at 5:44 PM, Mehdi Amini via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: mehdi_amini<br>
Date: Mon Dec 14 19:44:07 2015<br>
New Revision: 255600<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=255600&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=255600&view=rev</a><br>
Log:<br>
Instcombine: destructor loads of structs that do not contains padding<br>
<br>
For non padded structs, we can just proceed and deaggregate them.<br>
We don't want ot do this when there is padding in the struct as to not<br>
lose information about this padding (the subsequents passes would then<br>
try hard to preserve the padding, which is undesirable).<br></blockquote><div><br></div><div>Would it be enough to do something like insert a store of `undef` to the padding?</div><div><br></div><div>-- Sean Silva</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Also update extractvalue.ll and cast.ll so that they use structs with padding.<br>
<br>
Remove the FIXME in the extractvalue of laod case as the non padded case is<br>
handled when processing the load, and we don't want to do it on the padded<br>
case.<br>
<br>
Patch by: Amaury SECHET <<a href="mailto:deadalnix@gmail.com">deadalnix@gmail.com</a>><br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D14483" rel="noreferrer" target="_blank">http://reviews.llvm.org/D14483</a><br>
<br>
From: Mehdi Amini <<a href="mailto:mehdi.amini@apple.com">mehdi.amini@apple.com</a>><br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/IR/DataLayout.h<br>
    llvm/trunk/lib/IR/DataLayout.cpp<br>
    llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp<br>
    llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp<br>
    llvm/trunk/test/Transforms/InstCombine/cast.ll<br>
    llvm/trunk/test/Transforms/InstCombine/extractvalue.ll<br>
    llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll<br>
<br>
Modified: llvm/trunk/include/llvm/IR/DataLayout.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/DataLayout.h?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/DataLayout.h?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/IR/DataLayout.h (original)<br>
+++ llvm/trunk/include/llvm/IR/DataLayout.h Mon Dec 14 19:44:07 2015<br>
@@ -475,7 +475,8 @@ inline LLVMTargetDataRef wrap(const Data<br>
 class StructLayout {<br>
   uint64_t StructSize;<br>
   unsigned StructAlignment;<br>
-  unsigned NumElements;<br>
+  bool IsPadded : 1;<br>
+  unsigned NumElements : 31;<br>
   uint64_t MemberOffsets[1]; // variable sized array!<br>
 public:<br>
   uint64_t getSizeInBytes() const { return StructSize; }<br>
@@ -484,6 +485,10 @@ public:<br>
<br>
   unsigned getAlignment() const { return StructAlignment; }<br>
<br>
+  /// Returns whether the struct has padding or not between its fields.<br>
+  /// NB: Padding in nested element is not taken into account.<br>
+  bool hasPadding() const { return IsPadded; }<br>
+<br>
   /// \brief Given a valid byte offset into the structure, returns the structure<br>
   /// index that contains it.<br>
   unsigned getElementContainingOffset(uint64_t Offset) const;<br>
<br>
Modified: llvm/trunk/lib/IR/DataLayout.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/DataLayout.cpp?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/DataLayout.cpp?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/IR/DataLayout.cpp (original)<br>
+++ llvm/trunk/lib/IR/DataLayout.cpp Mon Dec 14 19:44:07 2015<br>
@@ -41,6 +41,7 @@ StructLayout::StructLayout(StructType *S<br>
   assert(!ST->isOpaque() && "Cannot get layout of opaque structs");<br>
   StructAlignment = 0;<br>
   StructSize = 0;<br>
+  IsPadded = false;<br>
   NumElements = ST->getNumElements();<br>
<br>
   // Loop over each of the elements, placing them in memory.<br>
@@ -49,8 +50,10 @@ StructLayout::StructLayout(StructType *S<br>
     unsigned TyAlign = ST->isPacked() ? 1 : DL.getABITypeAlignment(Ty);<br>
<br>
     // Add padding if necessary to align the data element properly.<br>
-    if ((StructSize & (TyAlign-1)) != 0)<br>
+    if ((StructSize & (TyAlign-1)) != 0) {<br>
+      IsPadded = true;<br>
       StructSize = RoundUpToAlignment(StructSize, TyAlign);<br>
+    }<br>
<br>
     // Keep track of maximum alignment constraint.<br>
     StructAlignment = std::max(TyAlign, StructAlignment);<br>
@@ -64,8 +67,10 @@ StructLayout::StructLayout(StructType *S<br>
<br>
   // Add padding to the end of the struct so that it could be put in an array<br>
   // and all array elements would be aligned correctly.<br>
-  if ((StructSize & (StructAlignment-1)) != 0)<br>
+  if ((StructSize & (StructAlignment-1)) != 0) {<br>
+    IsPadded = true;<br>
     StructSize = RoundUpToAlignment(StructSize, StructAlignment);<br>
+  }<br>
 }<br>
<br>
<br>
<br>
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp Mon Dec 14 19:44:07 2015<br>
@@ -524,12 +524,40 @@ static Instruction *unpackLoadToAggregat<br>
<br>
   if (auto *ST = dyn_cast<StructType>(T)) {<br>
     // If the struct only have one element, we unpack.<br>
-    if (ST->getNumElements() == 1) {<br>
+    unsigned Count = ST->getNumElements();<br>
+    if (Count == 1) {<br>
       LoadInst *NewLoad = combineLoadToNewType(IC, LI, ST->getTypeAtIndex(0U),<br>
                                                ".unpack");<br>
       return IC.ReplaceInstUsesWith(LI, IC.Builder->CreateInsertValue(<br>
         UndefValue::get(T), NewLoad, 0, LI.getName()));<br>
     }<br>
+<br>
+    // We don't want to break loads with padding here as we'd loose<br>
+    // the knowledge that padding exists for the rest of the pipeline.<br>
+    const DataLayout &DL = IC.getDataLayout();<br>
+    auto *SL = DL.getStructLayout(ST);<br>
+    if (SL->hasPadding())<br>
+      return nullptr;<br>
+<br>
+    auto Name = LI.getName();<br>
+    auto LoadName = LI.getName() + ".unpack";<br>
+    auto EltName = Name + ".elt";<br>
+    auto *Addr = LI.getPointerOperand();<br>
+    Value *V = UndefValue::get(T);<br>
+    auto *IdxType = Type::getInt32Ty(ST->getContext());<br>
+    auto *Zero = ConstantInt::get(IdxType, 0);<br>
+    for (unsigned i = 0; i < Count; i++) {<br>
+      Value *Indices[2] = {<br>
+        Zero,<br>
+        ConstantInt::get(IdxType, i),<br>
+      };<br>
+      auto *Ptr = IC.Builder->CreateInBoundsGEP(ST, Addr, makeArrayRef(Indices), EltName);<br>
+      auto *L = IC.Builder->CreateLoad(ST->getTypeAtIndex(i), Ptr, LoadName);<br>
+      V = IC.Builder->CreateInsertValue(V, L, i);<br>
+    }<br>
+<br>
+    V->setName(Name);<br>
+    return IC.ReplaceInstUsesWith(LI, V);<br>
   }<br>
<br>
   if (auto *AT = dyn_cast<ArrayType>(T)) {<br>
@@ -902,11 +930,36 @@ static bool unpackStoreToAggregate(InstC<br>
<br>
   if (auto *ST = dyn_cast<StructType>(T)) {<br>
     // If the struct only have one element, we unpack.<br>
-    if (ST->getNumElements() == 1) {<br>
+    unsigned Count = ST->getNumElements();<br>
+    if (Count == 1) {<br>
       V = IC.Builder->CreateExtractValue(V, 0);<br>
       combineStoreToNewValue(IC, SI, V);<br>
       return true;<br>
     }<br>
+<br>
+    // We don't want to break loads with padding here as we'd loose<br>
+    // the knowledge that padding exists for the rest of the pipeline.<br>
+    const DataLayout &DL = IC.getDataLayout();<br>
+    auto *SL = DL.getStructLayout(ST);<br>
+    if (SL->hasPadding())<br>
+      return false;<br>
+<br>
+    auto EltName = V->getName() + ".elt";<br>
+    auto *Addr = SI.getPointerOperand();<br>
+    auto AddrName = Addr->getName() + ".repack";<br>
+    auto *IdxType = Type::getInt32Ty(ST->getContext());<br>
+    auto *Zero = ConstantInt::get(IdxType, 0);<br>
+    for (unsigned i = 0; i < Count; i++) {<br>
+      Value *Indices[2] = {<br>
+        Zero,<br>
+        ConstantInt::get(IdxType, i),<br>
+      };<br>
+      auto *Ptr = IC.Builder->CreateInBoundsGEP(ST, Addr, makeArrayRef(Indices), AddrName);<br>
+      auto *Val = IC.Builder->CreateExtractValue(V, i, EltName);<br>
+      IC.Builder->CreateStore(Val, Ptr);<br>
+    }<br>
+<br>
+    return true;<br>
   }<br>
<br>
   if (auto *AT = dyn_cast<ArrayType>(T)) {<br>
<br>
Modified: llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp Mon Dec 14 19:44:07 2015<br>
@@ -2311,9 +2311,10 @@ Instruction *InstCombiner::visitExtractV<br>
   }<br>
   if (LoadInst *L = dyn_cast<LoadInst>(Agg))<br>
     // If the (non-volatile) load only has one use, we can rewrite this to a<br>
-    // load from a GEP. This reduces the size of the load.<br>
-    // FIXME: If a load is used only by extractvalue instructions then this<br>
-    //        could be done regardless of having multiple uses.<br>
+    // load from a GEP. This reduces the size of the load. If a load is used<br>
+    // only by extractvalue instructions then this either must have been<br>
+    // optimized before, or it is a struct with padding, in which case we<br>
+    // don't want to do the transformation as it loses padding knowledge.<br>
     if (L->isSimple() && L->hasOneUse()) {<br>
       // extractvalue has integer indices, getelementptr has Value*s. Convert.<br>
       SmallVector<Value*, 4> Indices;<br>
<br>
Modified: llvm/trunk/test/Transforms/InstCombine/cast.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast.ll?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast.ll?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/InstCombine/cast.ll (original)<br>
+++ llvm/trunk/test/Transforms/InstCombine/cast.ll Mon Dec 14 19:44:07 2015<br>
@@ -722,7 +722,7 @@ define i1 @test67(i1 %a, i32 %b) {<br>
 ; CHECK: ret i1 false<br>
 }<br>
<br>
-%s = type { i32, i32, i32 }<br>
+%s = type { i32, i32, i16 }<br>
<br>
 define %s @test68(%s *%p, i64 %i) {<br>
 ; CHECK-LABEL: @test68(<br>
<br>
Modified: llvm/trunk/test/Transforms/InstCombine/extractvalue.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/extractvalue.ll?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/extractvalue.ll?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/InstCombine/extractvalue.ll (original)<br>
+++ llvm/trunk/test/Transforms/InstCombine/extractvalue.ll Mon Dec 14 19:44:07 2015<br>
@@ -48,16 +48,16 @@ define i32 @foo(i32 %a, i32 %b) {<br>
 ; CHECK: call {{.*}}(i32 [[LOAD]])<br>
 ; CHECK-NOT: extractvalue<br>
 ; CHECK: ret i32 [[LOAD]]<br>
-define i32 @extract2gep({i32, i32}* %pair, i32* %P) {<br>
+define i32 @extract2gep({i16, i32}* %pair, i32* %P) {<br>
         ; The load + extractvalue should be converted<br>
         ; to an inbounds gep + smaller load.<br>
         ; The new load should be in the same spot as the old load.<br>
-        %L = load {i32, i32}, {i32, i32}* %pair<br>
+        %L = load {i16, i32}, {i16, i32}* %pair<br>
         store i32 0, i32* %P<br>
         br label %loop<br>
<br>
 loop:<br>
-        %E = extractvalue {i32, i32} %L, 1<br>
+        %E = extractvalue {i16, i32} %L, 1<br>
         %C = call i32 @baz(i32 %E)<br>
         store i32 %C, i32* %P<br>
         %cond = icmp eq i32 %C, 0<br>
@@ -67,17 +67,17 @@ end:<br>
         ret i32 %E<br>
 }<br>
<br>
-; CHECK-LABEL: define i32 @doubleextract2gep(<br>
+; CHECK-LABEL: define i16 @doubleextract2gep(<br>
 ; CHECK-NEXT: [[GEP:%[a-z0-9]+]] = getelementptr inbounds {{.*}}, {{.*}}* %arg, i64 0, i32 1, i32 1<br>
-; CHECK-NEXT: [[LOAD:%[A-Za-z0-9]+]] = load i32, i32* [[GEP]]<br>
-; CHECK-NEXT: ret i32 [[LOAD]]<br>
-define i32 @doubleextract2gep({i32, {i32, i32}}* %arg) {<br>
+; CHECK-NEXT: [[LOAD:%[A-Za-z0-9]+]] = load i16, i16* [[GEP]]<br>
+; CHECK-NEXT: ret i16 [[LOAD]]<br>
+define i16 @doubleextract2gep({i16, {i32, i16}}* %arg) {<br>
         ; The load + extractvalues should be converted<br>
         ; to a 3-index inbounds gep + smaller load.<br>
-        %L = load {i32, {i32, i32}}, {i32, {i32, i32}}* %arg<br>
-        %E1 = extractvalue {i32, {i32, i32}} %L, 1<br>
-        %E2 = extractvalue {i32, i32} %E1, 1<br>
-        ret i32 %E2<br>
+        %L = load {i16, {i32, i16}}, {i16, {i32, i16}}* %arg<br>
+        %E1 = extractvalue {i16, {i32, i16}} %L, 1<br>
+        %E2 = extractvalue {i32, i16} %E1, 1<br>
+        ret i16 %E2<br>
 }<br>
<br>
 ; CHECK: define i32 @nogep-multiuse<br>
<br>
Modified: llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll?rev=255600&r1=255599&r2=255600&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll?rev=255600&r1=255599&r2=255600&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll (original)<br>
+++ llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll Mon Dec 14 19:44:07 2015<br>
@@ -5,110 +5,134 @@ target triple = "x86_64-unknown-linux-gn<br>
<br>
 %A__vtbl = type { i8*, i32 (%A*)* }<br>
 %A = type { %A__vtbl* }<br>
+%B = type { i8*, i64 }<br>
<br>
 @A__vtblZ = constant %A__vtbl { i8* null, i32 (%A*)* @A.foo }<br>
<br>
 declare i32 @A.foo(%A* nocapture %this)<br>
<br>
-declare i8* @allocmemory(i64)<br>
-<br>
-define void @storeA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to %A*<br>
+define void @storeA(%A* %a.ptr) {<br>
 ; CHECK-LABEL: storeA<br>
-; CHECK: store %A__vtbl* @A__vtblZ<br>
-  store %A { %A__vtbl* @A__vtblZ }, %A* %1, align 8<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds %A, %A* %a.ptr, i64 0, i32 0<br>
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: ret void<br>
+  store %A { %A__vtbl* @A__vtblZ }, %A* %a.ptr, align 8<br>
+  ret void<br>
+}<br>
+<br>
+define void @storeB(%B* %b.ptr) {<br>
+; CHECK-LABEL: storeB<br>
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 0<br>
+; CHECK-NEXT: store i8* null, i8** [[GEP1]], align 8<br>
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 1<br>
+; CHECK-NEXT: store i64 42, i64* [[GEP2]], align 8<br>
+; CHECK-NEXT: ret void<br>
+  store %B { i8* null, i64 42 }, %B* %b.ptr, align 8<br>
   ret void<br>
 }<br>
<br>
-define void @storeStructOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to { %A }*<br>
+define void @storeStructOfA({ %A }* %sa.ptr) {<br>
 ; CHECK-LABEL: storeStructOfA<br>
-; CHECK: store %A__vtbl* @A__vtblZ<br>
-  store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %1, align 8<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { %A }, { %A }* %sa.ptr, i64 0, i32 0, i32 0<br>
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: ret void<br>
+  store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %sa.ptr, align 8<br>
   ret void<br>
 }<br>
<br>
-define void @storeArrayOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to [1 x %A]*<br>
+define void @storeArrayOfA([1 x %A]* %aa.ptr) {<br>
 ; CHECK-LABEL: storeArrayOfA<br>
-; CHECK: store %A__vtbl* @A__vtblZ<br>
-  store [1 x %A] [%A { %A__vtbl* @A__vtblZ }], [1 x %A]* %1, align 8<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds [1 x %A], [1 x %A]* %aa.ptr, i64 0, i64 0, i32 0<br>
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: ret void<br>
+  store [1 x %A] [%A { %A__vtbl* @A__vtblZ }], [1 x %A]* %aa.ptr, align 8<br>
   ret void<br>
 }<br>
<br>
-define void @storeStructOfArrayOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to { [1 x %A] }*<br>
+define void @storeStructOfArrayOfA({ [1 x %A] }* %saa.ptr) {<br>
 ; CHECK-LABEL: storeStructOfArrayOfA<br>
-; CHECK: store %A__vtbl* @A__vtblZ<br>
-  store { [1 x %A] } { [1 x %A] [%A { %A__vtbl* @A__vtblZ }] }, { [1 x %A] }* %1, align 8<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { [1 x %A] }, { [1 x %A] }* %saa.ptr, i64 0, i32 0, i64 0, i32 0<br>
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: ret void<br>
+  store { [1 x %A] } { [1 x %A] [%A { %A__vtbl* @A__vtblZ }] }, { [1 x %A] }* %saa.ptr, align 8<br>
   ret void<br>
 }<br>
<br>
-define %A @loadA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to %A*<br>
+define %A @loadA(%A* %a.ptr) {<br>
 ; CHECK-LABEL: loadA<br>
-; CHECK: load %A__vtbl*,<br>
-; CHECK: insertvalue %A undef, %A__vtbl* {{.*}}, 0<br>
-  %2 = load %A, %A* %1, align 8<br>
-  ret %A %2<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds %A, %A* %a.ptr, i64 0, i32 0<br>
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: [[IV:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0<br>
+; CHECK-NEXT: ret %A [[IV]]<br>
+  %1 = load %A, %A* %a.ptr, align 8<br>
+  ret %A %1<br>
+}<br>
+<br>
+define %B @loadB(%B* %b.ptr) {<br>
+; CHECK-LABEL: loadB<br>
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 0<br>
+; CHECK-NEXT: [[LOAD1:%[a-z0-9\.]+]] = load i8*, i8** [[GEP1]], align 8<br>
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %B undef, i8* [[LOAD1]], 0<br>
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 1<br>
+; CHECK-NEXT: [[LOAD2:%[a-z0-9\.]+]] = load i64, i64* [[GEP2]], align 8<br>
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue %B [[IV1]], i64 [[LOAD2]], 1<br>
+; CHECK-NEXT: ret %B [[IV2]]<br>
+  %1 = load %B, %B* %b.ptr, align 8<br>
+  ret %B %1<br>
 }<br>
<br>
-define { %A } @loadStructOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to { %A }*<br>
+define { %A } @loadStructOfA({ %A }* %sa.ptr) {<br>
 ; CHECK-LABEL: loadStructOfA<br>
-; CHECK: load %A__vtbl*,<br>
-; CHECK: insertvalue %A undef, %A__vtbl* {{.*}}, 0<br>
-; CHECK: insertvalue { %A } undef, %A {{.*}}, 0<br>
-  %2 = load { %A }, { %A }* %1, align 8<br>
-  ret { %A } %2<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { %A }, { %A }* %sa.ptr, i64 0, i32 0, i32 0<br>
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0<br>
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue { %A } undef, %A [[IV1]], 0<br>
+; CHECK-NEXT: ret { %A } [[IV2]]<br>
+  %1 = load { %A }, { %A }* %sa.ptr, align 8<br>
+  ret { %A } %1<br>
 }<br>
<br>
-define [1 x %A] @loadArrayOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to [1 x %A]*<br>
+define [1 x %A] @loadArrayOfA([1 x %A]* %aa.ptr) {<br>
 ; CHECK-LABEL: loadArrayOfA<br>
-; CHECK: load %A__vtbl*,<br>
-; CHECK: insertvalue %A undef, %A__vtbl* {{.*}}, 0<br>
-; CHECK: insertvalue [1 x %A] undef, %A {{.*}}, 0<br>
-  %2 = load [1 x %A], [1 x %A]* %1, align 8<br>
-  ret [1 x %A] %2<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds [1 x %A], [1 x %A]* %aa.ptr, i64 0, i64 0, i32 0<br>
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0<br>
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue [1 x %A] undef, %A [[IV1]], 0<br>
+; CHECK-NEXT: ret [1 x %A] [[IV2]]<br>
+  %1 = load [1 x %A], [1 x %A]* %aa.ptr, align 8<br>
+  ret [1 x %A] %1<br>
 }<br>
<br>
-define { [1 x %A] } @loadStructOfArrayOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to { [1 x %A] }*<br>
+define { [1 x %A] } @loadStructOfArrayOfA({ [1 x %A] }* %saa.ptr) {<br>
 ; CHECK-LABEL: loadStructOfArrayOfA<br>
-; CHECK: load %A__vtbl*,<br>
-; CHECK: insertvalue %A undef, %A__vtbl* {{.*}}, 0<br>
-; CHECK: insertvalue [1 x %A] undef, %A {{.*}}, 0<br>
-; CHECK: insertvalue { [1 x %A] } undef, [1 x %A] {{.*}}, 0<br>
-  %2 = load { [1 x %A] }, { [1 x %A] }* %1, align 8<br>
-  ret { [1 x %A] } %2<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { [1 x %A] }, { [1 x %A] }* %saa.ptr, i64 0, i32 0, i64 0, i32 0<br>
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0<br>
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue [1 x %A] undef, %A [[IV1]], 0<br>
+; CHECK-NEXT: [[IV3:%[a-z0-9\.]+]] = insertvalue { [1 x %A] } undef, [1 x %A] [[IV2]], 0<br>
+; CHECK-NEXT: ret { [1 x %A] } [[IV3]]<br>
+  %1 = load { [1 x %A] }, { [1 x %A] }* %saa.ptr, align 8<br>
+  ret { [1 x %A] } %1<br>
 }<br>
<br>
-define { %A } @structOfA() {<br>
-body:<br>
-  %0 = tail call i8* @allocmemory(i64 32)<br>
-  %1 = bitcast i8* %0 to { %A }*<br>
+define { %A } @structOfA({ %A }* %sa.ptr) {<br>
 ; CHECK-LABEL: structOfA<br>
-; CHECK: store %A__vtbl* @A__vtblZ<br>
-  store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %1, align 8<br>
-  %2 = load { %A }, { %A }* %1, align 8<br>
-; CHECK-NOT: load<br>
-; CHECK: ret { %A } { %A { %A__vtbl* @A__vtblZ } }<br>
-  ret { %A } %2<br>
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { %A }, { %A }* %sa.ptr, i64 0, i32 0, i32 0<br>
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8<br>
+; CHECK-NEXT: ret { %A } { %A { %A__vtbl* @A__vtblZ } }<br>
+  store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %sa.ptr, align 8<br>
+  %1 = load { %A }, { %A }* %sa.ptr, align 8<br>
+  ret { %A } %1<br>
+}<br>
+<br>
+define %B @structB(%B* %b.ptr) {<br>
+; CHECK-LABEL: structB<br>
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 0<br>
+; CHECK-NEXT: store i8* null, i8** [[GEP1]], align 8<br>
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 1<br>
+; CHECK-NEXT: store i64 42, i64* [[GEP2]], align 8<br>
+; CHECK-NEXT: ret %B { i8* null, i64 42 }<br>
+  store %B { i8* null, i64 42 }, %B* %b.ptr, align 8<br>
+  %1 = load %B, %B* %b.ptr, align 8<br>
+  ret %B %1<br>
 }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>