https://github.com/anchuraj created https://github.com/llvm/llvm-project/pull/143441
Atomic Control Options are used to specify architectural characteristics to help lowering of atomic operations. The options used are: `-f[no-]atomic-remote-memory`, `-f[no-]atomic-fine-grained-memory`, `-f[no-]atomic-ignore-denormal-mode`. Legacy option `-m[no-]unsafe-fp-atomics` is aliased to `-f[no-]ignore-denormal-mode`. More details can be found in https://github.com/llvm/llvm-project/pull/102569. This PR implements the frontend support for these options with OpenMP atomic in flang >From 51c6a6a9b1f58f37df3eb1b6988b62f489c8f4b8 Mon Sep 17 00:00:00 2001 From: Anchu Rajendran <asudh...@amd.com> Date: Wed, 4 Jun 2025 15:12:49 -0500 Subject: [PATCH] [flang][flang-driver] atomic control support --- clang/include/clang/Driver/Options.td | 22 +++++----- flang/include/flang/Frontend/TargetOptions.h | 5 +++ .../Optimizer/Dialect/Support/FIRContext.h | 14 +++++++ flang/lib/Frontend/CompilerInvocation.cpp | 12 ++++++ flang/lib/Lower/Bridge.cpp | 6 +++ flang/lib/Lower/OpenMP/OpenMP.cpp | 7 +++- .../Optimizer/Dialect/Support/FIRContext.cpp | 40 +++++++++++++++++++ .../Lower/OpenMP/atomic-control-options.f90 | 37 +++++++++++++++++ .../mlir/Dialect/OpenMP/OpenMPAttrDefs.td | 14 +++++++ mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | 8 ++-- mlir/test/Dialect/OpenMP/ops.mlir | 9 +++++ 11 files changed, 159 insertions(+), 15 deletions(-) create mode 100644 flang/test/Lower/OpenMP/atomic-control-options.f90 diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index fd6deb22d404e..c6d8f9106341a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2299,21 +2299,21 @@ def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>, defm atomic_remote_memory : BoolFOption<"atomic-remote-memory", LangOpts<"AtomicRemoteMemory">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], "May have">, - NegFlag<SetFalse, [], [ClangOption], "Assume no">, - BothFlags<[], [ClangOption], " atomic operations on remote memory">>; + PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "May have">, + NegFlag<SetFalse, [], [ClangOption, FlangOption], "Assume no">, + BothFlags<[], [ClangOption, FlangOption], " atomic operations on remote memory">>; defm atomic_fine_grained_memory : BoolFOption<"atomic-fine-grained-memory", LangOpts<"AtomicFineGrainedMemory">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], "May have">, - NegFlag<SetFalse, [], [ClangOption], "Assume no">, - BothFlags<[], [ClangOption], " atomic operations on fine-grained memory">>; + PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "May have">, + NegFlag<SetFalse, [], [ClangOption, FlangOption], "Assume no">, + BothFlags<[], [ClangOption, FlangOption], " atomic operations on fine-grained memory">>; defm atomic_ignore_denormal_mode : BoolFOption<"atomic-ignore-denormal-mode", LangOpts<"AtomicIgnoreDenormalMode">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], "Allow">, - NegFlag<SetFalse, [], [ClangOption], "Disallow">, - BothFlags<[], [ClangOption], " atomic operations to ignore denormal mode">>; + PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "Allow">, + NegFlag<SetFalse, [], [ClangOption, FlangOption], "Disallow">, + BothFlags<[], [ClangOption, FlangOption], " atomic operations to ignore denormal mode">>; defm memory_profile : OptInCC1FFlag<"memory-profile", "Enable", "Disable", " heap memory profiling">; def fmemory_profile_EQ : Joined<["-"], "fmemory-profile=">, @@ -5270,9 +5270,9 @@ defm amdgpu_precise_memory_op " precise memory mode (AMDGPU only)">; def munsafe_fp_atomics : Flag<["-"], "munsafe-fp-atomics">, - Visibility<[ClangOption, CC1Option]>, Alias<fatomic_ignore_denormal_mode>; + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, Alias<fatomic_ignore_denormal_mode>; def mno_unsafe_fp_atomics : Flag<["-"], "mno-unsafe-fp-atomics">, - Visibility<[ClangOption]>, Alias<fno_atomic_ignore_denormal_mode>; + Visibility<[ClangOption, FlangOption]>, Alias<fno_atomic_ignore_denormal_mode>; def faltivec : Flag<["-"], "faltivec">, Group<f_Group>; def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>; diff --git a/flang/include/flang/Frontend/TargetOptions.h b/flang/include/flang/Frontend/TargetOptions.h index 002d8d158abd4..26256fd775f11 100644 --- a/flang/include/flang/Frontend/TargetOptions.h +++ b/flang/include/flang/Frontend/TargetOptions.h @@ -53,6 +53,11 @@ class TargetOptions { /// Print verbose assembly bool asmVerbose = false; + + /// Atomic Control Options for AMD GPU + bool amdgpuIgnoreDenormalMode = false; + bool amdgpuRemoteMemory = false; + bool amdgpuFineGrainedMemory = false; }; } // end namespace Fortran::frontend diff --git a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h index 2df14f83c11e1..ac563bcc402c7 100644 --- a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h +++ b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h @@ -58,10 +58,24 @@ void setTargetCPU(mlir::ModuleOp mod, llvm::StringRef cpu); /// Get the target CPU string from the Module or return a null reference. llvm::StringRef getTargetCPU(mlir::ModuleOp mod); +// Setters and Getters for atomic control options +void setAmdgpuIgnoreDenormalMode(mlir::ModuleOp mod); +bool getAmdgpuIgnoreDenormalMode(mlir::ModuleOp mod); +void setAmdgpuFineGrainedMemory(mlir::ModuleOp mod); +bool getAmdgpuFineGrainedMemory(mlir::ModuleOp mod); +void setAmdgpuRemoteMemory(mlir::ModuleOp mod); +bool getAmdgpuRemoteMemory(mlir::ModuleOp mod); + /// Set the tune CPU for the module. `cpu` must not be deallocated while /// module `mod` is still live. void setTuneCPU(mlir::ModuleOp mod, llvm::StringRef cpu); +// set Atomic control options for amd gpu. +void setAmdgpuAtomicControlOptions(mlir::ModuleOp mod, + bool amdgpuIgnoreDenormalMode, + bool amdgpuNoFineGrainedMemory, + bool amdgpuNoRemoteMemory); + /// Get the tune CPU string from the Module or return a null reference. llvm::StringRef getTuneCPU(mlir::ModuleOp mod); diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 89aaee9f13853..78d44d76744dc 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -494,6 +494,18 @@ static void parseTargetArgs(TargetOptions &opts, llvm::opt::ArgList &args) { args.getLastArg(clang::driver::options::OPT_triple)) opts.triple = a->getValue(); + if (llvm::Triple(opts.triple).isAMDGPU()) { + opts.amdgpuIgnoreDenormalMode = args.hasFlag( + clang::driver::options::OPT_fatomic_ignore_denormal_mode, + clang::driver::options::OPT_fno_atomic_ignore_denormal_mode, false); + opts.amdgpuFineGrainedMemory = args.hasFlag( + clang::driver::options::OPT_fatomic_fine_grained_memory, + clang::driver::options::OPT_fno_atomic_fine_grained_memory, false); + opts.amdgpuRemoteMemory = args.hasFlag( + clang::driver::options::OPT_fatomic_remote_memory, + clang::driver::options::OPT_fno_atomic_remote_memory, false); + } + if (const llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_target_cpu)) opts.cpu = a->getValue(); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 64b16b3abe991..b045556565613 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -6648,6 +6648,12 @@ Fortran::lower::LoweringBridge::LoweringBridge( fir::setKindMapping(*module, kindMap); fir::setTargetCPU(*module, targetMachine.getTargetCPU()); fir::setTuneCPU(*module, targetOpts.cpuToTuneFor); + if (targetOpts.amdgpuIgnoreDenormalMode) + fir::setAmdgpuIgnoreDenormalMode(*module); + if (targetOpts.amdgpuFineGrainedMemory) + fir::setAmdgpuFineGrainedMemory(*module); + if (targetOpts.amdgpuRemoteMemory) + fir::setAmdgpuRemoteMemory(*module); fir::setTargetFeatures(*module, targetMachine.getTargetFeatureString()); fir::support::setMLIRDataLayout(*module, targetMachine.createDataLayout()); fir::setIdent(*module, Fortran::common::getFlangFullVersion()); diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 6892e571e62a3..bd09073100f1d 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -2911,8 +2911,13 @@ static void genAtomicUpdateStatement( if (rightHandClauseList) genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, memoryOrder); + auto module = firOpBuilder.getModule(); + auto atomicControlAttr = mlir::omp::AtomicControlAttr::get( + firOpBuilder.getContext(), fir::getAmdgpuIgnoreDenormalMode(module), + fir::getAmdgpuFineGrainedMemory(module), + fir::getAmdgpuRemoteMemory(module)); atomicUpdateOp = firOpBuilder.create<mlir::omp::AtomicUpdateOp>( - currentLocation, lhsAddr, hint, memoryOrder); + currentLocation, lhsAddr, atomicControlAttr, hint, memoryOrder); processOmpAtomicTODO(varType, loc); diff --git a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp index 01c0be66d1ecc..b961793dbdfd5 100644 --- a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp +++ b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp @@ -88,6 +88,46 @@ void fir::setTuneCPU(mlir::ModuleOp mod, llvm::StringRef cpu) { mod->setAttr(tuneCpuName, mlir::StringAttr::get(ctx, cpu)); } +static constexpr const char *amdgpuIgnoreDenormalModeName = + "fir.amdgpu.ignore.denormal.mode"; +void fir::setAmdgpuIgnoreDenormalMode(mlir::ModuleOp mod) { + auto *ctx = mod.getContext(); + mod->setAttr(amdgpuIgnoreDenormalModeName, mlir::UnitAttr::get(ctx)); +} + +bool fir::getAmdgpuIgnoreDenormalMode(mlir::ModuleOp mod) { + if (auto attr = + mod->getAttrOfType<mlir::UnitAttr>(amdgpuIgnoreDenormalModeName)) + return true; + return false; +} + +static constexpr const char *amdgpuFineGrainedMemoryName = + "fir.amdgpu.fine.grained.memory"; +void fir::setAmdgpuFineGrainedMemory(mlir::ModuleOp mod) { + auto *ctx = mod.getContext(); + mod->setAttr(amdgpuFineGrainedMemoryName, mlir::UnitAttr::get(ctx)); +} + +bool fir::getAmdgpuFineGrainedMemory(mlir::ModuleOp mod) { + if (auto attr = + mod->getAttrOfType<mlir::UnitAttr>(amdgpuFineGrainedMemoryName)) + return true; + return false; +} +static constexpr const char *amdgpuRemoteMemoryName = + "fir.amdgpu.remote.memory"; +void fir::setAmdgpuRemoteMemory(mlir::ModuleOp mod) { + auto *ctx = mod.getContext(); + mod->setAttr(amdgpuRemoteMemoryName, mlir::UnitAttr::get(ctx)); +} + +bool fir::getAmdgpuRemoteMemory(mlir::ModuleOp mod) { + if (auto attr = mod->getAttrOfType<mlir::UnitAttr>(amdgpuRemoteMemoryName)) + return true; + return false; +} + llvm::StringRef fir::getTuneCPU(mlir::ModuleOp mod) { if (auto attr = mod->getAttrOfType<mlir::StringAttr>(tuneCpuName)) return attr.getValue(); diff --git a/flang/test/Lower/OpenMP/atomic-control-options.f90 b/flang/test/Lower/OpenMP/atomic-control-options.f90 new file mode 100644 index 0000000000000..1eb0f617f365e --- /dev/null +++ b/flang/test/Lower/OpenMP/atomic-control-options.f90 @@ -0,0 +1,37 @@ +! RUN: %flang_fc1 -emit-hlfir -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-device -munsafe-fp-atomics %s -o - | FileCheck -check-prefix=UNSAFE-FP-ATOMICS %s +! RUN: %flang_fc1 -emit-hlfir -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-device -fatomic-ignore-denormal-mode %s -o - | FileCheck -check-prefix=IGNORE-DENORMAL %s +! RUN: %flang_fc1 -emit-hlfir -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-device -fatomic-fine-grained-memory %s -o - | FileCheck -check-prefix=FINE-GRAINED-MEMORY %s +! RUN: %flang_fc1 -emit-hlfir -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-device -fatomic-remote-memory %s -o - | FileCheck -check-prefix=REMOTE-MEMORY %s +program test + implicit none + integer :: A, B, threads + threads = 128 + A = 0 + B = 0 + !UNSAFE-FP-ATOMICS: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !UNSAFE-FP-ATOMICS: } {atomic_control = #omp.atomic_control<amdgpu_ignore_denormal_mode = true>} + !IGNORE-DENORMAL: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !IGNORE-DENORMAL: } {atomic_control = #omp.atomic_control<amdgpu_ignore_denormal_mode = true>} + !FINE-GRAINED-MEMORY: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !FINE-GRAINED-MEMORY: } {atomic_control = #omp.atomic_control<amdgpu_fine_grained_memory = true>} + !REMOTE-MEMORY: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !REMOTE-MEMORY: } {atomic_control = #omp.atomic_control<amdgpu_remote_memory = true>} + !$omp target parallel num_threads(threads) + !$omp atomic + A = A + 1 + !$omp end target parallel + !UNSAFE-FP-ATOMICS: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !UNSAFE-FP-ATOMICS: } {atomic_control = #omp.atomic_control<amdgpu_ignore_denormal_mode = true>} + !IGNORE-DENORMAL: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !IGNORE-DENORMAL: } {atomic_control = #omp.atomic_control<amdgpu_ignore_denormal_mode = true>} + !FINE-GRAINED-MEMORY: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !FINE-GRAINED-MEMORY: } {atomic_control = #omp.atomic_control<amdgpu_fine_grained_memory = true>} + !REMOTE-MEMORY: omp.atomic.update %{{.*}} : !fir.ref<i32> { + !REMOTE-MEMORY: } {atomic_control = #omp.atomic_control<amdgpu_remote_memory = true>} + !$omp target parallel num_threads(threads) + !$omp atomic capture + A = A + B + B = A + !$omp end atomic + !$omp end target parallel +end program test diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td index 704d0b2220e8a..84887dfd2c6f9 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td @@ -54,6 +54,20 @@ def FlagsAttr : OpenMP_Attr<"Flags", "flags"> { let assemblyFormat = "`<` struct(params) `>`"; } +//===----------------------------------------------------------------------===// +// AtomicControlAttr +//===----------------------------------------------------------------------===// + +// Runtime library flags attribute that holds information for lowering to LLVM. +def AtomicControlAttr : OpenMP_Attr<"AtomicControl", "atomic_control"> { + let parameters = + (ins DefaultValuedParameter<"bool", "false">:$amdgpu_ignore_denormal_mode, + DefaultValuedParameter<"bool", "false">:$amdgpu_fine_grained_memory, + DefaultValuedParameter<"bool", "false">:$amdgpu_remote_memory); + + let assemblyFormat = "`<` struct(params) `>`"; +} + //===----------------------------------------------------------------------===// // TaskDependArrayAttr //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td index 036c6a6e350a8..d7d14e96233ae 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -1543,9 +1543,11 @@ def AtomicUpdateOp : OpenMP_Op<"atomic.update", traits = [ operations. }] # clausesDescription; - let arguments = !con((ins Arg<OpenMP_PointerLikeType, - "Address of variable to be updated", - [MemRead, MemWrite]>:$x), clausesArgs); + let arguments = !con( + (ins Arg<OpenMP_PointerLikeType, + "Address of variable to be updated", [MemRead, MemWrite]>:$x, + OptionalAttr<AtomicControlAttr>:$atomic_control), + clausesArgs); // Override region definition. let regions = (region SizedRegion<1>:$region); diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir index 47cfc5278a5d0..e377b7aab3e43 100644 --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -1562,6 +1562,15 @@ func.func @omp_atomic_update(%x : memref<i32>, %expr : i32, %xBool : memref<i1>, omp.yield(%newval : i32) } + // CHECK: omp.atomic.update %[[X]] : memref<i32> { + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: omp.yield(%{{.+}} : i32) + // CHECK-NEXT: } {atomic_control_attr = #omp.atomic_control<amdgpu_ignore_denormal_mode = true, amdgpu_fine_grained_memory = true, amdgpu_remote_memory = true>} + omp.atomic.update %x : memref<i32> { + ^bb0(%xval:i32): + omp.yield(%const:i32) + } {atomic_control_attr = #omp.atomic_control<amdgpu_ignore_denormal_mode = true, amdgpu_fine_grained_memory = true, amdgpu_remote_memory = true>} + return } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits