Skip to content

Commit dae12f1

Browse files
committed
Add comment explaining the implicit casting
1 parent d00abc7 commit dae12f1

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2891,13 +2891,39 @@ static void genAtomicRead(lower::AbstractConverter &converter,
28912891
*semantics::GetExpr(assignmentStmtVariable), stmtCtx));
28922892

28932893
if (fromAddress.getType() != toAddress.getType()) {
2894-
// Emit an implicit cast
2894+
// Emit an implicit cast.
2895+
// Different yet compatible types on omp.atomic.read constitute valid
2896+
// Fortran. The OMPIRBuilder will emit atomic instructions (on primitive
2897+
// types) and
2898+
// __atomic_load libcall (on complex type) without explicitly converting
2899+
// between such compatible types, leading to execute issues. The
2900+
// OMPIRBuilder relies on the frontend to resolve such inconsistencies
2901+
// between omp.atomic.read operand types. Inconsistency between operand
2902+
// types in omp.atomic.write are resolved through implicit casting by use of
2903+
// typed assignment (i.e. `evaluate::Assignment`). However, use of typed
2904+
// assignment in omp.atomic.read (of form `v = x`) leads to an unsafe,
2905+
// non-atomic load of `x` into a temporary `alloca`, followed by an atomic
2906+
// read of form `v = alloca`. Hence, perform a custom implicit cast.
2907+
2908+
// For an atomic read of form `v = x` that would (without implicit casting)
2909+
// lower to `omp.atomic.read %v = %x : !fir.ref<type1>, !fir.ref<typ2>,
2910+
// type2`, this implicit casting will generate the following FIR: %alloca =
2911+
// fir.alloca type2
2912+
// omp.atomic.read %alloca = %x : !fir.ref<type2>, !fir.ref<type2>,
2913+
//type2 %load = fir.load %alloca : !fir.ref<type2> %cvt = fir.convert %load
2914+
//: (type2) -> type1 fir.store %cvt to %v : !fir.ref<type1>
2915+
2916+
// These sequence of operations is thread-safe since each thread allocates
2917+
// the `alloca` in its stack, and performs `%alloca = %x` atomically. Once
2918+
// safely read, each thread performs the implicit cast on the local alloca,
2919+
// and writes the final result to `%v`.
28952920
mlir::Type toType = fir::unwrapRefType(toAddress.getType());
28962921
mlir::Type fromType = fir::unwrapRefType(fromAddress.getType());
28972922
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
28982923
auto oldIP = builder.saveInsertionPoint();
28992924
builder.setInsertionPointToStart(builder.getAllocaBlock());
2900-
mlir::Value alloca = builder.create<fir::AllocaOp>(loc, fromType);
2925+
mlir::Value alloca = builder.create<fir::AllocaOp>(
2926+
loc, fromType); // Thread scope `alloca` to atomically read `%x`.
29012927
builder.restoreInsertionPoint(oldIP);
29022928
genAtomicCaptureStatement(converter, fromAddress, alloca,
29032929
leftHandClauseList, rightHandClauseList,

0 commit comments

Comments
 (0)