Model PHI nodes without demoting them
authorJohannes Doerfert <doerfert@cs.uni-saarland.de>
Fri, 6 Feb 2015 20:13:15 +0000 (20:13 +0000)
committerJohannes Doerfert <doerfert@cs.uni-saarland.de>
Fri, 6 Feb 2015 20:13:15 +0000 (20:13 +0000)
  This allows us to model PHI nodes in the polyhedral description
  without demoting them. The modeling however will result in the
  same accesses as the demotion would have introduced.

Differential Revision: http://reviews.llvm.org/D7415

llvm-svn: 228433

13 files changed:
polly/include/polly/ScopDetection.h
polly/include/polly/TempScopInfo.h
polly/lib/Analysis/ScopDetection.cpp
polly/lib/Analysis/ScopInfo.cpp
polly/lib/Analysis/TempScopInfo.cpp
polly/lib/Transform/CodePreparation.cpp
polly/lib/Transform/IndependentBlocks.cpp
polly/test/ScopInfo/phi_condition_modeling_1.ll [new file with mode: 0644]
polly/test/ScopInfo/phi_condition_modeling_2.ll [new file with mode: 0644]
polly/test/ScopInfo/phi_conditional_simple_1.ll [new file with mode: 0644]
polly/test/ScopInfo/phi_loop_carried_float.ll [new file with mode: 0644]
polly/test/ScopInfo/phi_scalar_simple_1.ll [new file with mode: 0644]
polly/test/ScopInfo/phi_scalar_simple_2.ll [new file with mode: 0644]

index 9753e38f2e724afe6eb86e8a673970b34a0f4fa9..2588f5cf749f2680b7a818d7c56bb5de1d2523a8 100644 (file)
@@ -108,6 +108,7 @@ typedef std::vector<PairInstSCEV> AFs;
 typedef std::map<const SCEVUnknown *, AFs> BaseToAFs;
 typedef std::map<const SCEVUnknown *, const SCEV *> BaseToElSize;
 
+extern bool PollyModelPHINodes;
 extern bool PollyTrackFailures;
 extern bool PollyDelinearize;
 extern bool PollyUseRuntimeAliasChecks;
index 44791c0553a8fd7f19a6a1b2ad5be3ccc44b28a6..c58b521be52adc18f31a1962bcab2b9e9ba98ad0 100644 (file)
@@ -275,6 +275,13 @@ class TempScopInfo : public FunctionPass {
   ///             Access is required.
   bool buildScalarDependences(Instruction *Inst, Region *R);
 
+  /// @brief Create IRAccesses for the given PHI node in the given region.
+  ///
+  /// @param PHI       The PHI node to be handled
+  /// @param R         The SCoP region
+  /// @param Functions The access functions of the current BB
+  void buildPHIAccesses(PHINode *PHI, Region &R, AccFuncSetType &Functions);
+
   void buildAccessFunctions(Region &RefRegion, BasicBlock &BB);
 
 public:
index 7eb20a930a597b10106d9e9809568ed0df9f7eea..4bb2b15cb41308b682df1f1eaa6ce44586addeaa 100644 (file)
@@ -149,6 +149,13 @@ static cl::opt<bool>
                 cl::Hidden, cl::init(false), cl::ZeroOrMore,
                 cl::cat(PollyCategory));
 
+static cl::opt<bool, true> XPollyModelPHINodes(
+    "polly-model-phi-nodes",
+    cl::desc("Allow PHI nodes in the input [Unsafe with code-generation!]."),
+    cl::location(PollyModelPHINodes), cl::Hidden, cl::ZeroOrMore,
+    cl::init(false), cl::cat(PollyCategory));
+
+bool polly::PollyModelPHINodes = false;
 bool polly::PollyTrackFailures = false;
 bool polly::PollyDelinearize = false;
 StringRef polly::PollySkipFnAttr = "polly.skip.fn";
