[flang][cuda] Adding support for more atomic calls (#124671)

The PR follows the earlier
https://github.com/llvm/llvm-project/pull/123840 PR for atomic operation
support in CUF
This commit is contained in:
Renaud Kauffmann 2025-01-28 08:36:43 -08:00 committed by GitHub
parent df122fc734
commit 56a0a7f6d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 245 additions and 4 deletions

View File

@ -186,6 +186,13 @@ struct IntrinsicLibrary {
fir::ExtendedValue genAny(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genAtanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicAdd(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicAnd(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicOr(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicDec(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicInc(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicMax(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicMin(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genAtomicSub(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue
genCommandArgumentCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genAsind(mlir::Type, llvm::ArrayRef<mlir::Value>);

View File

@ -151,6 +151,22 @@ static constexpr IntrinsicHandler handlers[]{
{"atomicaddf", &I::genAtomicAdd, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicaddi", &I::genAtomicAdd, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicaddl", &I::genAtomicAdd, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicandi", &I::genAtomicAnd, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicdeci", &I::genAtomicDec, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicinci", &I::genAtomicInc, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicmaxd", &I::genAtomicMax, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicmaxf", &I::genAtomicMax, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicmaxi", &I::genAtomicMax, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicmaxl", &I::genAtomicMax, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicmind", &I::genAtomicMin, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicminf", &I::genAtomicMin, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicmini", &I::genAtomicMin, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicminl", &I::genAtomicMin, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicori", &I::genAtomicOr, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicsubd", &I::genAtomicSub, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicsubf", &I::genAtomicSub, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicsubi", &I::genAtomicSub, {{{"a", asAddr}, {"v", asValue}}}, false},
{"atomicsubl", &I::genAtomicSub, {{{"a", asAddr}, {"v", asValue}}}, false},
{"bessel_jn",
&I::genBesselJn,
{{{"n1", asValue}, {"n2", asValue}, {"x", asValue}}},
@ -2600,6 +2616,75 @@ mlir::Value IntrinsicLibrary::genAtomicAdd(mlir::Type resultType,
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicSub(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
mlir::LLVM::AtomicBinOp binOp =
mlir::isa<mlir::IntegerType>(args[1].getType())
? mlir::LLVM::AtomicBinOp::sub
: mlir::LLVM::AtomicBinOp::fsub;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicAnd(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
assert(mlir::isa<mlir::IntegerType>(args[1].getType()));
mlir::LLVM::AtomicBinOp binOp = mlir::LLVM::AtomicBinOp::_and;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicOr(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
assert(mlir::isa<mlir::IntegerType>(args[1].getType()));
mlir::LLVM::AtomicBinOp binOp = mlir::LLVM::AtomicBinOp::_or;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicDec(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
assert(mlir::isa<mlir::IntegerType>(args[1].getType()));
mlir::LLVM::AtomicBinOp binOp = mlir::LLVM::AtomicBinOp::udec_wrap;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicInc(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
assert(mlir::isa<mlir::IntegerType>(args[1].getType()));
mlir::LLVM::AtomicBinOp binOp = mlir::LLVM::AtomicBinOp::uinc_wrap;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicMax(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
mlir::LLVM::AtomicBinOp binOp =
mlir::isa<mlir::IntegerType>(args[1].getType())
? mlir::LLVM::AtomicBinOp::max
: mlir::LLVM::AtomicBinOp::fmax;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
mlir::Value IntrinsicLibrary::genAtomicMin(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
mlir::LLVM::AtomicBinOp binOp =
mlir::isa<mlir::IntegerType>(args[1].getType())
? mlir::LLVM::AtomicBinOp::min
: mlir::LLVM::AtomicBinOp::fmin;
return genAtomBinOp(builder, loc, binOp, args[0], args[1]);
}
// ASSOCIATED
fir::ExtendedValue
IntrinsicLibrary::genAssociated(mlir::Type resultType,

View File

@ -106,10 +106,10 @@ implicit none
real, intent(inout) :: address
real, value :: val
end function
attributes(device) pure real*8 function atomicaddd(address, val)
attributes(device) pure real(8) function atomicaddd(address, val)
!dir$ ignore_tkr (d) address, (d) val
real*8, intent(inout) :: address
real*8, value :: val
real(8), intent(inout) :: address
real(8), value :: val
end function
attributes(device) pure integer(8) function atomicaddl(address, val)
!dir$ ignore_tkr (d) address, (d) val
@ -117,6 +117,115 @@ implicit none
integer(8), value :: val
end function
end interface
public :: atomicadd
public :: atomicadd
interface atomicsub
attributes(device) pure integer function atomicsubi(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
attributes(device) pure real function atomicsubf(address, val)
!dir$ ignore_tkr (d) address, (d) val
real, intent(inout) :: address
real, value :: val
end function
attributes(device) pure real(8) function atomicsubd(address, val)
!dir$ ignore_tkr (d) address, (d) val
real(8), intent(inout) :: address
real(8), value :: val
end function
attributes(device) pure integer(8) function atomicsubl(address, val)
!dir$ ignore_tkr (d) address, (dk) val
integer(8), intent(inout) :: address
integer(8), value :: val
end function
end interface
public :: atomicsub
interface atomicmax
attributes(device) pure integer function atomicmaxi(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
attributes(device) pure real function atomicmaxf(address, val)
!dir$ ignore_tkr (d) address, (d) val
real, intent(inout) :: address
real, value :: val
end function
attributes(device) pure real(8) function atomicmaxd(address, val)
!dir$ ignore_tkr (d) address, (d) val
real(8), intent(inout) :: address
real(8), value :: val
end function
attributes(device) pure integer(8) function atomicmaxl(address, val)
!dir$ ignore_tkr (d) address, (dk) val
integer(8), intent(inout) :: address
integer(8), value :: val
end function
end interface
public :: atomicmax
interface atomicmin
attributes(device) pure integer function atomicmini(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
attributes(device) pure real function atomicminf(address, val)
!dir$ ignore_tkr (d) address, (d) val
real, intent(inout) :: address
real, value :: val
end function
attributes(device) pure real(8) function atomicmind(address, val)
!dir$ ignore_tkr (d) address, (d) val
real(8), intent(inout) :: address
real(8), value :: val
end function
attributes(device) pure integer(8) function atomicminl(address, val)
!dir$ ignore_tkr (d) address, (dk) val
integer(8), intent(inout) :: address
integer(8), value :: val
end function
end interface
public :: atomicmin
interface atomicand
attributes(device) pure integer function atomicandi(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
end interface
public :: atomicand
interface atomicor
attributes(device) pure integer function atomicori(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
end interface
public :: atomicor
interface atomicinc
attributes(device) pure integer function atomicinci(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
end interface
public :: atomicinc
interface atomicdec
attributes(device) pure integer function atomicdeci(address, val)
!dir$ ignore_tkr (d) address, (d) val
integer, intent(inout) :: address
integer, value :: val
end function
end interface
public :: atomicdec
end module

View File

@ -23,6 +23,26 @@ attributes(global) subroutine devsub()
al = atomicadd(al, 1_8)
af = atomicadd(af, 1.0_4)
ad = atomicadd(ad, 1.0_8)
ai = atomicsub(ai, 1_4)
al = atomicsub(al, 1_8)
af = atomicsub(af, 1.0_4)
ad = atomicsub(ad, 1.0_8)
ai = atomicmax(ai, 1_4)
al = atomicmax(al, 1_8)
af = atomicmax(af, 1.0_4)
ad = atomicmax(ad, 1.0_8)
ai = atomicmin(ai, 1_4)
al = atomicmin(al, 1_8)
af = atomicmin(af, 1.0_4)
ad = atomicmin(ad, 1.0_8)
ai = atomicand(ai, 1_4)
ai = atomicor(ai, 1_4)
ai = atomicinc(ai, 1_4)
ai = atomicdec(ai, 1_4)
end
! CHECK-LABEL: func.func @_QPdevsub() attributes {cuf.proc_attr = #cuf.cuda_proc<global>}
@ -39,6 +59,26 @@ end
! CHECK: %{{.*}} = llvm.atomicrmw fadd %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f32
! CHECK: %{{.*}} = llvm.atomicrmw fadd %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f64
! CHECK: %{{.*}} = llvm.atomicrmw sub %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: %{{.*}} = llvm.atomicrmw sub %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i64
! CHECK: %{{.*}} = llvm.atomicrmw fsub %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f32
! CHECK: %{{.*}} = llvm.atomicrmw fsub %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f64
! CHECK: %{{.*}} = llvm.atomicrmw max %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: %{{.*}} = llvm.atomicrmw max %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i64
! CHECK: %{{.*}} = llvm.atomicrmw fmax %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f32
! CHECK: %{{.*}} = llvm.atomicrmw fmax %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f64
! CHECK: %{{.*}} = llvm.atomicrmw min %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: %{{.*}} = llvm.atomicrmw min %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i64
! CHECK: %{{.*}} = llvm.atomicrmw fmin %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f32
! CHECK: %{{.*}} = llvm.atomicrmw fmin %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, f64
! CHECK: %{{.*}} = llvm.atomicrmw _and %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: %{{.*}} = llvm.atomicrmw _or %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: %{{.*}} = llvm.atomicrmw uinc_wrap %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: %{{.*}} = llvm.atomicrmw udec_wrap %{{.*}}, %{{.*}} seq_cst : !llvm.ptr, i32
! CHECK: func.func private @llvm.nvvm.barrier0()
! CHECK: func.func private @__syncwarp(!fir.ref<i32> {cuf.data_attr = #cuf.cuda<device>}) attributes {cuf.proc_attr = #cuf.cuda_proc<device>, fir.bindc_name = "__syncwarp", fir.proc_attrs = #fir.proc_attrs<bind_c>}
! CHECK: func.func private @llvm.nvvm.membar.gl()