ahatanak created this revision.

This fixes a bug in EmitObjCForCollectionStmt which is causing clang to 
generate malformed IR.

When the following code (which I think is legal, at least when it is not 
compiled with ARC) is compiled:

$ cat test1.m

  @interface Obj
  @end
  void bar(void);
  void foo(Obj *o) {
    Obj *i;
    for (i in o) {
    thing:
      bar();
    }
    goto thing;
  }

the compilation terminates with the messages "Instruction does not dominate all 
uses!".

This patch fixes the bug by using temporary local variables instead of PHI 
instructions and moving instructions to locations that dominate their uses.

The example I showed still fails to compile (with an assertion) when compiled 
with -fobjc-arc, but I think that is a separate bug.

rdar://problem/31670637


https://reviews.llvm.org/D32187

Files:
  lib/CodeGen/CGObjC.cpp
  test/CodeGenObjC/arc-foreach.m

Index: test/CodeGenObjC/arc-foreach.m
===================================================================
--- test/CodeGenObjC/arc-foreach.m
+++ test/CodeGenObjC/arc-foreach.m
@@ -26,6 +26,9 @@
 // CHECK-LP64:      [[ARRAY:%.*]] = alloca [[ARRAY_T:%.*]]*,
 // CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
 // CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
+// CHECK-LP64-NEXT: [[INDEX:%.*]] = alloca [[INDEX_T:.*]],
+// CHECK-LP64-NEXT: [[COUNT:%.*]] = alloca [[COUNT_T:.*]],
+// CHECK-LP64-NEXT: [[MUTATION:%.*]] = alloca [[MUTATION_T:.*]],
 // CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8
 // CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
 
@@ -50,13 +53,29 @@
 // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
 // CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
 
+// CHECK-LP64-NEXT: [[MUTATIONPTRPTR:%.*]] = getelementptr inbounds [[STATE_T]], [[STATE_T]]* [[STATE]]
+
 // Check for a nonzero result.
 // CHECK-LP64-NEXT: [[T0:%.*]] = icmp eq i64 [[SIZE]], 0
 // CHECK-LP64-NEXT: br i1 [[T0]]
 
+// Initialize count, index, and mutation.
+// CHECK-LP64: [[MUTATIONPTR:%.*]] = load [[MUTATION_T]]*, [[MUTATION_T]]** [[MUTATIONPTRPTR]]
+// CHECK-LP64: [[INITIALMUTATIONVAL:%.*]] = load [[MUTATION_T]], [[MUTATION_T]]* [[MUTATIONPTR]]
+// CHECK-LP64: store [[MUTATION_T]] [[INITIALMUTATIONVAL]], [[MUTATION_T]]* [[MUTATION]]
+// CHECK-LP64: store [[INDEX_T]] 0, [[INDEX_T]]* [[INDEX]]
+// CHECK-LP64: store [[COUNT_T]] [[SIZE]], [[COUNT_T]]* [[COUNT]]
+
+// Check for mutation.
+// CHECK-LP64: [[MUTATIONPTR:%.*]] = load [[MUTATION_T]]*, [[MUTATION_T]]** [[MUTATIONPTRPTR]]
+// CHECK-LP64: [[MUTATIONSTATE:%.*]] = load [[MUTATION_T]], [[MUTATION_T]]* [[MUTATIONPTR]]
+// CHECK-LP64: [[INITIALMUTATIONVAL:%.*]] = load [[MUTATION_T]], [[MUTATION_T]]* [[MUTATION]]
+// CHECK-LP64: icmp eq [[MUTATION_T]] [[MUTATIONSTATE]], [[INITIALMUTATIONVAL]]
+
 // CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[STATE_T]], [[STATE_T]]* [[STATE]], i32 0, i32 1
 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8**, i8*** [[T0]]
-// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8*, i8** [[T1]], i64
+// CHECK-LP64-NEXT: [[INDEXVAL:%.*]] = load [[INDEX_T]], [[INDEX_T]]* [[INDEX]]
+// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8*, i8** [[T1]], i64 [[INDEXVAL]]
 // CHECK-LP64-NEXT: [[T3:%.*]] = load i8*, i8** [[T2]]
 // CHECK-LP64-NEXT: store i8* [[T3]], i8** [[X]]
 
