Skip to content

Commit ec63593

Browse files
committed
[OpenACC][CIR] Add lowering for 'copy' array indexes
The array indexes(and sections) are represented by the acc.bounds operation, which this ensures we fill in properly. The lowerbound is required, so we always get that. The upperbound or extent is required. We typically do extent, since that is the 'length' as specified by ACC, but in cases where we have implicit length, we use the extent instead. It isn't clear when 'stride' should be anything besides 1, though by my reading, since we have full-types in the emitted code, we should never have it be anything but 1. This patch enables these for copy on compute and combined constructs, and makes sure to test everything I could think of for combinations/permutations.
1 parent 12c62eb commit ec63593

File tree

3 files changed

+1001
-13
lines changed

3 files changed

+1001
-13
lines changed

clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ class OpenACCClauseCIREmitter final
121121
return constOp.getResult();
122122
}
123123

124+
mlir::Value createConstantInt(SourceLocation loc, unsigned width,
125+
int64_t value) {
126+
return createConstantInt(cgf.cgm.getLoc(loc), width, value);
127+
}
128+
124129
mlir::acc::DeviceType decodeDeviceType(const IdentifierInfo *ii) {
125130
// '*' case leaves no identifier-info, just a nullptr.
126131
if (!ii)
@@ -184,37 +189,94 @@ class OpenACCClauseCIREmitter final
184189
mlir::Location beginLoc;
185190
mlir::Value varValue;
186191
llvm::StringRef name;
192+
llvm::SmallVector<mlir::Value> bounds;
187193
};
188194

