Skip to content

Commit eece5a9

Browse files
[NFC][ScopBuilder]Move finalizeAccesses and its callees to ScopBuilder
Scope of changes: 1) Moved finalizeAccesses to ScopBuilder 2) Moved updateAccessDimensionality to ScopBuilder 3) Moved foldSizeConstantsToRight to ScopBuilder 4) Moved foldSizeConstantsToRight to ScopBuilder 5) Moved assumeNoOutOfBounds to ScopBuilder 6) Moved markFortranArrays to ScopBuilder 7) Added iterator range for AccessFunctions vector. Differential Revision: https://reviews.llvm.org/D63794 llvm-svn: 366374
1 parent 4a09a73 commit eece5a9

File tree

4 files changed

+259
-253
lines changed

4 files changed

+259
-253
lines changed

polly/include/polly/ScopBuilder.h

+63
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,69 @@ class ScopBuilder {
178178
/// @param Stmt The parent statement of the instruction
179179
void buildAccessSingleDim(MemAccInst Inst, ScopStmt *Stmt);
180180

181+
/// Finalize all access relations.
182+
///
183+
/// When building up access relations, temporary access relations that
184+
/// correctly represent each individual access are constructed. However, these
185+
/// access relations can be inconsistent or non-optimal when looking at the
186+
/// set of accesses as a whole. This function finalizes the memory accesses
187+
/// and constructs a globally consistent state.
188+
void finalizeAccesses();
189+
190+
/// Update access dimensionalities.
191+
///
192+
/// When detecting memory accesses different accesses to the same array may
193+
/// have built with different dimensionality, as outer zero-values dimensions
194+
/// may not have been recognized as separate dimensions. This function goes
195+
/// again over all memory accesses and updates their dimensionality to match
196+
/// the dimensionality of the underlying ScopArrayInfo object.
197+
void updateAccessDimensionality();
198+
199+
/// Fold size constants to the right.
200+
///
201+
/// In case all memory accesses in a given dimension are multiplied with a
202+
/// common constant, we can remove this constant from the individual access
203+
/// functions and move it to the size of the memory access. We do this as this
204+
/// increases the size of the innermost dimension, consequently widens the
205+
/// valid range the array subscript in this dimension can evaluate to, and
206+
/// as a result increases the likelihood that our delinearization is
207+
/// correct.
208+
///
209+
/// Example:
210+
///
211+
/// A[][n]
212+
/// S[i,j] -> A[2i][2j+1]
213+
/// S[i,j] -> A[2i][2j]
214+
///
215+
/// =>
216+
///
217+
/// A[][2n]
218+
/// S[i,j] -> A[i][2j+1]
219+
/// S[i,j] -> A[i][2j]
220+
///
221+
/// Constants in outer dimensions can arise when the elements of a parametric
222+
/// multi-dimensional array are not elementary data types, but e.g.,
223+
/// structures.
224+
void foldSizeConstantsToRight();
225+
226+
/// Fold memory accesses to handle parametric offset.
227+
///
228+
/// As a post-processing step, we 'fold' memory accesses to parametric
229+
/// offsets in the access functions. @see MemoryAccess::foldAccess for
230+
/// details.
231+
void foldAccessRelations();
232+
233+
/// Assume that all memory accesses are within bounds.
234+
///
235+
/// After we have built a model of all memory accesses, we need to assume
236+
/// that the model we built matches reality -- aka. all modeled memory
237+
/// accesses always remain within bounds. We do this as last step, after
238+
/// all memory accesses have been modeled and canonicalized.
239+
void assumeNoOutOfBounds();
240+
241+
/// Mark arrays that have memory accesses with FortranArrayDescriptor.
242+
void markFortranArrays();
243+
181244
/// Build the alias checks for this SCoP.
182245
bool buildAliasChecks();
183246

polly/include/polly/ScopInfo.h

+6-63
Original file line numberDiff line numberDiff line change
@@ -2090,57 +2090,6 @@ class Scop {
20902090
void addScopStmt(Region *R, StringRef Name, Loop *SurroundingLoop,
20912091
std::vector<Instruction *> EntryBlockInstructions);
20922092

2093-
/// Update access dimensionalities.
2094-
///
2095-
/// When detecting memory accesses different accesses to the same array may
2096-
/// have built with different dimensionality, as outer zero-values dimensions
2097-
/// may not have been recognized as separate dimensions. This function goes
2098-
/// again over all memory accesses and updates their dimensionality to match
2099-
/// the dimensionality of the underlying ScopArrayInfo object.
2100-
void updateAccessDimensionality();
2101-
2102-
/// Fold size constants to the right.
2103-
///
2104-
/// In case all memory accesses in a given dimension are multiplied with a
2105-
/// common constant, we can remove this constant from the individual access
2106-
/// functions and move it to the size of the memory access. We do this as this
2107-
/// increases the size of the innermost dimension, consequently widens the
2108-
/// valid range the array subscript in this dimension can evaluate to, and
2109-
/// as a result increases the likelihood that our delinearization is
2110-
/// correct.
2111-
///
2112-
/// Example:
2113-
///
2114-
/// A[][n]
2115-
/// S[i,j] -> A[2i][2j+1]
2116-
/// S[i,j] -> A[2i][2j]
2117-
///
2118-
/// =>
2119-
///
2120-
/// A[][2n]
2121-
/// S[i,j] -> A[i][2j+1]
2122-
/// S[i,j] -> A[i][2j]
2123-
///
2124-
/// Constants in outer dimensions can arise when the elements of a parametric
2125-
/// multi-dimensional array are not elementary data types, but e.g.,
2126-
/// structures.
2127-
void foldSizeConstantsToRight();
2128-
2129-
/// Fold memory accesses to handle parametric offset.
2130-
///
2131-
/// As a post-processing step, we 'fold' memory accesses to parametric
2132-
/// offsets in the access functions. @see MemoryAccess::foldAccess for
2133-
/// details.
2134-
void foldAccessRelations();
2135-
2136-
/// Assume that all memory accesses are within bounds.
2137-
///
2138-
/// After we have built a model of all memory accesses, we need to assume
2139-
/// that the model we built matches reality -- aka. all modeled memory
2140-
/// accesses always remain within bounds. We do this as last step, after
2141-
/// all memory accesses have been modeled and canonicalized.
2142-
void assumeNoOutOfBounds();
2143-
21442093
/// Remove statements from the list of scop statements.
21452094
///
21462095
/// @param ShouldDelete A function that returns true if the statement passed
@@ -2160,18 +2109,6 @@ class Scop {
21602109
/// have a corresponding domain in the domain map (or it is empty).
21612110
void removeStmtNotInDomainMap();
21622111

2163-
/// Mark arrays that have memory accesses with FortranArrayDescriptor.
2164-
void markFortranArrays();
2165-
2166-
/// Finalize all access relations.
2167-
///
2168-
/// When building up access relations, temporary access relations that
2169-
/// correctly represent each individual access are constructed. However, these
2170-
/// access relations can be inconsistent or non-optimal when looking at the
2171-
/// set of accesses as a whole. This function finalizes the memory accesses
2172-
/// and constructs a globally consistent state.
2173-
void finalizeAccesses();
2174-
21752112
/// Construct the schedule of this SCoP.
21762113
///
21772114
/// @param LI The LoopInfo for the current function.
@@ -2348,6 +2285,12 @@ class Scop {
23482285
return make_range(RecordedAssumptions.begin(), RecordedAssumptions.end());
23492286
}
23502287

2288+
/// Return an iterator range containing all the MemoryAccess objects of the
2289+
/// Scop.
2290+
iterator_range<AccFuncVector::iterator> access_functions() {
2291+
return make_range(AccessFunctions.begin(), AccessFunctions.end());
2292+
}
2293+
23512294
/// Return whether this scop is empty, i.e. contains no statements that
23522295
/// could be executed.
23532296
bool isEmpty() const { return Stmts.empty(); }

polly/lib/Analysis/ScopBuilder.cpp

+190-1
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,195 @@ void ScopBuilder::addArrayAccess(ScopStmt *Stmt, MemAccInst MemAccInst,
11541154
MemAccess->setFortranArrayDescriptor(FAD);
11551155
}
11561156

1157+
/// Check if @p Expr is divisible by @p Size.
1158+
static bool isDivisible(const SCEV *Expr, unsigned Size, ScalarEvolution &SE) {
1159+
assert(Size != 0);
1160+
if (Size == 1)
1161+
return true;
1162+
1163+
// Only one factor needs to be divisible.
1164+
if (auto *MulExpr = dyn_cast<SCEVMulExpr>(Expr)) {
1165+
for (auto *FactorExpr : MulExpr->operands())
1166+
if (isDivisible(FactorExpr, Size, SE))
1167+
return true;
1168+
return false;
1169+
}
1170+
1171+
// For other n-ary expressions (Add, AddRec, Max,...) all operands need
1172+
// to be divisible.
1173+
if (auto *NAryExpr = dyn_cast<SCEVNAryExpr>(Expr)) {
1174+
for (auto *OpExpr : NAryExpr->operands())
1175+
if (!isDivisible(OpExpr, Size, SE))
1176+
return false;
1177+
return true;
1178+
}
1179+
1180+
auto *SizeSCEV = SE.getConstant(Expr->getType(), Size);
1181+
auto *UDivSCEV = SE.getUDivExpr(Expr, SizeSCEV);
1182+
auto *MulSCEV = SE.getMulExpr(UDivSCEV, SizeSCEV);
1183+
return MulSCEV == Expr;
1184+
}
1185+
1186+
void ScopBuilder::foldSizeConstantsToRight() {
1187+
isl::union_set Accessed = scop->getAccesses().range();
1188+
1189+
for (auto Array : scop->arrays()) {
1190+
if (Array->getNumberOfDimensions() <= 1)
1191+
continue;
1192+
1193+
isl::space Space = Array->getSpace();
1194+
Space = Space.align_params(Accessed.get_space());
1195+
1196+
if (!Accessed.contains(Space))
1197+
continue;
1198+
1199+
isl::set Elements = Accessed.extract_set(Space);
1200+
isl::map Transform = isl::map::universe(Array->getSpace().map_from_set());
1201+
1202+
std::vector<int> Int;
1203+
int Dims = Elements.dim(isl::dim::set);
1204+
for (int i = 0; i < Dims; i++) {
1205+
isl::set DimOnly = isl::set(Elements).project_out(isl::dim::set, 0, i);
1206+
DimOnly = DimOnly.project_out(isl::dim::set, 1, Dims - i - 1);
1207+
DimOnly = DimOnly.lower_bound_si(isl::dim::set, 0, 0);
1208+
1209+
isl::basic_set DimHull = DimOnly.affine_hull();
1210+
1211+
if (i == Dims - 1) {
1212+
Int.push_back(1);
1213+
Transform = Transform.equate(isl::dim::in, i, isl::dim::out, i);
1214+
continue;
1215+
}
1216+
1217+
if (DimHull.dim(isl::dim::div) == 1) {
1218+
isl::aff Diff = DimHull.get_div(0);
1219+
isl::val Val = Diff.get_denominator_val();
1220+
1221+
int ValInt = 1;
1222+
if (Val.is_int()) {
1223+
auto ValAPInt = APIntFromVal(Val);
1224+
if (ValAPInt.isSignedIntN(32))
1225+
ValInt = ValAPInt.getSExtValue();
1226+
} else {
1227+
}
1228+
1229+
Int.push_back(ValInt);
1230+
isl::constraint C = isl::constraint::alloc_equality(
1231+
isl::local_space(Transform.get_space()));
1232+
C = C.set_coefficient_si(isl::dim::out, i, ValInt);
1233+
C = C.set_coefficient_si(isl::dim::in, i, -1);
1234+
Transform = Transform.add_constraint(C);
1235+
continue;
1236+
}
1237+
1238+
isl::basic_set ZeroSet = isl::basic_set(DimHull);
1239+
ZeroSet = ZeroSet.fix_si(isl::dim::set, 0, 0);
1240+
1241+
int ValInt = 1;
1242+
if (ZeroSet.is_equal(DimHull)) {
1243+
ValInt = 0;
1244+
}
1245+
1246+
Int.push_back(ValInt);
1247+
Transform = Transform.equate(isl::dim::in, i, isl::dim::out, i);
1248+
}
1249+
1250+
isl::set MappedElements = isl::map(Transform).domain();
1251+
if (!Elements.is_subset(MappedElements))
1252+
continue;
1253+
1254+
bool CanFold = true;
1255+
if (Int[0] <= 1)
1256+
CanFold = false;
1257+
1258+
unsigned NumDims = Array->getNumberOfDimensions();
1259+
for (unsigned i = 1; i < NumDims - 1; i++)
1260+
if (Int[0] != Int[i] && Int[i])
1261+
CanFold = false;
1262+
1263+
if (!CanFold)
1264+
continue;
1265+
1266+
for (auto &Access : scop->access_functions())
1267+
if (Access->getScopArrayInfo() == Array)
1268+
Access->setAccessRelation(
1269+
Access->getAccessRelation().apply_range(Transform));
1270+
1271+
std::vector<const SCEV *> Sizes;
1272+
for (unsigned i = 0; i < NumDims; i++) {
1273+
auto Size = Array->getDimensionSize(i);
1274+
1275+
if (i == NumDims - 1)
1276+
Size = SE.getMulExpr(Size, SE.getConstant(Size->getType(), Int[0]));
1277+
Sizes.push_back(Size);
1278+
}
1279+
1280+
Array->updateSizes(Sizes, false /* CheckConsistency */);
1281+
}
1282+
}
1283+
1284+
void ScopBuilder::markFortranArrays() {
1285+
for (ScopStmt &Stmt : *scop) {
1286+
for (MemoryAccess *MemAcc : Stmt) {
1287+
Value *FAD = MemAcc->getFortranArrayDescriptor();
1288+
if (!FAD)
1289+
continue;
1290+
1291+
// TODO: const_cast-ing to edit
1292+
ScopArrayInfo *SAI =
1293+
const_cast<ScopArrayInfo *>(MemAcc->getLatestScopArrayInfo());
1294+
assert(SAI && "memory access into a Fortran array does not "
1295+
"have an associated ScopArrayInfo");
1296+
SAI->applyAndSetFAD(FAD);
1297+
}
1298+
}
1299+
}
1300+
1301+
void ScopBuilder::finalizeAccesses() {
1302+
updateAccessDimensionality();
1303+
foldSizeConstantsToRight();
1304+
foldAccessRelations();
1305+
assumeNoOutOfBounds();
1306+
markFortranArrays();
1307+
}
1308+
1309+
void ScopBuilder::updateAccessDimensionality() {
1310+
// Check all array accesses for each base pointer and find a (virtual) element
1311+
// size for the base pointer that divides all access functions.
1312+
for (ScopStmt &Stmt : *scop)
1313+
for (MemoryAccess *Access : Stmt) {
1314+
if (!Access->isArrayKind())
1315+
continue;
1316+
ScopArrayInfo *Array =
1317+
const_cast<ScopArrayInfo *>(Access->getScopArrayInfo());
1318+
1319+
if (Array->getNumberOfDimensions() != 1)
1320+
continue;
1321+
unsigned DivisibleSize = Array->getElemSizeInBytes();
1322+
const SCEV *Subscript = Access->getSubscript(0);
1323+
while (!isDivisible(Subscript, DivisibleSize, SE))
1324+
DivisibleSize /= 2;
1325+
auto *Ty = IntegerType::get(SE.getContext(), DivisibleSize * 8);
1326+
Array->updateElementType(Ty);
1327+
}
1328+
1329+
for (auto &Stmt : *scop)
1330+
for (auto &Access : Stmt)
1331+
Access->updateDimensionality();
1332+
}
1333+
1334+
void ScopBuilder::foldAccessRelations() {
1335+
for (auto &Stmt : *scop)
1336+
for (auto &Access : Stmt)
1337+
Access->foldAccessRelation();
1338+
}
1339+
1340+
void ScopBuilder::assumeNoOutOfBounds() {
1341+
for (auto &Stmt : *scop)
1342+
for (auto &Access : Stmt)
1343+
Access->assumeNoOutOfBound();
1344+
}
1345+
11571346
void ScopBuilder::ensureValueWrite(Instruction *Inst) {
11581347
// Find the statement that defines the value of Inst. That statement has to
11591348
// write the value to make it available to those statements that read it.
@@ -2367,7 +2556,7 @@ void ScopBuilder::buildScop(Region &R, AssumptionCache &AC) {
23672556

23682557
scop->buildSchedule(LI);
23692558

2370-
scop->finalizeAccesses();
2559+
finalizeAccesses();
23712560

23722561
scop->realignParams();
23732562
addUserContext();

0 commit comments

Comments
 (0)