@@ -69,9 +88,18 @@
 // CHECK-LP64: call void @use_block(
 // CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null)
 
+// Increment index.
+// CHECK-LP64: [[INDEXVAL:%.*]] = load [[INDEX_T]], [[INDEX_T]]* [[INDEX]]
+// CHECK-LP64: [[T0:%.*]] = add [[INDEX_T]] [[INDEXVAL]], 1
+// CHECK-LP64: store [[INDEX_T]] [[T0]], [[INDEX_T]]* [[INDEX]]
+// CHECK-LP64: [[COUNTVAL:%.*]] = load [[COUNT_T]], [[COUNT_T]]* [[COUNT]]
+// CHECK-LP64: icmp ult [[COUNT_T]] [[T0]], [[COUNTVAL]]
+
 // CHECK-LP64:      [[T0:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
 // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
 // CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
+// CHECK-LP64: store [[INDEX_T]] 0, [[INDEX_T]]* [[INDEX]]
+// CHECK-LP64: store [[COUNT_T]] [[SIZE]], [[COUNT_T]]* [[COUNT]]
 
 // Release the array.
 // CHECK-LP64:      [[T0:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
@@ -99,12 +127,16 @@
 // CHECK-LP64:      alloca [[ARRAY_T:%.*]]*,
 // CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
 // CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
+// CHECK-LP64-NEXT: [[INDEX:%.*]] = alloca [[INDEX_T:.*]],
+// CHECK-LP64-NEXT: [[COUNT:%.*]] = alloca [[COUNT_T:.*]],
+// CHECK-LP64-NEXT: [[MUTATION:%.*]] = alloca [[MUTATION_T:.*]],
 // CHECK-LP64-NEXT: alloca [16 x i8*], align 8
 // CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
 
 // CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[STATE_T]], [[STATE_T]]* [[STATE]], i32 0, i32 1
 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8**, i8*** [[T0]]
-// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8*, i8** [[T1]], i64
+// CHECK-LP64-NEXT: [[INDEXVAL:%.*]] = load [[INDEX_T]], [[INDEX_T]]* [[INDEX]]
+// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8*, i8** [[T1]], i64 [[INDEXVAL]]
 // CHECK-LP64-NEXT: [[T3:%.*]] = load i8*, i8** [[T2]]
 // CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T3]])
 
Index: lib/CodeGen/CGObjC.cpp
===================================================================
--- lib/CodeGen/CGObjC.cpp
+++ lib/CodeGen/CGObjC.cpp
@@ -1495,6 +1495,13 @@
   // Fast enumeration state.
   QualType StateTy = CGM.getObjCFastEnumerationStateType();
   Address StatePtr = CreateMemTemp(StateTy, "state.ptr");
+  Address ForAllIdxAddr =
+      CreateMemTemp(getContext().UnsignedLongTy, "for.all.index.addr");
+  Address ForAllCntAddr =
+      CreateMemTemp(getContext().UnsignedLongTy, "for.all.count.addr");
+  Address InititialMutationsAddr = CreateMemTemp(
+      getContext().UnsignedLongTy, "forcooll.initial-mutations.addr");
+
   EmitNullInitialization(StatePtr, StateTy);
 
   // Number of elements in the items array.
@@ -1565,6 +1572,9 @@
 
   llvm::Value *zero = llvm::Constant::getNullValue(UnsignedLongLTy);
 
+  Address StateMutationsPtrPtr = Builder.CreateStructGEP(
+      StatePtr, 2, 2 * getPointerSize(), "mutationsptr.ptr");
+
   // If the limit pointer was zero to begin with, the collection is
   // empty; skip all this. Set the branch weight assuming this has the same
   // probability of exiting the loop as any other loop exit.
@@ -1580,28 +1590,23 @@
   // Save the initial mutations value.  This is the value at an
   // address that was written into the state object by
   // countByEnumeratingWithState:objects:count:.