195+
mlir::Value createBound(mlir::Location boundLoc, mlir::Value lowerBound,
196+
mlir::Value upperBound, mlir::Value extent) {
197+
// Arrays always have a start-idx of 0.
198+
mlir::Value startIdx = createConstantInt(boundLoc, 64, 0);
199+
// TODO: OpenACC: It isn't clear that stride would ever be anything other
200+
// than '1'? We emit the type of the reference 'correctly' as far as I
201+
// know, so it should just be 1 element each time. We could perhaps use
202+
// the 'inBytes' variant here, but it isn't clear what value that gets us.
203+
// We might need to revisit this once we try to opt this and see what is
204+
// going to happen.
205+
mlir::Value stride = createConstantInt(boundLoc, 64, 1);
206+
207+
auto bound = builder.create<mlir::acc::DataBoundsOp>(boundLoc, lowerBound,
208+
upperBound);
209+
bound.getStartIdxMutable().assign(startIdx);
210+
if (extent)
211+
bound.getExtentMutable().assign(extent);
212+
bound.getStrideMutable().assign(stride);
213+
214+
return bound;
215+
}
216+
189217
// A helper function that gets the information from an operand to a data
190218
// clause, so that it can be used to emit the data operations.
191-
inline DataOperandInfo getDataOperandInfo(OpenACCDirectiveKind dk,
192-
const Expr *e) {
219+
DataOperandInfo getDataOperandInfo(OpenACCDirectiveKind dk, const Expr *e) {
193220
// TODO: OpenACC: Cache was different enough as to need a separate
194221
// `ActOnCacheVar`, so we are going to need to do some investigations here
195222
// when it comes to implement this for cache.
196223
if (dk == OpenACCDirectiveKind::Cache) {
197224
cgf.cgm.errorNYI(e->getSourceRange(),
198225
"OpenACC data operand for 'cache' directive");
199-
return {cgf.cgm.getLoc(e->getBeginLoc()), {}, {}};
226+
return {cgf.cgm.getLoc(e->getBeginLoc()), {}, {}, {}};
200227
}
201228

202229
const Expr *curVarExpr = e->IgnoreParenImpCasts();
203230

204231
mlir::Location exprLoc = cgf.cgm.getLoc(curVarExpr->getBeginLoc());
232+
llvm::SmallVector<mlir::Value> bounds;
233+
234+
// Assemble the list of bounds.
235+
while (isa<ArraySectionExpr, ArraySubscriptExpr>(curVarExpr)) {
236+
mlir::Location boundLoc = cgf.cgm.getLoc(curVarExpr->getBeginLoc());
237+
mlir::Value lowerBound;
238+
mlir::Value upperBound;
239+
mlir::Value extent;
240+
241+
if (const auto *section = dyn_cast<ArraySectionExpr>(curVarExpr)) {
242+
if (const Expr *lb = section->getLowerBound())
243+
lowerBound = emitIntExpr(lb);
244+
else
245+
lowerBound = createConstantInt(boundLoc, 64, 0);
246+
247+
if (const Expr *len = section->getLength()) {
248+
extent = emitIntExpr(len);
249+
} else {
250+
QualType baseTy = ArraySectionExpr::getBaseOriginalType(
251+
section->getBase()->IgnoreParenImpCasts());
252+
// We know this is the case as implicit lengths are only allowed for
253+
// array types with a constant size, or a dependent size. AND since
254+
// we are codegen we know we're not dependent.
255+
auto *arrayTy = cgf.getContext().getAsConstantArrayType(baseTy);
256+
// Rather than trying to calculate the extent based on the
257+
// lower-bound, we can just emit this as an upper bound.
258+
upperBound =
259+
createConstantInt(boundLoc, 64, arrayTy->getLimitedSize() - 1);
260+
}
205261

206-
// TODO: OpenACC: Assemble the list of bounds.
207-
if (isa<ArraySectionExpr, ArraySubscriptExpr>(curVarExpr)) {
208-
cgf.cgm.errorNYI(curVarExpr->getSourceRange(),
209-
"OpenACC data clause array subscript/section");
210-
return {exprLoc, {}, {}};
262+
curVarExpr = section->getBase()->IgnoreParenImpCasts();
263+
} else {
264+
const auto *subscript = dyn_cast<ArraySubscriptExpr>(curVarExpr);
265+
266+
lowerBound = emitIntExpr(subscript->getIdx());
267+
// Length of an array index is always 1.
268+
extent = createConstantInt(boundLoc, 64, 1);
269+
curVarExpr = subscript->getBase()->IgnoreParenImpCasts();
270+
}
271+
272+
bounds.push_back(createBound(boundLoc, lowerBound, upperBound, extent));
211273
}
212274

213275
// TODO: OpenACC: if this is a member expr, emit the VarPtrPtr correctly.
214276
if (isa<MemberExpr>(curVarExpr)) {
215277
cgf.cgm.errorNYI(curVarExpr->getSourceRange(),
216278
"OpenACC Data clause member expr");
217-
return {exprLoc, {}, {}};
279+
return {exprLoc, {}, {}, std::move(bounds)};
218280
}
219281

220282
// Sema has made sure that only 4 types of things can get here, array
@@ -223,14 +285,14 @@ class OpenACCClauseCIREmitter final
223285
// right.
224286
const auto *dre = cast<DeclRefExpr>(curVarExpr);
225287
const auto *vd = cast<VarDecl>(dre->getFoundDecl()->getCanonicalDecl());
226-
return {exprLoc, cgf.emitDeclRefLValue(dre).getPointer(), vd->getName()};
288+
return {exprLoc, cgf.emitDeclRefLValue(dre).getPointer(), vd->getName(),
289+
std::move(bounds)};
227290
}
228291

229292
template <typename BeforeOpTy, typename AfterOpTy>
230293
void addDataOperand(const Expr *varOperand, mlir::acc::DataClause dataClause,
231294
bool structured, bool implicit) {
232295
DataOperandInfo opInfo = getDataOperandInfo(dirKind, varOperand);
233-
mlir::ValueRange bounds;
234296

235297
// TODO: OpenACC: we should comprehend the 'modifier-list' here for the data
236298
// operand. At the moment, we don't have a uniform way to assign these
@@ -239,7 +301,7 @@ class OpenACCClauseCIREmitter final
239301

240302
auto beforeOp =
241303
builder.create<BeforeOpTy>(opInfo.beginLoc, opInfo.varValue, structured,
242-
implicit, opInfo.name, bounds);
304+
implicit, opInfo.name, opInfo.bounds);
243305
operation.getDataClauseOperandsMutable().append(beforeOp.getResult());
244306

245307
AfterOpTy afterOp;
@@ -248,7 +310,7 @@ class OpenACCClauseCIREmitter final
248310
builder.setInsertionPointAfter(operation);
249311
afterOp = builder.create<AfterOpTy>(opInfo.beginLoc, beforeOp.getResult(),
250312
opInfo.varValue, structured, implicit,
251-
opInfo.name, bounds);
313+
opInfo.name, opInfo.bounds);
252314
}
253315

254316
// Set the 'rest' of the info for both operations.

0 commit comments

Comments
 (0)