This patch supports the atomic construct (read and write) following
section 2.17.7 of OpenMP 5.0 standard. Also added tests and
verifier for the same.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
---|---|---|
432 | Are we taking care of capture ,compare ,fail(seq_cst | acquire | relaxed) |
Thanks for reviewing this patch @abidmalikwaterloo.
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
---|---|---|
432 | I am sorry, I did not understand it correctly. The omp.atomic.capture and omp.atomic.update operations will be released as a separate patch to avoid too many changes in one patch (and ease of review). The restriction on memory ordering clause values is verified in the verifiers for these operations independently. Let me know if this wasn't your concern. |
Thanks @shraiysh for this patch. Have a few comments.
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
---|---|---|
63 | Is it possible to autogen this from OMP.td? This capability was introduced as part of https://reviews.llvm.org/D84347. If you can define ClauseVal entries in llvm/include/llvm/Frontend/OpenMP/OMP.td then these entries will be autogenerated. Example for proc_bind given below. def OMP_PROC_BIND_master : ClauseVal<"master",2,1> {} let clangClass = "OMPProcBindClause"; let flangClass = "OmpProcBindClause"; let enumClauseValue = "ProcBindKind"; let allowedClauseValues = [ OMP_PROC_BIND_master, OMP_PROC_BIND_close, OMP_PROC_BIND_spread, OMP_PROC_BIND_default, OMP_PROC_BIND_unknown ]; } | |
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | ||
1163 | Consider reducing this to "memory-order must not be acq_rel or release for atomic reads". | |
1201 | Is the order of hint and memory_order different from Read? | |
mlir/test/Dialect/OpenMP/invalid.mlir | ||
349 | should we have tests for allowed once clauses? | |
444 | Nit: Add newline |
Thanks for the review @kiranchandramohan. Addressed comments.
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
---|---|---|
63 | I don't think it can be done because in OMP.td, these values are treated like independent clauses. There is no unified "memory ordering" clause in that file. Let me know if I am missing something here. |
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
---|---|---|
63 | You can still define the enum in the file and have it generated for you by the current back-end. |
Moved Memory Order clause to OMP.td.
Thanks for the suggestion @kiranchandramohan @clementval. Addressed comments
The Synchronization Hint functions have been moved above because they are required in parseClauses. I will add it as an NFC and then rebase here, because right now reviewing this (the way it is showing differences) will be hard.
Hi all, the NFC has been merged, and the build is passing. This is ready for review now.
The patch looks OK. I just wanted to discuss the syntax also. Would any of the following be better?
%8 = omp.atomic.read %addr : memref<i32> -> i32 hint(speculative, contended) memory_order(seq_cst)
%8 = omp.atomic.read %addr hint(speculative, contended) memory_order(seq_cst) : memref<i32> -> i32
%8 = omp.atomic.read %addr {hint(speculative, contended) memory_order(seq_cst)} : memref<i32> -> i32
Hi @kiranchandramohan. Thanks for the review.
%8 = omp.atomic.read %addr : memref<i32> -> i32 hint(speculative, contended) memory_order(seq_cst)
This cannot be done because the statement ends at optional clauses. This is dangerous in the following situation where parser will try to match return as a clause instead of a new instruction. I had first actually tried it this way. Let me know if there is something that can be done to avoid this problem with this syntax.
%8 = omp.atomic.read %addr : memref<i32> -> i32 memory_order(seq_cst) return
We can try one of remaining two. I do not have a preference between these three:
%8 = omp.atomic.read %addr hint(speculative, contended) memory_order(seq_cst) : memref<i32> -> i32%8 = omp.atomic.read %addr {hint(speculative, contended) memory_order(seq_cst)} : memref<i32> -> i32
%8 = omp.atomic.read hint(speculative, contended) memory_order(seq_cst) %addr : memref<i32> -> i32 // current syntax
LGTM.
My preference is the following one. If you agree then please make the change, otherwise, you can keep it as is. Also, wait a couple of days to see whether others have comments.
%8 = omp.atomic.read %addr hint(speculative, contended) memory_order(seq_cst) : memref<i32> -> i32
clang/lib/CodeGen/CGStmtOpenMP.cpp | ||
---|---|---|
5993 ↗ | (On Diff #381772) | The memory_order clause in clang side is not handled in this patch. Maybe leaving the error is better since users will know it is not supported yet in clang. |
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
430 | How do you plan to handle synchronization between the threads if there is no region in atomic read op? Will there be one implicit kmpc_flush function call before !$omp end atomic? If yes, it is easier to find to location of emiting kmpc_flush if we have one region here. Please let me know if I am wrong. | |
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | ||
1124 | Please also check OpenMP 5.1 Spec. It seems that acq_rel is allowed if read clause is specified. |
clang/lib/CodeGen/CGStmtOpenMP.cpp | ||
---|---|---|
5993 ↗ | (On Diff #381772) |
Sorry. Please ignore this comment. |
Thanks for the review @peixin.
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | ||
---|---|---|
430 | Yes - there will be a kmpc_flush call, but OpenMP Dialect does not have to worry about that. OpenMP IR Builder takes care of flushes in the function createAtomicRead. | |
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | ||
1124 | Thanks for this observation, I will update it with the 5.1 standard. |
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | ||
---|---|---|
1124 | Just to be clear, the OpenMP 5.1 specification changes atomic by a considerable amount (especially it breaks capture into two sub-constructs (coming as a separate patch)) and AFAIK we are targeting OpenMP 5.0. So, do I still update it to the 5.1 standard (this will affect further implementation of atomic construct)? |
Is it possible to autogen this from OMP.td? This capability was introduced as part of https://reviews.llvm.org/D84347.
If you can define ClauseVal entries in llvm/include/llvm/Frontend/OpenMP/OMP.td then these entries will be autogenerated. Example for proc_bind given below.
def OMP_PROC_BIND_master : ClauseVal<"master",2,1> {}
def OMP_PROC_BIND_close : ClauseVal<"close",3,1> {}
def OMP_PROC_BIND_spread : ClauseVal<"spread",4,1> {}
def OMP_PROC_BIND_default : ClauseVal<"default",5,0> {}
def OMP_PROC_BIND_unknown : ClauseVal<"unknown",6,0> { let isDefault = 1; }
def OMPC_ProcBind : Clause<"proc_bind"> {
}