Skip to content

Commit 8497dfd

Browse files
committed
[mlir][openacc] Add firstprivate representation
Add a representation for firstprivate clause modeled on the private representation added in D150622. The firstprivate recipe operation has an additional mandatory region representing a sequences of operations needed to copy the initial value to the created private copy. Depends on D150622 Reviewed By: razvanlupusoru Differential Revision: https://reviews.llvm.org/D150729
1 parent 0457f50 commit 8497dfd

File tree

3 files changed

+218
-23
lines changed

3 files changed

+218
-23
lines changed

mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,71 @@ def OpenACC_PrivateRecipeOp : OpenACC_Op<"private.recipe",
457457
let hasRegionVerifier = 1;
458458
}
459459

460+
//===----------------------------------------------------------------------===//
461+
// 2.5.14 firstprivate clause
462+
//===----------------------------------------------------------------------===//
463+
464+
def OpenACC_FirstprivateRecipeOp : OpenACC_Op<"firstprivate.recipe",
465+
[IsolatedFromAbove, Symbol]> {
466+
let summary = "privatization recipe";
467+
468+
let description = [{
469+
Declares an OpenACC privatization recipe with copy of the initial value.
470+
The operation requires two mandatory regions and one optional.
471+
472+
1. The initializer region specifies how to allocate and initialize a new
473+
private value. For example in Fortran, a derived-type might have a
474+
default initialization. The region has an argument that contains the
475+
value that need to be privatized. This is useful if the type is not
476+
known at compile time and the private value is needed to create its
477+
copy.
478+
2. The copy region specifies how to copy the initial value to the newly
479+
created private value. It takes the initial value and the privatized
480+
value as arguments.
481+
3. The destroy region specifies how to destruct the value when it reaches
482+
its end of life. It takes the privatized value as argument.
483+
484+
A single privatization recipe can be used for multiple operand if they have
485+
the same type and do not require a specific default initialization.
486+
487+
Example:
488+
489+
```mlir
490+
acc.firstprivate.recipe @privatization_f32 : f32 init {
491+
^bb0(%0: f32):
492+
// init region contains a sequence of operations to create and
493+
// initialize the copy if needed. It yields the create copy.
494+
} copy {
495+
^bb0(%0: f32, %1: !llvm.ptr<f32>):
496+
// copy region contains a sequence of operations to copy the initial value
497+
// of the firstprivate value to the newly created value.
498+
} destroy {
499+
^bb0(%0: f32)
500+
// destroy region contains a sequences of operations to destruct the
501+
// created copy.
502+
}
503+
504+
// The privatization symbol is then used in the corresponding operation.
505+
acc.parallel firstprivate(@privatization_f32 -> %a : f32) {
506+
}
507+
```
508+
}];
509+
510+
let arguments = (ins SymbolNameAttr:$sym_name,
511+
TypeAttr:$type);
512+
513+
let regions = (region AnyRegion:$initRegion, AnyRegion:$copyRegion,
514+
AnyRegion:$destroyRegion);
515+
516+
let assemblyFormat = [{
517+
$sym_name `:` $type attr-dict-with-keyword `init` $initRegion
518+
`copy` $copyRegion
519+
(`destroy` $destroyRegion^)?
520+
}];
521+
522+
let hasRegionVerifier = 1;
523+
}
524+
460525
//===----------------------------------------------------------------------===//
461526
// 2.5.1 parallel Construct
462527
//===----------------------------------------------------------------------===//
@@ -921,7 +986,7 @@ def OpenACC_LoopOp : OpenACC_Op<"loop",
921986

