Joseph Huber 21b3461440
[flang-rt] Implement basic support for I/O from OpenMP GPU Offloading (#181039)
Summary:
This PR provides the minimal support for Fortran I/O coming from a GPU
in OpenMP offloading. We use the same support the `libc` uses for its
printing through the RPC server. The helper functions `rpc::dispatch`
and `rpc::invoke` help make this mostly automatic.

Becaus Fortran I/O is not reentrant, the vast majority of complexity
comes from needing to stitch together calls from the GPU until they can
be executed all at once. This is needed not only because of the
limitations of recursive I/O, but without this the output would all be
interleaved because of the GPU's lock-step execution.

As such, the return values from the intermediate functions are
meaningless, all returning true. The final value is correct however. For
cookies we create a context pointer on the server to chain these
together.

Works on both my AMD and NVIDIA GPUs.
```fortran
program hello_gpu
  implicit none

  !$omp target teams num_teams(1)
  !$omp parallel num_threads(2)
    ! Print strings
    print *, "Hello from GPU"
  !$omp end parallel
  !$omp end target teams

end program hello_gpu
```
```console
> flang hello.f90 -O2 -fopenmp --offload-arch=gfx1030 
> ./a.out 
 Hello from GPU
 Hello from GPU
> flang hello.f90 -O2 -fopenmp --offload-arch=sm_89  
> ./a.out 
 Hello from GPU
 Hello from GPU
```
2026-02-20 07:56:59 -06:00

60 lines
1.6 KiB
C++

//===-- lib/runtime/array.h -------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef FLANG_RT_RUNTIME_ARRAY_H_
#define FLANG_RT_RUNTIME_ARRAY_H_
#include "flang-rt/runtime/memory.h"
#include "flang-rt/runtime/terminator.h"
namespace Fortran::runtime {
// A simple dynamic array that only supports appending to avoid std::vector.
template <typename T> struct DynamicArray {
~DynamicArray() {
for (std::size_t i = 0; i < size_; ++i) {
data_[i].~T();
}
FreeMemory(data_);
}
void emplace_back(T &&value) {
if (size_ == capacity_) {
reserve(capacity_ ? capacity_ * 2 : 4);
}
new (data_ + size_) T(std::move(value));
++size_;
}
void reserve(std::size_t newCap) {
if (newCap <= capacity_) {
return;
}
T *new_data = static_cast<T *>(
AllocateMemoryOrCrash(terminator_, newCap * sizeof(T)));
for (std::size_t i = 0; i < size_; ++i) {
new (new_data + i) T(std::move(data_[i]));
data_[i].~T();
}
FreeMemory(data_);
data_ = new_data;
capacity_ = newCap;
}
T *begin() const { return data_; }
T *end() const { return data_ + size_; }
private:
T *data_ = nullptr;
std::size_t size_ = 0;
std::size_t capacity_ = 0;
Terminator terminator_{__FILE__, __LINE__};
};
} // namespace Fortran::runtime
#endif // FLANG_RT_RUNTIME_ARRAY_H_