void addParameters(__isl_take isl_set *Context);
void create(__isl_take isl_ast_node *Node);
+ /// @brief Allocate memory for all new arrays created by Polly.
+ void allocateNewArrays();
+
/// @brief Preload all memory loads that are invariant.
bool preloadInvariantLoads();
/// @param Kind The kind of the array object.
/// @param DL The data layout of the module.
/// @param S The scop this array object belongs to.
+ /// @param BaseName The optional name of this memory reference.
ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *IslCtx,
ArrayRef<const SCEV *> DimensionSizes, enum MemoryKind Kind,
- const DataLayout &DL, Scop *S);
+ const DataLayout &DL, Scop *S, const char *BaseName = nullptr);
/// @brief Update the element type of the ScopArrayInfo object.
///
/// @brief The affinator used to translate SCEVs to isl expressions.
SCEVAffinator Affinator;
- typedef MapVector<std::pair<AssertingVH<const Value>, int>,
- std::unique_ptr<ScopArrayInfo>>
+ typedef std::map<std::pair<AssertingVH<const Value>, int>,
+ std::unique_ptr<ScopArrayInfo>>
ArrayInfoMapTy;
+
+ typedef StringMap<std::unique_ptr<ScopArrayInfo>> ArrayNameMapTy;
+
+ typedef SetVector<ScopArrayInfo *> ArrayInfoSetTy;
+
/// @brief A map to remember ScopArrayInfo objects for all base pointers.
///
/// As PHI nodes may have two array info objects associated, we add a flag
/// and the normal one.
ArrayInfoMapTy ScopArrayInfoMap;
+ /// @brief A map to remember ScopArrayInfo objects for all names of memory
+ /// references.
+ ArrayNameMapTy ScopArrayNameMap;
+
+ /// @brief A set to remember ScopArrayInfo objects.
+ /// @see Scop::ScopArrayInfoMap
+ ArrayInfoSetTy ScopArrayInfoSet;
+
/// @brief The assumptions under which this scop was built.
///
/// When constructing a scop sometimes the exact representation of a statement
/// could be executed.
bool isEmpty() const { return Stmts.empty(); }
- typedef ArrayInfoMapTy::iterator array_iterator;
- typedef ArrayInfoMapTy::const_iterator const_array_iterator;
- typedef iterator_range<ArrayInfoMapTy::iterator> array_range;
- typedef iterator_range<ArrayInfoMapTy::const_iterator> const_array_range;
+ typedef ArrayInfoSetTy::iterator array_iterator;
+ typedef ArrayInfoSetTy::const_iterator const_array_iterator;
+ typedef iterator_range<ArrayInfoSetTy::iterator> array_range;
+ typedef iterator_range<ArrayInfoSetTy::const_iterator> const_array_range;
- inline array_iterator array_begin() { return ScopArrayInfoMap.begin(); }
+ inline array_iterator array_begin() { return ScopArrayInfoSet.begin(); }
- inline array_iterator array_end() { return ScopArrayInfoMap.end(); }
+ inline array_iterator array_end() { return ScopArrayInfoSet.end(); }
inline const_array_iterator array_begin() const {
- return ScopArrayInfoMap.begin();
+ return ScopArrayInfoSet.begin();
}
inline const_array_iterator array_end() const {
- return ScopArrayInfoMap.end();
+ return ScopArrayInfoSet.end();
}
inline array_range arrays() {
///
/// @param ElementType The type of the elements stored in this array.
/// @param Kind The kind of the array info object.
+ /// @param BaseName The optional name of this memory reference.
const ScopArrayInfo *getOrCreateScopArrayInfo(Value *BasePtr,
Type *ElementType,
ArrayRef<const SCEV *> Sizes,
- ScopArrayInfo::MemoryKind Kind);
+ ScopArrayInfo::MemoryKind Kind,
+ const char *BaseName = nullptr);
+
+ /// @brief Create an array and return the corresponding ScopArrayInfo object.
+ ///
+ /// @param ElementType The type of the elements stored in this array.
+ /// @param BaseName The name of this memory reference.
+ /// @param Sizes The sizes of dimensions.
+ const ScopArrayInfo *createScopArrayInfo(Type *ElementType,
+ const std::string &BaseName,
+ const std::vector<unsigned> &Sizes);
/// @brief Return the cached ScopArrayInfo object for @p BasePtr.
///
/// @param BasePtr The base pointer of the ScopArrayInfo object to invalidate.
/// @param Kind The Kind of the ScopArrayInfo object.
void invalidateScopArrayInfo(Value *BasePtr, ScopArrayInfo::MemoryKind Kind) {
- ScopArrayInfoMap.erase(std::make_pair(BasePtr, Kind));
+ auto It = ScopArrayInfoMap.find(std::make_pair(BasePtr, Kind));
+ if (It == ScopArrayInfoMap.end())
+ return;
+ ScopArrayInfoSet.remove(It->second.get());
+ ScopArrayInfoMap.erase(It);
}
void setContext(isl_set *NewContext);
/// >0 for other loops in the SCoP
/// -1 if @p L is nullptr or there is no outermost loop in the SCoP
int getRelativeLoopDepth(const Loop *L) const;
+
+ /// @brief Find the ScopArrayInfo associated with an isl Id
+ /// that has name @p Name.
+ ScopArrayInfo *getArrayInfoByName(const std::string BaseName);
};
/// @brief Print Scop scop to raw_ostream O.
ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx,
ArrayRef<const SCEV *> Sizes, enum MemoryKind Kind,
- const DataLayout &DL, Scop *S)
+ const DataLayout &DL, Scop *S,
+ const char *BaseName)
: BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) {
std::string BasePtrName =
- getIslCompatibleName("MemRef_", BasePtr, Kind == MK_PHI ? "__phi" : "");
+ BaseName ? BaseName : getIslCompatibleName("MemRef_", BasePtr,
+ Kind == MK_PHI ? "__phi" : "");
Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this);
updateSizes(Sizes);
+
+ if (!BasePtr) {
+ BasePtrOriginSAI = nullptr;
+ return;
+ }
+
BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr);
if (BasePtrOriginSAI)
const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this);
// Explicitly release all Scop objects and the underlying isl objects before
// we relase the isl context.
Stmts.clear();
+ ScopArrayInfoSet.clear();
ScopArrayInfoMap.clear();
+ ScopArrayNameMap.clear();
AccFuncMap.clear();
}
isl_union_map_free(Writes);
}
-const ScopArrayInfo *
-Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType,
- ArrayRef<const SCEV *> Sizes,
- ScopArrayInfo::MemoryKind Kind) {
- auto &SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)];
+const ScopArrayInfo *Scop::getOrCreateScopArrayInfo(
+ Value *BasePtr, Type *ElementType, ArrayRef<const SCEV *> Sizes,
+ ScopArrayInfo::MemoryKind Kind, const char *BaseName) {
+ assert((BasePtr || BaseName) &&
+ "BasePtr and BaseName can not be nullptr at the same time.");
+ assert(!(BasePtr && BaseName) && "BaseName is redundant.");
+ auto &SAI = BasePtr ? ScopArrayInfoMap[std::make_pair(BasePtr, Kind)]
+ : ScopArrayNameMap[BaseName];
if (!SAI) {
auto &DL = getFunction().getParent()->getDataLayout();
SAI.reset(new ScopArrayInfo(BasePtr, ElementType, getIslCtx(), Sizes, Kind,
- DL, this));
+ DL, this, BaseName));
+ ScopArrayInfoSet.insert(SAI.get());
} else {
SAI->updateElementType(ElementType);
// In case of mismatching array sizes, we bail out by setting the run-time
return SAI.get();
}
+const ScopArrayInfo *
+Scop::createScopArrayInfo(Type *ElementType, const std::string &BaseName,
+ const std::vector<unsigned> &Sizes) {
+ auto *DimSizeType = Type::getInt64Ty(getSE()->getContext());
+ std::vector<const SCEV *> SCEVSizes;
+
+ for (auto size : Sizes)
+ SCEVSizes.push_back(getSE()->getConstant(DimSizeType, size, false));
+
+ auto *SAI =
+ getOrCreateScopArrayInfo(nullptr, ElementType, SCEVSizes,
+ ScopArrayInfo::MK_Array, BaseName.c_str());
+ return SAI;
+}
+
const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr,
ScopArrayInfo::MemoryKind Kind) {
auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get();
OS << "Arrays {\n";
for (auto &Array : arrays())
- Array.second->print(OS);
+ Array->print(OS);
OS.indent(4) << "}\n";
OS.indent(4) << "Arrays (Bounds as pw_affs) {\n";
for (auto &Array : arrays())
- Array.second->print(OS, /* SizeAsPwAff */ true);
+ Array->print(OS, /* SizeAsPwAff */ true);
OS.indent(4) << "}\n";
}
return L->getLoopDepth() - OuterLoop->getLoopDepth();
}
+ScopArrayInfo *Scop::getArrayInfoByName(const std::string BaseName) {
+ for (auto &SAI : arrays()) {
+ if (SAI->getName() == BaseName)
+ return SAI;
+ }
+ return nullptr;
+}
+
//===----------------------------------------------------------------------===//
void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LoopInfoWrapperPass>();
Builder.SetInsertPoint(StartBB->getTerminator());
- for (auto &Pair : S.arrays()) {
- auto &Array = Pair.second;
+ for (auto &Array : S.arrays()) {
if (Array->getNumberOfDimensions() != 0)
continue;
if (Array->isPHIKind()) {
}
void BlockGenerator::findOutsideUsers(Scop &S) {
- for (auto &Pair : S.arrays()) {
- auto &Array = Pair.second;
+ for (auto &Array : S.arrays()) {
if (Array->getNumberOfDimensions() != 0)
continue;
Builder.SetInsertPoint(OptExitBB->getTerminator());
- for (auto &Pair : S.arrays()) {
- auto &SAI = Pair.second;
+ for (auto &SAI : S.arrays()) {
auto *Val = SAI->getBasePtr();
// Only Value-like scalars need a merge PHI. Exit block PHIs receive either
isl_ast_node_free(AstRoot);
} else {
+ NodeBuilder.allocateNewArrays();
NodeBuilder.addParameters(S.getContext());
return true;
}
+void IslNodeBuilder::allocateNewArrays() {
+ for (auto &SAI : S.arrays()) {
+ if (SAI->getBasePtr())
+ continue;
+
+ Type *NewArrayType = nullptr;
+ for (unsigned i = SAI->getNumberOfDimensions() - 1; i >= 1; i--) {
+ auto *DimSize = SAI->getDimensionSize(i);
+ unsigned UnsignedDimSize = static_cast<const SCEVConstant *>(DimSize)
+ ->getAPInt()
+ .getLimitedValue();
+
+ if (!NewArrayType)
+ NewArrayType = SAI->getElementType();
+
+ NewArrayType = ArrayType::get(NewArrayType, UnsignedDimSize);
+ }
+
+ auto InstIt =
+ Builder.GetInsertBlock()->getParent()->getEntryBlock().getTerminator();
+ Value *CreatedArray =
+ new AllocaInst(NewArrayType, SAI->getName(), &*InstIt);
+ SAI->setBasePtr(CreatedArray);
+ }
+}
+
bool IslNodeBuilder::preloadInvariantLoads() {
auto &InvariantEquivClasses = S.getInvariantAccesses();
findValues(Expr, SE, SubtreeValues);
for (auto &SAI : S.arrays())
- SubtreeValues.remove(SAI.second->getBasePtr());
+ SubtreeValues.remove(SAI->getBasePtr());
isl_space *Space = S.getParamSpace();
for (long i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
}
for (auto &Array : S->arrays()) {
- auto Id = Array.second->getBasePtrId();
+ auto Id = Array->getBasePtrId();
Names = isl_id_to_ast_expr_set(Names, Id, isl_ast_expr_copy(Zero));
}
/// @param PPCGProg The program to compute the arrays for.
void createArrays(gpu_prog *PPCGProg) {
int i = 0;
- for (auto &Element : S->arrays()) {
- ScopArrayInfo *Array = Element.second.get();
-
+ for (auto &Array : S->arrays()) {
std::string TypeName;
raw_string_ostream OS(TypeName);
isl_union_map *getArrayIdentity() {
isl_union_map *Maps = isl_union_map_empty(S->getParamSpace());
- for (auto &Item : S->arrays()) {
- ScopArrayInfo *Array = Item.second.get();
+ for (auto &Array : S->arrays()) {
isl_space *Space = Array->getSpace();
Space = isl_space_map_from_set(Space);
isl_map *Identity = isl_map_identity(Space);
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
#include "isl/constraint.h"
#include "isl/map.h"
#include "isl/printer.h"
/// @returns True if the import succeeded, otherwise False.
bool importSchedule(Scop &S, Json::Value &JScop, const Dependences &D);
+ /// Import new arrays from JScop.
+ ///
+ /// @param S The scop to update.
+ /// @param JScop The JScop file describing new arrays.
+ ///
+ /// @returns True if the import succeeded, otherwise False.
+ bool importArrays(Scop &S, Json::Value &JScop);
+
/// Import new memory accesses from JScop.
///
/// @param S The scop to update.
void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { S.print(OS); }
+/// Export all arrays from the Scop.
+///
+/// @param S The Scop containing the arrays.
+///
+/// @returns Json::Value containing the arrays.
+Json::Value exportArrays(const Scop &S) {
+ Json::Value Arrays;
+ std::string Buffer;
+ llvm::raw_string_ostream RawStringOstream(Buffer);
+
+ for (auto &SAI : S.arrays()) {
+ if (!SAI->isArrayKind())
+ continue;
+
+ Json::Value Array;
+ Array["name"] = SAI->getName();
+ for (unsigned i = 1; i < SAI->getNumberOfDimensions(); i++) {
+ SAI->getDimensionSize(i)->print(RawStringOstream);
+ Array["sizes"].append(RawStringOstream.str());
+ Buffer.clear();
+ }
+ SAI->getElementType()->print(RawStringOstream);
+ Array["type"] = RawStringOstream.str();
+ Buffer.clear();
+ Arrays.append(Array);
+ }
+ return Arrays;
+}
+
Json::Value JSONExporter::getJSON(Scop &S) const {
Json::Value root;
unsigned LineBegin, LineEnd;
root["context"] = S.getContextStr();
if (LineBegin != (unsigned)-1)
root["location"] = Location;
+
+ root["arrays"] = exportArrays(S);
+
root["statements"];
for (ScopStmt &Stmt : S) {
return false;
}
- isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
- NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, OutId);
+ isl_id *NewOutId;
+
+ if (MA->isArrayKind()) {
+ NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
+ auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
+ isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
+ auto *OutSAI = ScopArrayInfo::getFromId(OutId);
+ if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
+ errs() << "JScop file contains access function with undeclared "
+ "ScopArrayInfo\n";
+ isl_map_free(CurrentAccessMap);
+ isl_map_free(NewAccessMap);
+ isl_id_free(NewOutId);
+ return false;
+ }
+ isl_id_free(NewOutId);
+ NewOutId = SAI->getBasePtrId();
+ } else {
+ NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
+ }
+
+ NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId);
if (MA->isArrayKind()) {
// We keep the old alignment, thus we cannot allow accesses to memory
isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in);
NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id);
- if (!isl_map_has_equal_space(CurrentAccessMap, NewAccessMap)) {
+ auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap));
+ auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap));
+
+ if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) {
errs() << "JScop file contains access function with incompatible "
<< "dimensions\n";
isl_map_free(CurrentAccessMap);
isl_map_free(NewAccessMap);
+ isl_set_free(NewAccessDomain);
+ isl_set_free(CurrentAccessDomain);
return false;
}
- auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap));
- auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap));
-
NewAccessDomain =
isl_set_intersect_params(NewAccessDomain, S.getContext());
CurrentAccessDomain =
return true;
}
+/// @brief Check whether @p SAI and @p Array represent the same array.
+bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) {
+ std::string Buffer;
+ llvm::raw_string_ostream RawStringOstream(Buffer);
+
+ if (SAI->getName() != Array["name"].asCString())
+ return false;
+
+ if (SAI->getNumberOfDimensions() != Array["sizes"].size() + 1)
+ return false;
+
+ for (unsigned i = 0; i < Array["sizes"].size(); i++) {
+ SAI->getDimensionSize(i + 1)->print(RawStringOstream);
+ if (RawStringOstream.str() != Array["sizes"][i].asCString())
+ return false;
+ Buffer.clear();
+ }
+
+ SAI->getElementType()->print(RawStringOstream);
+ if (RawStringOstream.str() != Array["type"].asCString())
+ return false;
+
+ return true;
+}
+
+/// @brief Get the accepted primitive type from its textual representation
+/// @p TypeTextRepresentation.
+///
+/// @param TypeTextRepresentation The textual representation of the type.
+/// @return The pointer to the primitive type, if this type is accepted
+/// or nullptr otherwise.
+Type *parseTextType(const std::string &TypeTextRepresentation,
+ LLVMContext &LLVMContext) {
+ std::map<std::string, Type *> MapStrToType = {
+ {"void", Type::getVoidTy(LLVMContext)},
+ {"half", Type::getHalfTy(LLVMContext)},
+ {"float", Type::getFloatTy(LLVMContext)},
+ {"double", Type::getDoubleTy(LLVMContext)},
+ {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)},
+ {"fp128", Type::getFP128Ty(LLVMContext)},
+ {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)},
+ {"i1", Type::getInt1Ty(LLVMContext)},
+ {"i8", Type::getInt8Ty(LLVMContext)},
+ {"i16", Type::getInt16Ty(LLVMContext)},
+ {"i32", Type::getInt32Ty(LLVMContext)},
+ {"i64", Type::getInt64Ty(LLVMContext)},
+ {"i128", Type::getInt128Ty(LLVMContext)}};
+
+ auto It = MapStrToType.find(TypeTextRepresentation);
+ if (It != MapStrToType.end())
+ return It->second;
+
+ errs() << "Textual representation can not be parsed: "
+ << TypeTextRepresentation << "\n";
+ return nullptr;
+}
+
+bool JSONImporter::importArrays(Scop &S, Json::Value &JScop) {
+ Json::Value Arrays = JScop["arrays"];
+
+ if (Arrays.size() == 0)
+ return true;
+
+ unsigned ArrayIdx = 0;
+ for (auto &SAI : S.arrays()) {
+ if (!SAI->isArrayKind())
+ continue;
+ if (ArrayIdx + 1 > Arrays.size())
+ return false;
+ if (!areArraysEqual(SAI, Arrays[ArrayIdx]))
+ return false;
+ ArrayIdx++;
+ }
+
+ for (; ArrayIdx < Arrays.size(); ArrayIdx++) {
+ auto *ElementType = parseTextType(Arrays[ArrayIdx]["type"].asCString(),
+ S.getSE()->getContext());
+ if (!ElementType)
+ return false;
+ std::vector<unsigned> DimSizes;
+ for (unsigned i = 0; i < Arrays[ArrayIdx]["sizes"].size(); i++)
+ DimSizes.push_back(std::stoi(Arrays[ArrayIdx]["sizes"][i].asCString()));
+ S.createScopArrayInfo(ElementType, Arrays[ArrayIdx]["name"].asCString(),
+ DimSizes);
+ }
+
+ return true;
+}
+
bool JSONImporter::runOnScop(Scop &S) {
const Dependences &D =
getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement);
if (!Success)
return false;
+ Success = importArrays(S, jscop);
+
+ if (!Success)
+ return false;
+
Success = importAccesses(S, jscop, DL);
if (!Success)
--- /dev/null
+; RUN: opt %loadPolly -polly-scops -analyze -polly-import-jscop-dir=%S -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop-dir=%S -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s 2>&1 | FileCheck %s --check-prefix=CODEGEN
+;
+; for (i = 0; i < _PB_NI; i++)
+; for (j = 0; j < _PB_NJ; j++)
+; for (k = 0; k < _PB_NK; ++k)
+; B[i][j] = beta * A[i][k];
+;
+;
+; CHECK: Arrays {
+; CHECK: double MemRef_B[*][1024]; // Element size 8
+; CHECK: double MemRef_beta; // Element size 8
+; CHECK: double MemRef_A[*][1056]; // Element size 8
+; CHECK: double D[*][270336]; // Element size 8
+; CHECK: double E[*][270336][200000]; // Element size 8
+; CHECK: i64 F[*][270336]; // Element size 8
+;
+; CHECK:New access function '{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }'detected in JSCOP file
+;
+;define internal void @create_arrays(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+;bb:
+; %beta.s2a = alloca double
+; %D = alloca [270336 x double]
+; %E = alloca [270336 x [200000 x double]]
+; %F = alloca [270336 x i64]
+; br label %bb8
+;
+; CODEGEN: %polly.access.cast.E = bitcast [270336 x [200000 x double]]* %E to double*
+; CODEGEN: %polly.access.mul.E = mul nsw i64 %polly.indvar33, 270336
+; CODEGEN: %polly.access.add.E = add nsw i64 %polly.access.mul.E, %polly.indvar
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: nounwind uwtable
+define internal void @create_arrays(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+bb:
+ br label %bb8
+
+bb8: ; preds = %bb
+ br label %bb9
+
+bb9: ; preds = %bb23, %bb8
+ %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ]
+ br label %bb10
+
+bb10: ; preds = %bb20, %bb9
+ %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ]
+ br label %bb12
+
+bb12: ; preds = %bb12, %bb10
+ %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ]
+ %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13
+ %tmp15 = load double, double* %tmp14, align 8
+ %tmp16 = fmul double %tmp15, %beta
+ %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11
+ store double %tmp16, double* %tmp17, align 8
+ %tmp18 = add nuw nsw i64 %tmp13, 1
+ %tmp19 = icmp ne i64 %tmp18, 1024
+ br i1 %tmp19, label %bb12, label %bb20
+
+bb20: ; preds = %bb12
+ %tmp21 = add nuw nsw i64 %tmp11, 1
+ %tmp22 = icmp ne i64 %tmp21, 1056
+ br i1 %tmp22, label %bb10, label %bb23
+
+bb23: ; preds = %bb20
+ %tmp24 = add nuw nsw i64 %tmp, 1
+ %tmp25 = icmp ne i64 %tmp24, 1056
+ br i1 %tmp25, label %bb9, label %bb26
+
+bb26: ; preds = %bb23
+ ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
--- /dev/null
+{
+ "arrays" : [
+ {
+ "name" : "MemRef_B",
+ "sizes" : [ "1024" ],
+ "type" : "double"
+ },
+ {
+ "name" : "MemRef_A",
+ "sizes" : [ "1056" ],
+ "type" : "double"
+ }
+ ],
+ "context" : "{ : }",
+ "name" : "%bb9---%bb26",
+ "statements" : [
+ {
+ "accesses" : [
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_B[i0, i2] }"
+ },
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+ },
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+ }
+ ],
+ "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+ "name" : "Stmt_bb12",
+ "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+ }
+ ]
+}
--- /dev/null
+{
+ "arrays" : [
+ {
+ "name" : "MemRef_B",
+ "sizes" : [ "1024" ],
+ "type" : "double"
+ },
+ {
+ "name" : "MemRef_A",
+ "sizes" : [ "1056" ],
+ "type" : "double"
+ },
+ {
+ "name" : "D",
+ "sizes" : [ "270336" ],
+ "type" : "double"
+ },
+ {
+ "name" : "E",
+ "sizes" : [ "270336", "200000" ],
+ "type" : "double"
+ },
+ {
+ "name" : "F",
+ "sizes" : [ "270336" ],
+ "type" : "i64"
+ }
+ ],
+ "context" : "{ : }",
+ "name" : "%bb9---%bb26",
+ "statements" : [
+ {
+ "accesses" : [
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }"
+ },
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+ },
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+ }
+ ],
+ "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+ "name" : "Stmt_bb12",
+ "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+ }
+ ]
+}