-  Address StateMutationsPtrPtr = Builder.CreateStructGEP(
-      StatePtr, 2, 2 * getPointerSize(), "mutationsptr.ptr");
   llvm::Value *StateMutationsPtr
     = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
 
   llvm::Value *initialMutations =
     Builder.CreateAlignedLoad(StateMutationsPtr, getPointerAlign(),
                               "forcoll.initial-mutations");
+  Builder.CreateStore(initialMutations, InititialMutationsAddr);
+
+  // Initialize index and buffer size.
+  Builder.CreateStore(zero, ForAllIdxAddr);
+  Builder.CreateStore(initialBufferLimit, ForAllCntAddr);
 
   // Start looping.  This is the point we return to whenever we have a
   // fresh, non-empty batch of objects.
   llvm::BasicBlock *LoopBodyBB = createBasicBlock("forcoll.loopbody");
   EmitBlock(LoopBodyBB);
 
-  // The current index into the buffer.
-  llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.index");
-  index->addIncoming(zero, LoopInitBB);
-
-  // The current buffer size.
-  llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count");
-  count->addIncoming(initialBufferLimit, LoopInitBB);
-
   incrementProfileCounter(&S);
 
   // Check whether the mutations value has changed from where it was
@@ -1614,6 +1619,8 @@
 
   llvm::BasicBlock *WasMutatedBB = createBasicBlock("forcoll.mutated");
   llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcoll.notmutated");
+  initialMutations =
+      Builder.CreateLoad(InititialMutationsAddr, "forcoll.initial-mutations");
 
   Builder.CreateCondBr(Builder.CreateICmpEQ(currentMutations, initialMutations),
                        WasNotMutatedBB, WasMutatedBB);
@@ -1668,6 +1675,7 @@
     Builder.CreateLoad(StateItemsPtr, "stateitems");
 
   // Fetch the value at the current index from the buffer.
+  auto *index = Builder.CreateLoad(ForAllIdxAddr, "for.all.index");
   llvm::Value *CurrentItemPtr =
     Builder.CreateGEP(EnumStateItems, index, "currentitem.ptr");
   llvm::Value *CurrentItem =
@@ -1709,20 +1717,20 @@
   llvm::BasicBlock *FetchMoreBB = createBasicBlock("forcoll.refetch");
 
   // First we check in the local buffer.
+  index = Builder.CreateLoad(ForAllIdxAddr, "for.all.index");
   llvm::Value *indexPlusOne
     = Builder.CreateAdd(index, llvm::ConstantInt::get(UnsignedLongLTy, 1));
+  Builder.CreateStore(indexPlusOne, ForAllIdxAddr);
 
   // If we haven't overrun the buffer yet, we can continue.
   // Set the branch weights based on the simplifying assumption that this is
   // like a while-loop, i.e., ignoring that the false branch fetches more
   // elements and then returns to the loop.
+  auto *count = Builder.CreateLoad(ForAllCntAddr, "for.all.count");
   Builder.CreateCondBr(
       Builder.CreateICmpULT(indexPlusOne, count), LoopBodyBB, FetchMoreBB,
       createProfileWeights(getProfileCount(S.getBody()), EntryCount));
 
-  index->addIncoming(indexPlusOne, AfterBody.getBlock());
-  count->addIncoming(count, AfterBody.getBlock());
-
   // Otherwise, we have to fetch more elements.
   EmitBlock(FetchMoreBB);
 
@@ -1736,8 +1744,8 @@
   llvm::Value *refetchCount = CountRV.getScalarVal();
 
   // (note that the message send might split FetchMoreBB)
-  index->addIncoming(zero, Builder.GetInsertBlock());
-  count->addIncoming(refetchCount, Builder.GetInsertBlock());
+  Builder.CreateStore(zero, ForAllIdxAddr);
+  Builder.CreateStore(refetchCount, ForAllCntAddr);
 
   Builder.CreateCondBr(Builder.CreateICmpEQ(refetchCount, zero),
                        EmptyBB, LoopBodyBB);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to