@@ -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