@@ -596,7 +603,7 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
 bool ScopDetection::isValidInstruction(Instruction &Inst,
                                        DetectionContext &Context) const {
   if (PHINode *PN = dyn_cast<PHINode>(&Inst))
-    if (!canSynthesize(PN, LI, SE, &Context.CurRegion)) {
+    if (!PollyModelPHINodes && !canSynthesize(PN, LI, SE, &Context.CurRegion)) {
       return invalid<ReportPhiNodeRefInRegion>(Context, /*Assert=*/true, &Inst);
     }
 
index d205e9052ebfb8a373d01c7388b2ea794f4ae7cf..f33b3e07f63f859cd49e5fa50740bbd3546bf5df 100644 (file)
@@ -570,7 +570,8 @@ void MemoryAccess::print(raw_ostream &OS) const {
     OS.indent(12) << "MayWriteAccess :=\t";
     break;
   }
-  OS << "[Reduction Type: " << getReductionType() << "]\n";
+  OS << "[Reduction Type: " << getReductionType() << "] ";
+  OS << "[Scalar: " << isScalar() << "]\n";
   OS.indent(16) << getOriginalAccessRelationStr() << ";\n";
 }
 
index 507654987247c69f070650310755f9d20c499a97..14b0faaa43cb02a800a3dd2d71769da902963817 100644 (file)
@@ -98,6 +98,48 @@ void TempScop::printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
   }
 }
 
