diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h index 977949e399a53..6ac6a3116d40b 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h +++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h @@ -72,6 +72,9 @@ constexpr llvm::StringRef getOptionalAttrName() { return "fir.optional"; } /// Attribute to mark Fortran entities with the TARGET attribute. static constexpr llvm::StringRef getTargetAttrName() { return "fir.target"; } +/// Attribute to mark Fortran entities with the CUDA attribute. +static constexpr llvm::StringRef getCUDAAttrName() { return "fir.cuda_attr"; } + /// Attribute to mark that a function argument is a character dummy procedure. /// Character dummy procedure have special ABI constraints. static constexpr llvm::StringRef getCharacterProcedureDummyAttrName() { diff --git a/flang/include/flang/Optimizer/Support/Utils.h b/flang/include/flang/Optimizer/Support/Utils.h index b50f297a7d314..586701b4c54d1 100644 --- a/flang/include/flang/Optimizer/Support/Utils.h +++ b/flang/include/flang/Optimizer/Support/Utils.h @@ -273,6 +273,36 @@ inline void genMinMaxlocReductionLoop( builder.setInsertionPointAfter(ifMaskTrueOp); } +inline fir::CUDAAttributeAttr +getCUDAAttribute(mlir::MLIRContext *mlirContext, + std::optional cudaAttr) { + if (cudaAttr) { + fir::CUDAAttribute attr; + switch (*cudaAttr) { + case Fortran::common::CUDADataAttr::Constant: + attr = fir::CUDAAttribute::Constant; + break; + case Fortran::common::CUDADataAttr::Device: + attr = fir::CUDAAttribute::Device; + break; + case Fortran::common::CUDADataAttr::Managed: + attr = fir::CUDAAttribute::Managed; + break; + case Fortran::common::CUDADataAttr::Pinned: + attr = fir::CUDAAttribute::Pinned; + break; + case Fortran::common::CUDADataAttr::Shared: + attr = fir::CUDAAttribute::Shared; + break; + case Fortran::common::CUDADataAttr::Texture: + // Obsolete attribute + return {}; + } + return fir::CUDAAttributeAttr::get(mlirContext, attr); + } + return {}; +} + } // namespace fir #endif // FORTRAN_OPTIMIZER_SUPPORT_UTILS_H diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp index b007c958cb6b3..4c297ceffc536 100644 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -19,6 +19,7 @@ #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/InternalNames.h" +#include "flang/Optimizer/Support/Utils.h" #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" #include @@ -993,6 +994,10 @@ class Fortran::lower::CallInterfaceImpl { TODO(loc, "VOLATILE in procedure interface"); if (obj.attrs.test(Attrs::Target)) addMLIRAttr(fir::getTargetAttrName()); + if (obj.cudaDataAttr) + attrs.emplace_back( + mlir::StringAttr::get(&mlirContext, fir::getCUDAAttrName()), + fir::getCUDAAttribute(&mlirContext, obj.cudaDataAttr)); // TODO: intents that require special care (e.g finalization) diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index d57bdd448da3f..f14267f123421 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -37,6 +37,7 @@ #include "flang/Optimizer/HLFIR/HLFIROps.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Optimizer/Support/InternalNames.h" +#include "flang/Optimizer/Support/Utils.h" #include "flang/Semantics/runtime-type-info.h" #include "flang/Semantics/tools.h" #include "llvm/Support/Debug.h" @@ -1583,32 +1584,7 @@ fir::CUDAAttributeAttr Fortran::lower::translateSymbolCUDAAttribute( mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym) { std::optional cudaAttr = Fortran::semantics::GetCUDADataAttr(&sym); - if (cudaAttr) { - fir::CUDAAttribute attr; - switch (*cudaAttr) { - case Fortran::common::CUDADataAttr::Constant: - attr = fir::CUDAAttribute::Constant; - break; - case Fortran::common::CUDADataAttr::Device: - attr = fir::CUDAAttribute::Device; - break; - case Fortran::common::CUDADataAttr::Managed: - attr = fir::CUDAAttribute::Managed; - break; - case Fortran::common::CUDADataAttr::Pinned: - attr = fir::CUDAAttribute::Pinned; - break; - case Fortran::common::CUDADataAttr::Shared: - attr = fir::CUDAAttribute::Shared; - break; - case Fortran::common::CUDADataAttr::Texture: - // Obsolete attribute - return {}; - } - - return fir::CUDAAttributeAttr::get(mlirContext, attr); - } - return {}; + return fir::getCUDAAttribute(mlirContext, cudaAttr); } /// Map a symbol to its FIR address and evaluated specification expressions. diff --git a/flang/test/Lower/CUDA/cuda-data-attribute.cuf b/flang/test/Lower/CUDA/cuda-data-attribute.cuf index caa8ac7baff38..b02701bf3aea5 100644 --- a/flang/test/Lower/CUDA/cuda-data-attribute.cuf +++ b/flang/test/Lower/CUDA/cuda-data-attribute.cuf @@ -1,7 +1,7 @@ ! RUN: bbc -emit-hlfir -fcuda %s -o - | FileCheck %s ! RUN: bbc -emit-hlfir -fcuda %s -o - | fir-opt -convert-hlfir-to-fir | FileCheck %s --check-prefix=FIR -! Test lowering of CUDA attribute on local variables. +! Test lowering of CUDA attribute on variables. subroutine local_var_attrs real, constant :: rc @@ -20,3 +20,36 @@ end subroutine ! FIR: %{{.*}} = fir.declare %{{.*}} {cuda_attr = #fir.cuda, uniq_name = "_QFlocal_var_attrsErd"} : (!fir.ref) -> !fir.ref ! FIR: %{{.*}} = fir.declare %{{.*}} {cuda_attr = #fir.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFlocal_var_attrsErm"} : (!fir.ref>>) -> !fir.ref>> ! FIR: %{{.*}} = fir.declare %{{.*}} {cuda_attr = #fir.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFlocal_var_attrsErp"} : (!fir.ref>>) -> !fir.ref>> + +subroutine dummy_arg_constant(dc) + real, constant :: dc +end subroutine +! CHECK-LABEL: func.func @_QPdummy_arg_constant( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "dc", fir.cuda_attr = #fir.cuda} +! CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {cuda_attr = #fir.cuda, uniq_name = "_QFdummy_arg_constantEdc"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +subroutine dummy_arg_device(dd) + real, device :: dd +end subroutine +! CHECK-LABEL: func.func @_QPdummy_arg_device( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "dd", fir.cuda_attr = #fir.cuda}) { +! CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {cuda_attr = #fir.cuda, uniq_name = "_QFdummy_arg_deviceEdd"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +subroutine dummy_arg_managed(dm) + real, allocatable, managed :: dm +end subroutine +! CHECK-LABEL: func.func @_QPdummy_arg_managed( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>> {fir.bindc_name = "dm", fir.cuda_attr = #fir.cuda}) { +! CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {cuda_attr = #fir.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFdummy_arg_managedEdm"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + +subroutine dummy_arg_pinned(dp) + real, allocatable, pinned :: dp +end subroutine +! CHECK-LABEL: func.func @_QPdummy_arg_pinned( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>> {fir.bindc_name = "dp", fir.cuda_attr = #fir.cuda}) { +! CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {cuda_attr = #fir.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFdummy_arg_pinnedEdp"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + + + + +