Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang][cuda] Implicitly load cudadevice module in device/global subprogram #92038

Merged
merged 7 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion flang/include/flang/Semantics/semantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,10 @@ class SemanticsContext {
void UseFortranBuiltinsModule();
const Scope *GetBuiltinsScope() const { return builtinsScope_; }

void UsePPCBuiltinTypesModule();
const Scope &GetCUDABuiltinsScope();
const Scope &GetCUDADeviceScope();

void UsePPCBuiltinTypesModule();
void UsePPCBuiltinsModule();
Scope *GetPPCBuiltinTypesScope() { return ppcBuiltinTypesScope_; }
const Scope *GetPPCBuiltinsScope() const { return ppcBuiltinsScope_; }
Expand Down Expand Up @@ -292,6 +294,7 @@ class SemanticsContext {
const Scope *builtinsScope_{nullptr}; // module __Fortran_builtins
Scope *ppcBuiltinTypesScope_{nullptr}; // module __Fortran_PPC_types
std::optional<const Scope *> cudaBuiltinsScope_; // module __CUDA_builtins
std::optional<const Scope *> cudaDeviceScope_; // module cudadevice
const Scope *ppcBuiltinsScope_{nullptr}; // module __ppc_intrinsics
std::list<parser::Program> modFileParseTrees_;
std::unique_ptr<CommonBlockMap> commonBlockMap_;
Expand Down
20 changes: 20 additions & 0 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3797,6 +3797,26 @@ bool SubprogramVisitor::Pre(const parser::PrefixSpec::Attributes &attrs) {
subp->set_cudaSubprogramAttrs(attr);
}
}
if (auto attrs{subp->cudaSubprogramAttrs()}) {
if (*attrs == common::CUDASubprogramAttrs::Global ||
*attrs == common::CUDASubprogramAttrs::Device) {
const Scope &scope{currScope()};
const Scope *mod{FindModuleContaining(scope)};
if (mod && mod->GetName().value() == "cudadevice") {
return false;
}
// Implicitly USE the cudadevice module by copying its symbols in the
// current scope.
const Scope &cudaDeviceScope{context().GetCUDADeviceScope()};
for (auto sym : cudaDeviceScope.GetSymbols()) {
if (!currScope().FindSymbol(sym->name())) {
auto &localSymbol{MakeSymbol(sym->name())};
clementval marked this conversation as resolved.
Show resolved Hide resolved
localSymbol.set_details(UseDetails{sym->name(), *sym});
localSymbol.flags() = sym->flags();
}
}
}
}
}
return false;
}
Expand Down
8 changes: 8 additions & 0 deletions flang/lib/Semantics/semantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,14 @@ const Scope &SemanticsContext::GetCUDABuiltinsScope() {
return **cudaBuiltinsScope_;
}

const Scope &SemanticsContext::GetCUDADeviceScope() {
if (!cudaDeviceScope_) {
cudaDeviceScope_ = GetBuiltinModule("cudadevice");
CHECK(cudaDeviceScope_.value() != nullptr);
}
return **cudaDeviceScope_;
}