+void TempScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
+                                    AccFuncSetType &Functions) {
+  if (canSynthesize(PHI, LI, SE, &R))
+    return;
+
+  // PHI nodes are modeled as if they had been demoted prior to the SCoP
+  // detection. Hence, the PHI is a load of a new memory location in which the
+  // incoming value was written at the end of the incoming basic block.
+  for (unsigned u = 0; u < PHI->getNumIncomingValues(); u++) {
+    Value *Op = PHI->getIncomingValue(u);
+    BasicBlock *OpBB = PHI->getIncomingBlock(u);
+
+    if (!R.contains(OpBB))
+      continue;
+
+    Instruction *OpI = dyn_cast<Instruction>(Op);
+    if (OpI) {
+      BasicBlock *OpIBB = OpI->getParent();
+      // As we pretend there is a use (or more precise a write) of OpI in OpBB
+      // we have to insert a scalar dependence from the definition of OpI to
+      // OpBB if the definition is not in OpBB.
+      if (OpIBB != OpBB) {
+        IRAccess ScalarRead(IRAccess::READ, OpI, ZeroOffset, 1, true);
+        AccFuncMap[OpBB].push_back(std::make_pair(ScalarRead, PHI));
+        IRAccess ScalarWrite(IRAccess::MUST_WRITE, OpI, ZeroOffset, 1, true);
+        AccFuncMap[OpIBB].push_back(std::make_pair(ScalarWrite, OpI));
+      }
+    }
+
+    // If the operand is a constant, global or argument we need an access
+    // instruction and just choose the PHI.
+    if (!OpI)
+      OpI = PHI;
+
+    IRAccess ScalarAccess(IRAccess::MUST_WRITE, PHI, ZeroOffset, 1, true);
+    AccFuncMap[OpBB].push_back(std::make_pair(ScalarAccess, OpI));
+  }
+
+  IRAccess ScalarAccess(IRAccess::READ, PHI, ZeroOffset, 1, true);
+  Functions.push_back(std::make_pair(ScalarAccess, PHI));
+}
+
 bool TempScopInfo::buildScalarDependences(Instruction *Inst, Region *R) {
   // No need to translate these scalar dependences into polyhedral form, because
   // synthesizable scalars can be generated by the code generator.
@@ -127,6 +169,10 @@ bool TempScopInfo::buildScalarDependences(Instruction *Inst, Region *R) {
     if (canSynthesize(UI, LI, SE, R))
       continue;
 
+    // Skip PHI nodes as they handle their operands on their own.
+    if (isa<PHINode>(UI))
+      continue;
+
     // Now U is used in another statement.
     AnyCrossStmtUse = true;
 
@@ -134,8 +180,6 @@ bool TempScopInfo::buildScalarDependences(Instruction *Inst, Region *R) {
     if (!R->contains(UseParent))
       continue;
 
-    assert(!isa<PHINode>(UI) && "Non synthesizable PHINode found in a SCoP!");
-
     // Use the def instruction as base address of the IRAccess, so that it will
     // become the name of the scalar access in the polyhedral form.
     IRAccess ScalarAccess(IRAccess::READ, Inst, ZeroOffset, 1, true);
@@ -197,6 +241,9 @@ void TempScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB) {
     if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
       Functions.push_back(std::make_pair(buildIRAccess(Inst, L, &R), Inst));
 
+    if (PHINode *PHI = dyn_cast<PHINode>(Inst))
+      buildPHIAccesses(PHI, R, Functions);
+
     if (!isa<StoreInst>(Inst) && buildScalarDependences(Inst, &R)) {
       // If the Instruction is used outside the statement, we need to build the
       // write access.
index 5847c69596861580e8a79f06152285fb384e0f0f..5aba77e7662159bd89f55fe9ec22d144c7d90cbf 100644 (file)
@@ -27,6 +27,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "polly/LinkAllPasses.h"
+#include "polly/ScopDetection.h"
 #include "polly/CodeGen/BlockGenerators.h"
 #include "polly/Support/ScopHelper.h"
 #include "llvm/Analysis/DominanceFrontier.h"
@@ -201,6 +202,9 @@ void CodePreparation::getAnalysisUsage(AnalysisUsage &AU) const {
 }
 
 bool CodePreparation::runOnFunction(Function &F) {
+  if (PollyModelPHINodes)
+    return false;
+
   LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
   SE = &getAnalysis<ScalarEvolution>();
 
index 72f9661bcf4b70c407c333f123dda11361e168dc..0bebe7cdb65f74a29c84b0b68ddecc6cdcd3208b 100644 (file)
@@ -256,7 +256,8 @@ bool IndependentBlocks::createIndependentBlocks(BasicBlock *BB,
   Instruction *InsertPos = BB->getFirstNonPHIOrDbg();
 
   for (Instruction *Inst : WorkList)
-    moveOperandTree(Inst, R, ReplacedMap, InsertPos);
+    if (!isa<PHINode>(Inst))
+      moveOperandTree(Inst, R, ReplacedMap, InsertPos);
 
   // The BB was changed if we replaced any operand.
   return !ReplacedMap.empty();
diff --git a/polly/test/ScopInfo/phi_condition_modeling_1.ll b/polly/test/ScopInfo/phi_condition_modeling_1.ll
new file mode 100644 (file)
index 0000000..63300e5
--- /dev/null
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-model-phi-nodes < %s | FileCheck %s
+;
+;    void f(int *A, int c, int N) {
+;      int tmp;
+;      for (int i = 0; i < N; i++) {
+;        if (i > c)
+;          tmp = 3;
+;        else
+;          tmp = 5;
+;        A[i] = tmp;
+;      }
+;    }
+;
+; CHECK:    Statements {
+; CHECK:      Stmt_bb6
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb6[i0] -> MemRef_tmp_0[] };
+; CHECK:      Stmt_bb7
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb7[i0] -> MemRef_tmp_0[] };
+; CHECK:      Stmt_bb8
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_A[i0] };
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp3, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %tmp5, label %bb6, label %bb7
+
+bb6:                                              ; preds = %bb4
+  br label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %tmp.0 = phi i32 [ 3, %bb6 ], [ 5, %bb7 ]
+  %tmp9 = getelementptr inbounds i32* %A, i64 %indvars.iv
+  store i32 %tmp.0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb11:                                             ; preds = %bb2
+  ret void
+}
diff --git a/polly/test/ScopInfo/phi_condition_modeling_2.ll b/polly/test/ScopInfo/phi_condition_modeling_2.ll
new file mode 100644 (file)
index 0000000..50d24b8
--- /dev/null
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -analyze -polly-scops -disable-polly-intra-scop-scalar-to-array -polly-model-phi-nodes < %s | FileCheck %s
+;
+;    void f(int *A, int c, int N) {
+;      int tmp;
+;      for (int i = 0; i < N; i++) {
+;        if (i > c)
+;          tmp = 3;
+;        else
+;          tmp = 5;
+;        A[i] = tmp;
+;      }
+;    }
+;
+; CHECK:    Statements {
+; CHECK:      Stmt_bb6
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb6[i0] -> MemRef_tmp_0[] };
+; CHECK:      Stmt_bb7
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb7[i0] -> MemRef_tmp_0[] };
+; CHECK:      Stmt_bb8
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0[] };
+; CHECK:      Stmt_bb8b
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8b[i0] -> MemRef_tmp_0[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N, c] -> { Stmt_bb8b[i0] -> MemRef_A[i0] };
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp3, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %tmp5, label %bb6, label %bb7
+
+bb6:                                              ; preds = %bb4
+  br label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %tmp.0 = phi i32 [ 3, %bb6 ], [ 5, %bb7 ]
+  br label %bb8b
+
+bb8b:
+  %tmp9 = getelementptr inbounds i32* %A, i64 %indvars.iv
+  store i32 %tmp.0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb11:                                             ; preds = %bb2
+  ret void
+}
diff --git a/polly/test/ScopInfo/phi_conditional_simple_1.ll b/polly/test/ScopInfo/phi_conditional_simple_1.ll
new file mode 100644 (file)
index 0000000..e980de4
--- /dev/null
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-model-phi-nodes < %s | FileCheck %s
+;
+;    void jd(int *A, int c) {
+;      for (int i = 0; i < 1024; i++) {
+;        if (c)
+;          A[i] = 1;
+;        else
+;          A[i] = 2;
+;      }
+;    }
+;
+; CHECK:    Statements {
+; CHECK:      Stmt_if_else
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [c] -> { Stmt_if_else[i0] -> MemRef_phi[] };
+; CHECK:      Stmt_if_then
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [c] -> { Stmt_if_then[i0] -> MemRef_phi[] };
+; CHECK:      Stmt_if_end
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [c] -> { Stmt_if_end[i0] -> MemRef_phi[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [c] -> { Stmt_if_end[i0] -> MemRef_A[i0] };
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %for.body
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  %phi = phi i32 [ 1, %if.then], [ 2, %if.else ]
+  %arrayidx = getelementptr inbounds i32* %A, i64 %indvars.iv
+  store i32 %phi, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/polly/test/ScopInfo/phi_loop_carried_float.ll b/polly/test/ScopInfo/phi_loop_carried_float.ll
new file mode 100644 (file)
index 0000000..3d9294c
--- /dev/null
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-scops -polly-model-phi-nodes -disable-polly-intra-scop-scalar-to-array -analyze < %s | FileCheck %s
+;
+;    float f(float *A, int N) {
+;      float tmp = 0;
+;      for (int i = 0; i < N; i++)
+;        tmp += A[i];
+;    }
+;
+; CHECK:      Statements {
+; CHECK:        Stmt_bb1
+; CHECK:              ReadAccess := [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb1[i0] -> MemRef_tmp_0[] };
+; CHECK:              MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb1[i0] -> MemRef_tmp_0[] };
+; CHECK:        Stmt_bb4
+; CHECK:              MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] };
+; CHECK:              ReadAccess := [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] };
+; CHECK:              ReadAccess := [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[i0] -> MemRef_A[i0] };
+; CHECK:              MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[i0] -> MemRef_tmp7[] };
+; CHECK:      }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %tmp.0 = phi float [ 0.000000e+00, %bb ], [ %tmp7, %bb4 ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb8
+
+bb3:                                              ; preds = %bb1
+  br label %bb4
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = getelementptr inbounds float* %A, i64 %indvars.iv
+  %tmp6 = load float* %tmp5, align 4
+  %tmp7 = fadd float %tmp.0, %tmp6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/polly/test/ScopInfo/phi_scalar_simple_1.ll b/polly/test/ScopInfo/phi_scalar_simple_1.ll
new file mode 100644 (file)
index 0000000..3ac67e0
--- /dev/null
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-scops -polly-model-phi-nodes -disable-polly-intra-scop-scalar-to-array -analyze < %s | FileCheck %s
+;
+;    int jd(int *restrict A, int x, int N) {
+;      for (int i = 1; i < N; i++)
+;        for (int j = 3; j < N; j++)
+;          x += A[i];
+;      return x;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+; CHECK: Stmt_for_cond
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc4 ], [ 1, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1.lcssa, %for.inc4 ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+; CHECK: Stmt_for_body
+; CHECK:       ReadAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_body[i0] -> MemRef_x_addr_0[] };
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_body[i0] -> MemRef_x_addr_1[] };
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+; CHECK: Stmt_for_cond1
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1_lcssa[] };
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %add, %for.inc ]
+  %j.0 = phi i32 [ 3, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+; CHECK: Stmt_for_inc
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:           [N] -> { Stmt_for_inc[i0, i1] -> MemRef_A[1 + i0] };
+  %arrayidx = getelementptr inbounds i32* %A, i64 %indvars.iv
+  %tmp1 = load i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp1
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+; CHECK: Stmt_for_end
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_end[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_end[i0] -> MemRef_x_addr_1_lcssa[] };
+  %x.addr.1.lcssa = phi i32 [ %x.addr.1, %for.cond1 ]
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+; CHECK: Stmt_for_inc4
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc4[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc4[i0] -> MemRef_x_addr_0[] };
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
diff --git a/polly/test/ScopInfo/phi_scalar_simple_2.ll b/polly/test/ScopInfo/phi_scalar_simple_2.ll
new file mode 100644 (file)
index 0000000..d42f2a8
--- /dev/null
@@ -0,0 +1,114 @@
+; RUN: opt %loadPolly -polly-scops -polly-model-phi-nodes -disable-polly-intra-scop-scalar-to-array -analyze < %s | FileCheck %s
+;
+;    int jd(int *restrict A, int x, int N, int c) {
+;      for (int i = 0; i < N; i++)
+;        for (int j = 0; j < N; j++)
+;          if (i < c)
+;            x += A[i];
+;      return x;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N, i32 %c) {
+entry:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+; CHECK: Stmt_for_cond
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0_s2a[0] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_A[i0] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc5 ], [ 0, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1, %for.inc5 ]
+  %arrayidx2 = getelementptr inbounds i32* %A, i64 %indvars.iv
+  store i32 %x.addr.0, i32* %arrayidx2
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+; CHECK: Stmt_for_body
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body[i0] -> MemRef_x_addr_0[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body[i0] -> MemRef_x_addr_1[] };
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+; CHECK: Stmt_for_cond1
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %x.addr.2, %for.inc ]
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+; CHECK: Stmt_for_body3
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body3[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body3[i0, i1] -> MemRef_x_addr_2[] };
+  %cmp4 = icmp slt i64 %indvars.iv, %tmp1
+  br i1 %cmp4, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+; CHECK: Stmt_if_then
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_A[i0] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_2[] };
+  %arrayidx = getelementptr inbounds i32* %A, i64 %indvars.iv
+  %tmp2 = load i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp2
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body3
+; CHECK: Stmt_if_end
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_end[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_end[i0, i1] -> MemRef_x_addr_2[] };
+  %x.addr.2 = phi i32 [ %add, %if.then ], [ %x.addr.1, %for.body3 ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+; CHECK: Stmt_for_inc
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+; CHECK: Stmt_for_inc5
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc5[i0] -> MemRef_x_addr_1[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc5[i0] -> MemRef_x_addr_0[] };
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
+