922987
// Yield operation for the acc.loop and acc.parallel operations.
923988
def OpenACC_YieldOp : OpenACC_Op<"yield", [ReturnLike, Terminator,
924-
ParentOneOf<["ParallelOp, LoopOp, SerialOp, PrivateRecipeOp"]>]> {
989+
ParentOneOf<["ParallelOp, LoopOp, SerialOp, PrivateRecipeOp, FirstprivateRecipeOp"]>]> {
925990
let summary = "Acc yield and termination operation";
926991

927992
let description = [{

mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -338,31 +338,70 @@ struct RemoveConstantIfConditionWithRegion : public OpRewritePattern<OpTy> {
338338
// PrivateRecipeOp
339339
//===----------------------------------------------------------------------===//
340340

341-
LogicalResult acc::PrivateRecipeOp::verifyRegions() {
342-
if (getInitRegion().empty())
343-
return emitOpError() << "expects non-empty init region";
344-
Block &initBlock = getInitRegion().front();
345-
if (initBlock.getNumArguments() != 1 ||
346-
initBlock.getArgument(0).getType() != getType())
347-
return emitOpError() << "expects init region with one argument of the "
348-
<< "privatization type";
349-
350-
for (YieldOp yieldOp : getInitRegion().getOps<YieldOp>()) {
351-
if (yieldOp.getOperands().size() != 1 ||
352-
yieldOp.getOperands().getTypes()[0] != getType())
353-
return emitOpError() << "expects init region to yield a value "
354-
"of the privatization type";
341+
static LogicalResult verifyPrivateLikeRegion(Operation *op, Region &region,
342+
StringRef regionName, Type type,
343+
unsigned expectNbArg,
344+
bool optionalRegion,
345+
bool verifyYield) {
346+
if (optionalRegion && region.empty())
347+
return success();
348+
349+
if (region.empty())
350+
return op->emitOpError() << "expects non-empty " << regionName << " region";
351+
Block &firstBlock = region.front();
352+
if (expectNbArg == 1 && (firstBlock.getNumArguments() != 1 ||
353+
firstBlock.getArgument(0).getType() != type))
354+
return op->emitOpError() << "expects " << regionName
355+
<< " region with one "
356+
"argument of the privatization type";
357+
if (expectNbArg == 2 && (firstBlock.getNumArguments() != 2 ||
358+
firstBlock.getArgument(0).getType() != type))
359+
return op->emitOpError() << "expects " << regionName
360+
<< " region with two "
361+
"arguments of the privatization type";
362+
363+
if (verifyYield) {
364+
for (YieldOp yieldOp : region.getOps<acc::YieldOp>()) {
365+
if (yieldOp.getOperands().size() != 1 ||
366+
yieldOp.getOperands().getTypes()[0] != type)
367+
return op->emitOpError() << "expects " << regionName
368+
<< " region to "
369+
"yield a value of the privatization type";
370+
}
355371
}
372+
return success();
373+
}
356374

357-
// Destroy region is optional.
358-
if (getDestroyRegion().empty())
359-
return success();
375+
LogicalResult acc::PrivateRecipeOp::verifyRegions() {
376+
if (failed(verifyPrivateLikeRegion(*this, getInitRegion(), "init", getType(),
377+
1, /*optional=*/false,
378+
/*verifyYield=*/true)))
379+
return failure();
380+
if (failed(verifyPrivateLikeRegion(*this, getDestroyRegion(), "destroy",
381+
getType(), 1, /*optional=*/true,
382+
/*verifyYield=*/false)))
383+
return failure();
384+
return success();
385+
}
386+
387+
//===----------------------------------------------------------------------===//
388+
// FirstprivateRecipeOp
389+
//===----------------------------------------------------------------------===//
390+
391+
LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
392+
if (failed(verifyPrivateLikeRegion(*this, getInitRegion(), "init", getType(),
393+
1, /*optional=*/false,
394+
/*verifyYield=*/true)))
395+
return failure();
360396

361-
Block &destroyBlock = getDestroyRegion().front();
362-
if (destroyBlock.getNumArguments() != 1 ||
363-
destroyBlock.getArgument(0).getType() != getType())
364-
return emitOpError() << "expects destroy region with one argument of the "
365-
<< "privatization type";
397+
if (failed(verifyPrivateLikeRegion(*this, getCopyRegion(), "copy", getType(),
398+
2, /*optional=*/false,
399+
/*verifyYield=*/false)))
400+
return failure();
401+
if (failed(verifyPrivateLikeRegion(*this, getDestroyRegion(), "destroy",
402+
getType(), 1, /*optional=*/true,
403+
/*verifyYield=*/false)))
404+
return failure();
366405
return success();
367406
}
368407

mlir/test/Dialect/OpenACC/invalid.mlir

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,94 @@ acc.private.recipe @privatization_i32 : !llvm.ptr<i32> init {
303303
^bb0(%arg0 : f32):
304304
"test.openacc_dummy_op"(%arg0) : (f32) -> ()
305305
}
306+
307+
// -----
308+
309+
// expected-error@+1 {{expects non-empty init region}}
310+
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {
311+
} copy {}
312+
313+
// -----
314+
315+
// expected-error@+1 {{expects init region with one argument of the privatization type}}
316+
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {
317+
^bb0(%arg0 : !llvm.ptr<f32>):
318+
%c1 = arith.constant 1 : i32
319+
%c0 = arith.constant 0 : i32
320+
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<i32>
321+
llvm.store %c0, %0 : !llvm.ptr<i32>
322+
acc.yield %0 : !llvm.ptr<i32>
323+
} copy {}
324+
325+
// -----
326+
327+
// expected-error@+1 {{expects init region to yield a value of the privatization type}}
328+
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<f32> init {
329+
^bb0(%arg0 : !llvm.ptr<f32>):
330+
%c1 = arith.constant 1 : i32
331+
%c0 = arith.constant 0 : i32
332+
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<i32>
333+
llvm.store %c0, %0 : !llvm.ptr<i32>
334+
acc.yield %0 : !llvm.ptr<i32>
335+
} copy {}
336+
337+
// -----
338+
339+
// expected-error@+1 {{expects non-empty copy region}}
340+
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {
341+
^bb0(%arg0 : !llvm.ptr<i32>):
342+
%c1 = arith.constant 1 : i32
343+
%c0 = arith.constant 0 : i32
344+
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<i32>
345+
llvm.store %c0, %0 : !llvm.ptr<i32>
346+
acc.yield %0 : !llvm.ptr<i32>
347+
} copy {
348+
}
349+
350+
// -----
351+
352+
// expected-error@+1 {{expects copy region with two arguments of the privatization type}}
353+
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {
354+
^bb0(%arg0 : !llvm.ptr<i32>):
355+
%c1 = arith.constant 1 : i32
356+
%c0 = arith.constant 0 : i32
357+
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<i32>
358+
llvm.store %c0, %0 : !llvm.ptr<i32>
359+
acc.yield %0 : !llvm.ptr<i32>
360+
} copy {
361+
^bb0(%arg0 : f32):
362+
"test.openacc_dummy_op"(%arg0) : (f32) -> ()
363+
}
364+
365+
// -----
366+
367+
// expected-error@+1 {{expects copy region with two arguments of the privatization type}}
368+
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {
369+
^bb0(%arg0 : !llvm.ptr<i32>):
370+
%c1 = arith.constant 1 : i32
371+
%c0 = arith.constant 0 : i32
372+
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<i32>
373+
llvm.store %c0, %0 : !llvm.ptr<i32>
374+
acc.yield %0 : !llvm.ptr<i32>
375+
} copy {
376+
^bb0(%arg0 : f32, %arg1 : i32):
377+
"test.openacc_dummy_op"(%arg0) : (f32) -> ()
378+
}
379+
380+
// -----
381+
382+
// expected-error@+1 {{destroy region with one argument of the privatization type}}
383+
acc.firstprivate.recipe @privatization_i32 : i32 init {
384+
^bb0(%arg0 : i32):
385+
%0 = arith.constant 1 : i32
386+
acc.yield %0 : i32
387+
} copy {
388+
^bb0(%arg0 : i32, %arg1 : !llvm.ptr<i32>):
389+
llvm.store %arg0, %arg1 : !llvm.ptr<i32>
390+
acc.yield
391+
} destroy {
392+
^bb0(%arg0 : f32):
393+
acc.yield
394+
}
395+
396+

0 commit comments

Comments
 (0)