Remove AffineSCEVIterator

We do not use it anymore. It was replaced by SCEVVisitors like the
SCEVValidator.

llvm-svn: 144229
This commit is contained in:
Tobias Grosser 2011-11-09 22:35:00 +00:00
parent f317e3ac83
commit 6e9f25a5d5
12 changed files with 4 additions and 611 deletions

View File

@ -1,292 +0,0 @@
//===-- AffineSCEVIterator.h - Iterate the SCEV in an affine way -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The iterator can be used to iterate over the affine component of the SCEV
// expression.
//
//===----------------------------------------------------------------------===//
#ifndef AFFINE_SCEV_ITERATOR_H
#define AFFINE_SCEV_ITERATOR_H
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include <map>
#include "llvm/ADT/SmallVector.h"
using namespace llvm;
namespace polly {
/// @brief The itertor transform the scalar expressions to the form of sum of
/// (constant * variable)s, and return the variable/constant pairs one by one
/// on the fly.
///
/// For example, we can write SCEV:
/// {{%x,+,sizeof(i32)}<%bb2.preheader>,+,(4 * sizeof(i32))}<%bb1>
/// in affine form:
/// (4 * sizeof(i32)) * %indvar + sizeof(i32) * %0 + 1 * %x + 0 * 1
/// so we can get the follow pair from the iterator:
/// {%indvar, (4 * sizeof(i32))}, {%0, sizeof(i32)}, {%x, 1} and {1, 0}
/// where %indvar is the induction variable of loop %bb1 and %0 is the induction
/// variable of loop %bb2.preheader.
///
/// In the returned pair,
/// The "first" field is the variable part, the "second" field constant part.
/// And the translation part of the expression will always return last.
///
class AffineSCEVIterator : public std::iterator<std::forward_iterator_tag,
std::pair<const SCEV*, const SCEV*>, ptrdiff_t>,
SCEVVisitor<AffineSCEVIterator,
std::pair<const SCEV*, const SCEV*> >
{
typedef std::iterator<std::forward_iterator_tag,
std::pair<const SCEV*, const SCEV*>, ptrdiff_t> super;
friend struct llvm::SCEVVisitor<AffineSCEVIterator,
std::pair<const SCEV*, const SCEV*> >;
ScalarEvolution *SE;
public:
typedef super::value_type value_type;
typedef super::pointer ptr_type;
typedef AffineSCEVIterator Self;
private:
typedef SCEVNAryExpr::op_iterator scev_op_it;
// The stack help us remember the SCEVs that not visit yet.
SmallVector<const SCEV*, 8> visitStack;
// The current value of this iterator.
value_type val;
const SCEVConstant* getSCEVOne(const SCEV* S) const {
return cast<SCEVConstant>(SE->getConstant(S->getType(), 1));
}
//===-------------------------------------------------------------------===//
/// Functions for SCEVVisitor.
///
/// These function compute the constant part and variable part of the SCEV,
/// and return them in a std::pair, where the first field is the variable,
/// and the second field is the constant.
///
value_type visitConstant(const SCEVConstant *S) {
return std::make_pair(getSCEVOne(S), S);
}
value_type visitUnknown(const SCEVUnknown* S) {
Type *AllocTy;
Constant *FieldNo;
// We treat these as constant.
if (S->isSizeOf (AllocTy) ||
S->isAlignOf (AllocTy) ||
S->isOffsetOf(AllocTy, FieldNo))
return std::make_pair(getSCEVOne(S), S);
return std::make_pair(S, getSCEVOne(S));
}
value_type visitMulExpr(const SCEVMulExpr* S) {
SmallVector<const SCEV*, 4> Coeffs, Variables;
// Do not worry about the Constant * Variable * (Variable + Variable)
// MulExpr, we will never get a affine expression from it, so we just
// leave it there.
for (scev_op_it I = S->op_begin(), E = S->op_end(); I != E; ++I) {
// Get the constant part and the variable part of each operand.
value_type res = visit(*I);
Coeffs.push_back(res.second);
Variables.push_back(res.first);
}
// Get the constant part and variable part of this MulExpr by
// multiply them together.
const SCEV *Coeff = SE->getMulExpr(Coeffs);
// There maybe "sizeof" and others.
// TODO: Assert the allowed coeff type.
// assert(Coeff && "Expect Coeff to be a const!");
const SCEV *Var = SE->getMulExpr(Variables);
return std::make_pair(Var, Coeff);
}
value_type visitCastExpr(const SCEVCastExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
value_type visitTruncateExpr(const SCEVTruncateExpr *S) {
return visitCastExpr(S);
}
value_type visitZeroExtendExpr(const SCEVZeroExtendExpr *S) {
return visitCastExpr(S);
}
value_type visitSignExtendExpr(const SCEVSignExtendExpr *S) {
return visitCastExpr(S);
}
value_type visitAddExpr(const SCEVAddExpr *S) {
// AddExpr will handled out in visit Next;
return std::make_pair(S, getSCEVOne(S));
}
value_type visitAddRecExpr(const SCEVAddRecExpr *S) {
// AddRecExpr will handled out in visit Next;
return std::make_pair(S, getSCEVOne(S));
}
value_type visitUDivExpr(const SCEVUDivExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
value_type visitSMaxExpr(const SCEVSMaxExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
value_type visitUMaxExpr(const SCEVUMaxExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
/// Get the next {variable, constant} pair of the SCEV.
value_type visitNext() {
value_type ret(0, 0);
if (visitStack.empty())
return ret;
const SCEV* nextS = visitStack.back();
if (const SCEVAddRecExpr *ARec = dyn_cast<SCEVAddRecExpr>(nextS)){
// Visiting the AddRec, check if its Affine;
PHINode *IV = ARec->getLoop()->getCanonicalInductionVariable();
// Only decompose the AddRec, if the loop has a canonical induction
// variable.
if (ARec->isAffine() && IV != 0) {
ret = visit(ARec->getStepRecurrence(*SE));
if (isa<SCEVConstant>(ret.first)) { // If the step is constant.
const SCEV *Start = ARec->getStart();
visitStack.back() = Start;
// The AddRec is expect to be decomposed to
//
// | start + step * {1, +, 1}<loop>
//
// Now we get the {1, +, 1}<loop> part.
ret.first = SE->getSCEV(IV);
// Push CouldNotCompute to take the place.
visitStack.push_back(SE->getCouldNotCompute());
return ret;
}
// The step is not a constant. Then this AddRec is not Affine or
// no canonical induction variable found.
// Fall through.
}
}
// Get the constant part and variable part of the SCEV.
ret = visit(nextS);
// If the reach the last constant
if (isa<SCEVConstant>(ret.first) && (visitStack.size() != 1)) {
// Else, merge all constant component, we will output it at last.
visitStack.front() = SE->getAddExpr(visitStack.front(), ret.second);
//assert(isa<SCEVConstant>(visitStack.front().first));
// Pop the top constant, because it already merged into the bottom of the Stack
// and output it last.
visitStack.pop_back();
// Try again.
return visitNext();
}
// Not a constant or Stack not empty
// If ret is in (xxx) * AddExpr form, we will decompose the AddExpr
else if (const SCEVAddExpr *AddExpr = dyn_cast<SCEVAddExpr>(ret.first)) {
// Pop the current SCEV, we will decompose it.
visitStack.pop_back();
assert(AddExpr->getNumOperands() && "AddExpr without operand?");
for (scev_op_it I = AddExpr->op_begin(), E = AddExpr->op_end(); I != E; ++I){
visitStack.push_back(SE->getMulExpr(ret.second, *I));
}
// Try again with the new SCEV.
return visitNext();
}
return ret;
}
public:
/// @brief Create the iterator from a SCEV and the ScalarEvolution analysis.
AffineSCEVIterator(const SCEV* S, ScalarEvolution *se ) : SE(se) {
// Dont iterate CouldNotCompute.
if (isa<SCEVCouldNotCompute>(S))
return;
Type *Ty = S->getType();
// Init the constant component.
visitStack.push_back(SE->getConstant(Ty, 0));
// Get the first affine component.
visitStack.push_back(S);
val = visitNext();
}
/// @brief Create an end iterator.
inline AffineSCEVIterator() {}
inline bool operator==(const Self& x) const {
return visitStack == x.visitStack;
}
inline bool operator!=(const Self& x) const { return !operator==(x); }
/// @brief Return the current (constant * variable) component of the SCEV.
///
/// @return The "first" field of the pair is the variable part,
/// the "second" field of the pair is the constant part.
inline value_type operator*() const {
assert(val.first && val.second && "Cant dereference iterator!");
return val;
}
inline const value_type* operator->() const {
assert(val.first && val.second && "Cant dereference iterator!");
return &val;
}
inline Self& operator++() { // Preincrement
assert(!visitStack.empty() && "Cant ++ iterator!");
// Pop the last SCEV.
visitStack.pop_back();
val = visitNext();
return *this;
}
inline Self operator++(int) { // Postincrement
Self tmp = *this; ++*this; return tmp;
}
};
inline static AffineSCEVIterator affine_begin(const SCEV* S, ScalarEvolution *SE) {
return AffineSCEVIterator(S, SE);
}
inline static AffineSCEVIterator affine_end() {
return AffineSCEVIterator();
}
} // end namespace polly
#endif

View File

@ -49,12 +49,13 @@
#include "polly/LinkAllPasses.h"
#include "polly/Support/ScopHelper.h"
#include "polly/Support/SCEVValidator.h"
#include "polly/Support/AffineSCEVIterator.h"
#include "llvm/LLVMContext.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"

View File

@ -16,7 +16,6 @@
#include "polly/TempScopInfo.h"
#include "polly/LinkAllPasses.h"
#include "polly/Support/AffineSCEVIterator.h"
#include "polly/Support/GICHelper.h"
#include "polly/Support/ScopHelper.h"
#include "polly/Support/SCEVValidator.h"
@ -25,6 +24,8 @@
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/ADT/STLExtras.h"
#define DEBUG_TYPE "polly-analyze-ir"

View File

@ -1,121 +0,0 @@
//===- AffSCEVItTester.cpp - Test the affine scev itertor. ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Test the affine scev itertor.
//
//===----------------------------------------------------------------------===//
#include "polly/Support/AffineSCEVIterator.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace llvm;
using namespace polly;
static void printSCEVAffine(raw_ostream &OS, const SCEV* S,
ScalarEvolution *SE) {
for (AffineSCEVIterator I = affine_begin(S, SE), E = affine_end();
I != E; ++I) {
OS << *I->second << " * " << *I->first;
// The constant part of the SCEV will always be the last one.
if (!isa<SCEVConstant>(S))
OS << " + ";
}
}
namespace {
struct AffSCEVItTester : public FunctionPass {
static char ID;
ScalarEvolution *SE;
LoopInfo *LI;
Function *F;
explicit AffSCEVItTester() : FunctionPass(ID), SE(0), LI(0), F(0) {}
virtual bool runOnFunction(Function &F) {
SE = &getAnalysis<ScalarEvolution>();
LI = &getAnalysis<LoopInfo>();
this->F = &F;
return false;
}
virtual void print(raw_ostream &OS, const Module *M) const {
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
if (SE->isSCEVable(I->getType())) {
OS << *I << '\n';
OS << " --> ";
const SCEV *SV = SE->getSCEV(&*I);
if (Loop *L = LI->getLoopFor(I->getParent()))
SV = SE->getSCEVAtScope(SV, L);
SV->print(OS);
OS << "\n";
OS << "affine function --> ";
printSCEVAffine(OS, SV, SE);
OS << "\n";
}
for (LoopInfo::iterator I = LI->begin(), E = LI->end(); I != E; ++I)
PrintLoopInfo(OS, *I);
}
void PrintLoopInfo(raw_ostream &OS, const Loop *L) const{
// Print all inner loops first
for (Loop::iterator I = L->begin(), E = L->end(); I != E; ++I)
PrintLoopInfo(OS, *I);
OS << "Loop ";
WriteAsOperand(OS, L->getHeader(), /*PrintType=*/false);
OS << ": ";
if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
const SCEV *SV = SE->getBackedgeTakenCount(L);
OS << "backedge-taken count is ";
printSCEVAffine(OS, SV, SE);
OS << "\nloop count in scev ";
SV->print(OS);
OS << "\n";
}
else {
OS << "Unpredictable\n";
}
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<ScalarEvolution>();
AU.addRequired<LoopInfo>();
AU.setPreservesAll();
}
};
} // end namespace
char AffSCEVItTester::ID = 0;
RegisterPass<AffSCEVItTester> B("print-scev-affine",
"Print the SCEV expressions in affine form.",
true,
true);
namespace polly {
Pass *createAffSCEVItTesterPass() {
return new AffSCEVItTester();
}
}

View File

@ -1,5 +1,4 @@
add_polly_library(PollySupport
AffSCEVItTester.cpp
GICHelper.cpp
SCEVValidator.cpp
ScopHelper.cpp

View File

@ -1,24 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define void @f(i32* nocapture %a) nounwind {
entry:
%0 = tail call i32 (...)* @rnd() nounwind ; <i32> [#uses=2]
; CHECK: 1 * %0 + 0 * 1
%1 = icmp sgt i32 %0, 0 ; <i1> [#uses=1]
br i1 %1, label %bb, label %return
bb: ; preds = %bb, %entry
%i.03 = phi i32 [ 0, %entry ], [ %3, %bb ] ; <i32> [#uses=1]
; CHECK: 1 * {0,+,1}<nuw><nsw><%bb> + 0 * 1
%2 = tail call i32 (...)* @rnd() nounwind ; <i32> [#uses=0]
; CHECK: 1 * %2 + 0 * 1
%3 = add nsw i32 %i.03, 1 ; <i32> [#uses=2]
; CHECK: 1 * {0,+,1}<nuw><nsw><%bb> + 1 * 1
%exitcond = icmp eq i32 %3, %0 ; <i1> [#uses=1]
br i1 %exitcond, label %return, label %bb
return: ; preds = %bb, %entry
ret void
}
declare i32 @rnd(...)

View File

@ -1,20 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define i32 @f(i64 %a, i64 %b, i64 %c, [8 x i32]* nocapture %x) nounwind readonly {
entry:
%0 = shl i64 %a, 1 ; <i64> [#uses=1]
%1 = add nsw i64 %0, %b ; <i64> [#uses=1]
; CHECK: 1 * %b + 2 * %a + 0 * 1
%2 = shl i64 %1, 1 ; <i64> [#uses=1]
; CHECK: 2 * %b + 4 * %a + 0 * 1
%3 = add i64 %2, 2 ; <i64> [#uses=1]
%4 = mul i64 %a, 3 ; <i64> [#uses=1]
%5 = shl i64 %b, 2 ; <i64> [#uses=1]
%6 = add nsw i64 %4, 2 ; <i64> [#uses=1]
%7 = add nsw i64 %6, %c ; <i64> [#uses=1]
%8 = add nsw i64 %7, %5 ; <i64> [#uses=1]
%9 = getelementptr inbounds [8 x i32]* %x, i64 %3, i64 %8 ; <i32*> [#uses=1]
; CHECK: 1 * %x + sizeof(i32) * %c + (35 * sizeof(i32)) * %a + (20 * sizeof(i32)) * %b + (18 * sizeof(i32)) * 1
%10 = load i32* %9, align 4 ; <i32> [#uses=1]
ret i32 %10
}

View File

@ -1,44 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define void @f([8 x i32]* nocapture %x) nounwind {
entry:
br label %bb5.preheader
bb2: ; preds = %bb3.preheader, %bb2
%k.09 = phi i64 [ 0, %bb3.preheader ], [ %1, %bb2 ] ; <i64> [#uses=2]
%tmp19 = add i64 %k.09, %tmp18 ; <i64> [#uses=1]
%scevgep = getelementptr [8 x i32]* %x, i64 2, i64 %tmp19 ; <i32*> [#uses=1]
; CHECK: sizeof(i32) * {0,+,1}<nuw><nsw><%bb2> + (20 * sizeof(i32)) * {0,+,1}<%bb3.preheader> + (35 * sizeof(i32)) * {0,+,1}<%bb5.preheader> + 1 * %x + (18 * sizeof(i32)) * 1
%0 = tail call i32 (...)* @rnd() nounwind ; <i32> [#uses=1]
store i32 %0, i32* %scevgep, align 4
%1 = add nsw i64 %k.09, 1 ; <i64> [#uses=2]
%exitcond = icmp eq i64 %1, 64 ; <i1> [#uses=1]
br i1 %exitcond, label %bb4, label %bb2
bb4: ; preds = %bb2
%2 = add i64 %j.010, 1 ; <i64> [#uses=2]
%exitcond20 = icmp eq i64 %2, 64 ; <i1> [#uses=1]
br i1 %exitcond20, label %bb6, label %bb3.preheader
bb3.preheader: ; preds = %bb5.preheader, %bb4
%j.010 = phi i64 [ 0, %bb5.preheader ], [ %2, %bb4 ] ; <i64> [#uses=2]
%tmp21 = mul i64 %j.010, 20 ; <i64> [#uses=1]
%tmp18 = add i64 %tmp21, %tmp23 ; <i64> [#uses=1]
br label %bb2
bb6: ; preds = %bb4
%3 = add i64 %i.012, 1 ; <i64> [#uses=2]
%exitcond25 = icmp eq i64 %3, 64 ; <i1> [#uses=1]
br i1 %exitcond25, label %return, label %bb5.preheader
bb5.preheader: ; preds = %bb6, %entry
%i.012 = phi i64 [ 0, %entry ], [ %3, %bb6 ] ; <i64> [#uses=2]
%tmp = mul i64 %i.012, 35 ; <i64> [#uses=1]
%tmp23 = add i64 %tmp, 2 ; <i64> [#uses=1]
br label %bb3.preheader
return: ; preds = %bb6
ret void
}
declare i32 @rnd(...)

View File

@ -1,20 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, i32* nocapture %x) nounwind readnone {
entry:
%0 = shl i32 %a, 1 ; <i32> [#uses=1]
; CHECK: 2 * %a + 0 * 1
%1 = mul i32 %b, 3 ; <i32> [#uses=1]
; CHECK: 3 * %b + 0 * 1
%2 = shl i32 %d, 2 ; <i32> [#uses=1]
; CHECK: 4 * %d + 0 * 1
%3 = add nsw i32 %0, 5 ; <i32> [#uses=1]
; CHECK: 2 * %a + 5 * 1
%4 = add nsw i32 %3, %c ; <i32> [#uses=1]
; CHECK: 1 * %c + 2 * %a + 5 * 1
%5 = add nsw i32 %4, %1 ; <i32> [#uses=1]
; CHECK: 1 * %c + 3 * %b + 2 * %a + 5 * 1
%6 = add nsw i32 %5, %2 ; <i32> [#uses=1]
; CHECK: 1 * %c + 4 * %d + 3 * %b + 2 * %a + 5 * 1
ret i32 %6
}

View File

@ -1,24 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
target triple = "x86_64-unknown-linux-gnu"
define i32 @f(i32 %a, i32 %b, i32 %c, i64 %d, i8 signext %e, i32 %f, i32 %g, i32 %h) nounwind readnone {
entry:
%0 = mul i32 %a, 3 ; <i32> [#uses=1]
%1 = mul i32 %b, 5 ; <i32> [#uses=1]
%2 = mul i32 %1, %c ; <i32> [#uses=1]
; CHECK: 5 * (%b * %c) + 0 * 1
%3 = mul i32 %2, %f ; <i32> [#uses=1]
; CHECK: 5 * (%b * %c * %f) + 0 * 1
%4 = sext i8 %e to i32 ; <i32> [#uses=1]
%5 = shl i32 %4, 2 ; <i32> [#uses=1]
%6 = trunc i64 %d to i32 ; <i32> [#uses=1]
%7 = mul i32 %6, %h ; <i32> [#uses=1]
%8 = add nsw i32 %0, %g ; <i32> [#uses=1]
%9 = add nsw i32 %8, %5 ; <i32> [#uses=1]
%10 = add nsw i32 %9, %3 ; <i32> [#uses=1]
%11 = add nsw i32 %10, %7 ; <i32> [#uses=1]
; CHECK: 1 * %g + 1 * ((trunc i64 %d to i32) * %h) + 5 * (%b * %c * %f) + 4 * (sext i8 %e to i32) + 3 * %a + 0 * 1
ret i32 %11
}

View File

@ -1,25 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
target triple = "x86_64-unknown-linux-gnu"
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, i32* nocapture %x) nounwind {
entry:
br label %bb
bb: ; preds = %bb, %entry
%indvar = phi i64 [ 0, %entry ], [ %indvar.next, %bb ] ; <i64> [#uses=3]
; CHECK: 1 * {0,+,1}<%bb> + 0 * 1
%scevgep = getelementptr i32* %x, i64 %indvar ; <i32*> [#uses=1]
; CHECK: 4 * {0,+,1}<%bb> + 1 * %x + 0 * 1
%i.04 = trunc i64 %indvar to i32 ; <i32> [#uses=1]
; CHECK: 1 * {0,+,1}<%bb> + 0 * 1
store i32 %i.04, i32* %scevgep, align 4
%indvar.next = add i64 %indvar, 1 ; <i64> [#uses=2]
; CHECK: 1 * {0,+,1}<%bb> + 1 * 1
%exitcond = icmp eq i64 %indvar.next, 64 ; <i1> [#uses=1]
br i1 %exitcond, label %bb2, label %bb
bb2: ; preds = %bb
ret i32 %a
}

View File

@ -1,38 +0,0 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
target triple = "x86_64-unknown-linux-gnu"
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, [4 x i32]* nocapture %x) nounwind {
entry:
br label %bb2.preheader
bb1: ; preds = %bb2.preheader, %bb1
%indvar = phi i64 [ 0, %bb2.preheader ], [ %indvar.next, %bb1 ] ; <i64> [#uses=3]
; CHECK: 1 * {0,+,1}<%bb1> + 0 * 1
%scevgep = getelementptr [4 x i32]* %x, i64 %indvar, i64 %0 ; <i32*> [#uses=1]
; CHECK: 16 * {0,+,1}<%bb1> + 4 * {0,+,1}<%bb2.preheader> + 1 * %x + 0 * 1
%tmp = mul i64 %indvar, %0 ; <i64> [#uses=1]
; CHECK: 1 * {0,+,{0,+,1}<%bb2.preheader>}<%bb1> + 0 * 1
%tmp13 = trunc i64 %tmp to i32 ; <i32> [#uses=1]
; CHECK: 1 * {0,+,{0,+,1}<%bb2.preheader>}<%bb1> + 0 * 1
store i32 %tmp13, i32* %scevgep, align 4
%indvar.next = add i64 %indvar, 1 ; <i64> [#uses=2]
; CHECK: 1 * {0,+,1}<%bb1> + 1 * 1
%exitcond = icmp eq i64 %indvar.next, 64 ; <i1> [#uses=1]
br i1 %exitcond, label %bb3, label %bb1
bb3: ; preds = %bb1
%indvar.next12 = add i64 %0, 1 ; <i64> [#uses=2]
; CHECK: 1 * {0,+,1}<%bb2.preheader> + 1 * 1
%exitcond14 = icmp eq i64 %indvar.next12, 64 ; <i1> [#uses=1]
br i1 %exitcond14, label %bb5, label %bb2.preheader
bb2.preheader: ; preds = %bb3, %entry
%0 = phi i64 [ 0, %entry ], [ %indvar.next12, %bb3 ] ; <i64> [#uses=3]
; CHECK: 1 * {0,+,1}<%bb2.preheader> + 0 * 1
br label %bb1
bb5: ; preds = %bb3
ret i32 %a
}