[OpenMP] Add workdistribute construct in openMP dialect and in llvm frontend.

This commit is contained in:
skc7 2025-08-19 21:32:39 +05:30
parent a5f1ddd115
commit d534a638f1
5 changed files with 205 additions and 0 deletions

View File

@ -1322,6 +1322,17 @@ def OMP_EndWorkshare : Directive<[Spelling<"end workshare">]> {
let category = OMP_Workshare.category;
let languages = [L_Fortran];
}
def OMP_Workdistribute : Directive<[Spelling<"workdistribute">]> {
let association = AS_Block;
let category = CA_Executable;
let languages = [L_Fortran];
}
def OMP_EndWorkdistribute : Directive<[Spelling<"end workdistribute">]> {
let leafConstructs = OMP_Workdistribute.leafConstructs;
let association = OMP_Workdistribute.association;
let category = OMP_Workdistribute.category;
let languages = [L_Fortran];
}
//===----------------------------------------------------------------------===//
// Definitions of OpenMP compound directives

View File

@ -2209,4 +2209,27 @@ def TargetFreeMemOp : OpenMP_Op<"target_freemem",
let assemblyFormat = "$device `,` $heapref attr-dict `:` type($device) `,` qualified(type($heapref))";
}
//===----------------------------------------------------------------------===//
// workdistribute Construct
//===----------------------------------------------------------------------===//
def WorkdistributeOp : OpenMP_Op<"workdistribute"> {
let summary = "workdistribute directive";
let description = [{
workdistribute divides execution of the enclosed structured block into
separate units of work, each executed only once by each
initial thread in the league.
```
!$omp target teams
!$omp workdistribute
y = a * x + y
!$omp end workdistribute
!$omp end target teams
```
}];
let regions = (region AnyRegion:$region);
let hasVerifier = 1;
let assemblyFormat = "$region attr-dict";
}
#endif // OPENMP_OPS

View File

@ -3975,6 +3975,58 @@ llvm::LogicalResult omp::TargetAllocMemOp::verify() {
return mlir::success();
}
//===----------------------------------------------------------------------===//
// WorkdistributeOp
//===----------------------------------------------------------------------===//
LogicalResult WorkdistributeOp::verify() {
// Check that region exists and is not empty
Region &region = getRegion();
if (region.empty())
return emitOpError("region cannot be empty");
// Verify single entry point.
Block &entryBlock = region.front();
if (entryBlock.empty())
return emitOpError("region must contain a structured block");
// Verify single exit point.
bool hasTerminator = false;
for (Block &block : region) {
if (isa<TerminatorOp>(block.back())) {
if (hasTerminator) {
return emitOpError("region must have exactly one terminator");
}
hasTerminator = true;
}
}
if (!hasTerminator) {
return emitOpError("region must be terminated with omp.terminator");
}
auto walkResult = region.walk([&](Operation *op) -> WalkResult {
// No implicit barrier at end
if (isa<BarrierOp>(op)) {
return emitOpError(
"explicit barriers are not allowed in workdistribute region");
}
// Check for invalid nested constructs
if (isa<ParallelOp>(op)) {
return emitOpError(
"nested parallel constructs not allowed in workdistribute");
}
if (isa<TeamsOp>(op)) {
return emitOpError(
"nested teams constructs not allowed in workdistribute");
}
return WalkResult::advance();
});
if (walkResult.wasInterrupted())
return failure();
Operation *parentOp = (*this)->getParentOp();
if (!llvm::dyn_cast<TeamsOp>(parentOp))
return emitOpError("workdistribute must be nested under teams");
return success();
}
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"

View File

@ -3017,3 +3017,110 @@ func.func @invalid_allocate_allocator(%arg0 : memref<i32>) -> () {
return
}
// -----
func.func @invalid_workdistribute_empty_region() -> () {
omp.teams {
// expected-error @below {{region cannot be empty}}
omp.workdistribute {
}
omp.terminator
}
return
}
// -----
func.func @invalid_workdistribute_no_terminator() -> () {
omp.teams {
// expected-error @below {{region must be terminated with omp.terminator}}
omp.workdistribute {
%c0 = arith.constant 0 : i32
}
omp.terminator
}
return
}
// -----
func.func @invalid_workdistribute_wrong_terminator() -> () {
omp.teams {
// expected-error @below {{region must be terminated with omp.terminator}}
omp.workdistribute {
%c0 = arith.constant 0 : i32
func.return
}
omp.terminator
}
return
}
// -----
func.func @invalid_workdistribute_multiple_terminators() -> () {
omp.teams {
// expected-error @below {{region must have exactly one terminator}}
omp.workdistribute {
%cond = arith.constant true
cf.cond_br %cond, ^bb1, ^bb2
^bb1:
omp.terminator
^bb2:
omp.terminator
}
omp.terminator
}
return
}
// -----
func.func @invalid_workdistribute_with_barrier() -> () {
omp.teams {
// expected-error @below {{explicit barriers are not allowed in workdistribute region}}
omp.workdistribute {
%c0 = arith.constant 0 : i32
omp.barrier
omp.terminator
}
omp.terminator
}
return
}
// -----
func.func @invalid_workdistribute_nested_parallel() -> () {
omp.teams {
// expected-error @below {{nested parallel constructs not allowed in workdistribute}}
omp.workdistribute {
omp.parallel {
omp.terminator
}
omp.terminator
}
omp.terminator
}
return
}
// -----
// Test: nested teams not allowed in workdistribute
func.func @invalid_workdistribute_nested_teams() -> () {
omp.teams {
// expected-error @below {{nested teams constructs not allowed in workdistribute}}
omp.workdistribute {
omp.teams {
omp.terminator
}
omp.terminator
}
omp.terminator
}
return
}
// -----
func.func @invalid_workdistribute() -> () {
// expected-error @below {{workdistribute must be nested under teams}}
omp.workdistribute {
omp.terminator
}
return
}

View File

@ -3238,3 +3238,15 @@ func.func @omp_allocate_dir(%arg0 : memref<i32>, %arg1 : memref<i32>) -> () {
return
}
// CHECK-LABEL: func.func @omp_workdistribute
func.func @omp_workdistribute() {
// CHECK: omp.teams
omp.teams {
// CHECK: omp.workdistribute
omp.workdistribute {
omp.terminator
}
omp.terminator
}
return
}