diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -116,10 +116,29 @@ OMP_PROC_BIND_unknown ]; } + +// static and auto are C++ keywords so need a capital to disambiguate. +def OMP_SCHEDULE_Static : ClauseVal<"Static", 2, 1> {} +def OMP_SCHEDULE_Dynamic : ClauseVal<"Dynamic", 3, 1> {} +def OMP_SCHEDULE_Guided : ClauseVal<"Guided", 4, 1> {} +def OMP_SCHEDULE_Auto : ClauseVal<"Auto", 5, 1> {} +def OMP_SCHEDULE_Runtime : ClauseVal<"Runtime", 6, 1> {} +def OMP_SCHEDULE_Default : ClauseVal<"Default", 7, 0> { let isDefault = 1; } + def OMPC_Schedule : Clause<"schedule"> { let clangClass = "OMPScheduleClause"; let flangClass = "OmpScheduleClause"; + let enumClauseValue = "ScheduleKind"; + let allowedClauseValues = [ + OMP_SCHEDULE_Static, + OMP_SCHEDULE_Dynamic, + OMP_SCHEDULE_Guided, + OMP_SCHEDULE_Auto, + OMP_SCHEDULE_Runtime, + OMP_SCHEDULE_Default + ]; } + def OMPC_Ordered : Clause<"ordered"> { let clangClass = "OMPOrderedClause"; let flangClassValue = "ScalarIntConstantExpr"; @@ -239,8 +258,14 @@ def OMPC_NonTemporal : Clause<"nontemporal"> { let clangClass = "OMPNontemporalClause"; } + +def OMP_ORDER_concurrent : ClauseVal<"default",2,0> { let isDefault = 1; } def OMPC_Order : Clause<"order"> { let clangClass = "OMPOrderClause"; + let enumClauseValue = "OrderKind"; + let allowedClauseValues = [ + OMP_ORDER_concurrent + ]; } def OMPC_Destroy : Clause<"destroy"> { let clangClass = "OMPDestroyClause"; diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.h --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.h +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.h @@ -13,8 +13,11 @@ #ifndef MLIR_DIALECT_OPENMP_OPENMPDIALECT_H_ #define MLIR_DIALECT_OPENMP_OPENMPDIALECT_H_ +#include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/Dialect.h" #include "mlir/IR/OpDefinition.h" +#include "mlir/Interfaces/ControlFlowInterfaces.h" +#include "mlir/Interfaces/SideEffectInterfaces.h" #include "mlir/Dialect/OpenMP/OpenMPOpsDialect.h.inc" #include "mlir/Dialect/OpenMP/OpenMPOpsEnums.h.inc" diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -15,6 +15,9 @@ #define OPENMP_OPS include "mlir/IR/OpBase.td" +include "mlir/Interfaces/SideEffectInterfaces.td" +include "mlir/Interfaces/ControlFlowInterfaces.td" +include "mlir/Dialect/LLVMIR/LLVMOpBase.td" include "mlir/Dialect/OpenMP/OmpCommon.td" def OpenMP_Dialect : Dialect { @@ -25,6 +28,10 @@ class OpenMP_Op traits = []> : Op; +// Type which can be constraint accepting standard integers, indices and +// LLVM integer types. +def IntLikeType : AnyTypeOf<[AnyInteger, Index, LLVM_AnyInteger]>; + //===----------------------------------------------------------------------===// // 2.6 parallel Construct //===----------------------------------------------------------------------===// @@ -102,6 +109,91 @@ let assemblyFormat = "attr-dict"; } +//===----------------------------------------------------------------------===// +// 2.9.2 Workshare Loop Construct +//===----------------------------------------------------------------------===// + +def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments]> { + let summary = "workshare loop construct"; + let description = [{ + The workshare loop construct specifies that the iterations of the loop(s) + will be executed in parallel by threads in the current context. These + iterations are spread across threads that already exist in the enclosing + parallel region. + + The body region can contain any number of blocks. The region is terminated + by "omp.yield" instruction without operands. + + ``` + omp.wsloop (%i1, %i2) = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { + %a = load %arrA[%i1, %i2] : memref + %b = load %arrB[%i1, %i2] : memref + %sum = addf %a, %b : f32 + store %sum, %arrC[%i1, %i2] : memref + omp.yield + } + ``` + + `private_vars`, `firstprivate_vars`, `lastprivate_vars` and `linear_vars` + arguments are variadic list of operands that specify the data sharing + attributes of the list of values. The `linear_step_vars` operand + additionally specifies the step for each associated linear operand. Note + that the `linear_vars` and `linear_step_vars` variadic lists should contain + the same number of elements. + + The optional `schedule_val` attribute specifies the loop schedule for this + loop, determining how the loop is distributed across the parallel threads. + The optional `schedule_chunk_var` associated with this determines further + controls this distribution. + + The optional `collapse_val` attribute specifies the number of loops which + are collapsed to form the worksharing loop. + + The `nowait` attribute, when present, signifies that there should be no + implicit barrier at the end of the loop. + + The optional `ordered_val` attribute specifies how many loops are associated + with the do loop construct. + + The optional `order` attribute specifies which order the iterations of the + associate loops are executed in. Currently the only option for this + attribute is "concurrent". + }]; + + let arguments = (ins Variadic:$lowerBound, + Variadic:$upperBound, + Variadic:$step, + Variadic:$private_vars, + Variadic:$firstprivate_vars, + Variadic:$lastprivate_vars, + Variadic:$linear_vars, + Variadic:$linear_step_vars, + OptionalAttr:$schedule_val, + Optional:$schedule_chunk_var, + Confined, [IntMinValue<0>]>:$collapse_val, + OptionalAttr:$nowait, + Confined, [IntMinValue<0>]>:$ordered_val, + OptionalAttr:$order_val); + + let regions = (region AnyRegion:$region); +} + +def YieldOp : OpenMP_Op<"yield", [NoSideEffect, ReturnLike, Terminator, + HasParent<"WsLoopOp">]> { + let summary = "loop yield and termination operation"; + let description = [{ + "omp.yield" yields SSA values from the OpenMP dialect op region and + terminates the region. The semantics of how the values are yielded is + defined by the parent operation. + If "omp.yield" has any operands, the operands must match the parent + operation's results. + }]; + + let arguments = (ins Variadic:$results); + + let assemblyFormat = [{ ( `(` $results^ `:` type($results) `)` )? attr-dict}]; +} + //===----------------------------------------------------------------------===// // 2.10.4 taskyield Construct //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -125,3 +125,41 @@ return } + +func @omp_wsloop(%lb : index, %ub : index, %step : index, + %data_var : memref, %linear_var : si32, %chunk_var : si32) -> () { + + // CHECK: "omp.wsloop"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) + "omp.wsloop" (%lb, %ub, %step, %data_var) ({ + omp.yield + }) {operand_segment_sizes = dense<[1,1,1,1,0,0,0,0,0]> : vector<9xi32>, collapse_val = 2, ordered_val = 1} : + (index, index, index, memref) -> () + + // CHECK: "omp.wsloop"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) + "omp.wsloop" (%lb, %lb, %ub, %ub, %step, %step, %data_var) ({ + omp.yield + }) {operand_segment_sizes = dense<[2,2,2,1,0,0,0,0,0]> : vector<9xi32>, collapse_val = 2, ordered_val = 1} : + (index, index, index, index, index, index, memref) -> () + + + // CHECK: "omp.wsloop"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) + "omp.wsloop" (%lb, %ub, %step, %data_var, %linear_var) ({ + omp.yield + }) {operand_segment_sizes = dense<[1,1,1,0,0,0,1,1,0]> : vector<9xi32>, schedule_val = "Static"} : + (index, index, index, memref, si32) -> () + + // CHECK: "omp.wsloop"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) + "omp.wsloop" (%lb, %ub, %step, %data_var, %data_var, %data_var, %data_var, %linear_var, %chunk_var) ({ + omp.yield + }) {operand_segment_sizes = dense<[1,1,1,1,1,1,1,1,1]> : vector<9xi32>, schedule_val = "Dynamic", collapse_val = 3, ordered_val = 2} : + (index, index, index, memref, memref, memref, memref, si32, si32) -> () + + // CHECK: "omp.wsloop"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) + "omp.wsloop" (%lb, %ub, %step, %data_var) ({ + omp.yield + }) {operand_segment_sizes = dense<[1,1,1,1,0,0,0,0,0]> : vector<9xi32>, nowait, schedule_val = "Auto"} : + (index, index, index, memref) -> () + + + return +}