void SemanticsContext::UsePPCBuiltinsModule() {
if (ppcBuiltinsScope_ == nullptr) {
ppcBuiltinsScope_ = GetBuiltinModule("__ppc_intrinsics");
Expand Down
74 changes: 74 additions & 0 deletions flang/module/cudadevice.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
!===-- module/cudedevice.f90 -----------------------------------------------===!
!
! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
! See https://llvm.org/LICENSE.txt for license information.
! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
!
!===------------------------------------------------------------------------===!

! CUDA Fortran procedures available in device subprogram

module cudadevice
implicit none

! Set PRIVATE by default to explicitly only export what is meant
! to be exported by this MODULE.
private

! Synchronization Functions

interface
attributes(device) subroutine syncthreads()
end subroutine
end interface
public :: syncthreads

interface
attributes(device) integer function syncthreads_and(value)
integer :: value
end function
end interface
public :: syncthreads_and

interface
attributes(device) integer function syncthreads_count(value)
integer :: value
end function
end interface
public :: syncthreads_count

interface
attributes(device) integer function syncthreads_or(value)
integer :: value
end function
end interface
public :: syncthreads_or

interface
attributes(device) subroutine syncwarp(mask)
integer :: mask
end subroutine
end interface
public :: syncwarp

! Memory Fences

interface
attributes(device) subroutine threadfence()
end subroutine
end interface
public :: threadfence

interface
attributes(device) subroutine threadfence_block()
end subroutine
end interface
public :: threadfence_block

interface
attributes(device) subroutine threadfence_system()
end subroutine
end interface
public :: threadfence_system

end module
35 changes: 35 additions & 0 deletions flang/test/Semantics/cuf-device-procedures01.cuf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
! RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s

! Test CUDA Fortran intrinsic can pass semantic

attributes(global) subroutine devsub()
implicit none
integer :: ret

! 3.6.4. Synchronization Functions
call syncthreads()
call syncwarp(1)
call threadfence()
call threadfence_block()
call threadfence_system()
ret = syncthreads_and(1)
ret = syncthreads_count(1)
ret = syncthreads_or(1)
end

! CHECK-LABEL: Subprogram scope: devsub
! CHECK: syncthreads (Subroutine): Use from syncthreads in cudadevice
! CHECK: syncthreads_and (Function): Use from syncthreads_and in cudadevice
! CHECK: syncthreads_count (Function): Use from syncthreads_count in cudadevice
! CHECK: syncthreads_or (Function): Use from syncthreads_or in cudadevice
! CHECK: syncwarp (Subroutine): Use from syncwarp in cudadevice
! CHECK: threadfence (Subroutine): Use from threadfence in cudadevice
! CHECK: threadfence_block (Subroutine): Use from threadfence_block in cudadevice
! CHECK: threadfence_system (Subroutine): Use from threadfence_system in cudadevice

subroutine host()
call syncthreads()
end subroutine

! CHECK-LABEL: Subprogram scope: host
! CHECK: syncthreads, EXTERNAL: HostAssoc{{$}}
17 changes: 17 additions & 0 deletions flang/test/Semantics/cuf-device-procedures02.cuf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
! RUN: %python %S/test_errors.py %s %flang_fc1

module dev
integer, device :: syncthreads

contains

attributes(device) subroutine sub1()
syncthreads = 1 ! syncthreads not overwritten by cudadevice
end subroutine

attributes(global) subroutine sub2()
!ERROR: 'threadfence' is use-associated from module 'cudadevice' and cannot be re-declared
integer :: threadfence
end subroutine
end module

11 changes: 7 additions & 4 deletions flang/tools/f18/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(MODULES
"__ppc_intrinsics"
"mma"
"__cuda_builtins"
"cudadevice"
"ieee_arithmetic"
"ieee_exceptions"
"ieee_features"
Expand All @@ -26,11 +27,14 @@ set(MODULES
if (NOT CMAKE_CROSSCOMPILING)
foreach(filename ${MODULES})
set(depends "")
set(opts "")
if(${filename} STREQUAL "__fortran_builtins" OR
${filename} STREQUAL "__ppc_types")
elseif(${filename} STREQUAL "__ppc_intrinsics" OR
${filename} STREQUAL "mma")
set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__ppc_types.mod)
elseif(${filename} STREQUAL "cudadevice")
set(opts "-xcuda")
clementval marked this conversation as resolved.
Show resolved Hide resolved
else()
set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__fortran_builtins.mod)
if(NOT ${filename} STREQUAL "__fortran_type_info")
Expand All @@ -43,9 +47,8 @@ if (NOT CMAKE_CROSSCOMPILING)
endif()

# The module contains PPC vector types that needs the PPC target.
set(opts "")
if(${filename} STREQUAL "__ppc_intrinsics" OR
${filename} STREQUAL "mma")
if(${filename} STREQUAL "__ppc_intrinsics" OR
${filename} STREQUAL "mma")
if (PowerPC IN_LIST LLVM_TARGETS_TO_BUILD)
set(opts "--target=ppc64le")
else()
Expand All @@ -58,7 +61,7 @@ if (NOT CMAKE_CROSSCOMPILING)
# TODO: We may need to flag this with conditional, in case Flang is built w/o OpenMP support
add_custom_command(OUTPUT ${base}.mod
COMMAND ${CMAKE_COMMAND} -E make_directory ${FLANG_INTRINSIC_MODULES_DIR}
COMMAND flang-new -cpp -fsyntax-only ${opts} -module-dir ${FLANG_INTRINSIC_MODULES_DIR}
COMMAND flang-new -fc1 -cpp -fsyntax-only ${opts} -module-dir ${FLANG_INTRINSIC_MODULES_DIR}
clementval marked this conversation as resolved.
Show resolved Hide resolved
${FLANG_SOURCE_DIR}/module/${filename}.f90
DEPENDS flang-new ${FLANG_SOURCE_DIR}/module/${filename}.f90 ${FLANG_SOURCE_DIR}/module/__fortran_builtins.f90 ${depends}
)
Expand Down
Loading