summaryrefslogtreecommitdiffstats
path: root/flang/runtime/freestanding-tools.h
blob: 451bf13b9fa6da8c5bcde958d29efe757e5a2760 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//===-- runtime/freestanding-tools.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 FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_
#define FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_

#include "flang/Common/api-attrs.h"
#include "flang/Runtime/c-or-cpp.h"
#include <algorithm>
#include <cstring>

// The file defines a set of utilities/classes that might be
// used to get reduce the dependency on external libraries (e.g. libstdc++).

#if !defined(STD_FILL_N_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_FILL_N_UNSUPPORTED 1
#endif

#if !defined(STD_MEMMOVE_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_MEMMOVE_UNSUPPORTED 1
#endif

#if !defined(STD_STRLEN_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_STRLEN_UNSUPPORTED 1
#endif

#if !defined(STD_MEMCMP_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_MEMCMP_UNSUPPORTED 1
#endif

#if !defined(STD_REALLOC_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_REALLOC_UNSUPPORTED 1
#endif

#if !defined(STD_MEMCHR_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_MEMCHR_UNSUPPORTED 1
#endif

#if !defined(STD_STRCPY_UNSUPPORTED) && \
    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_STRCPY_UNSUPPORTED 1
#endif

namespace Fortran::runtime {

#if STD_FILL_N_UNSUPPORTED
// Provides alternative implementation for std::fill_n(), if
// it is not supported.
template <typename A, typename B>
static inline RT_API_ATTRS std::enable_if_t<std::is_convertible_v<B, A>, void>
fill_n(A *start, std::size_t count, const B &value) {
  for (std::size_t j{0}; j < count; ++j) {
    start[j] = value;
  }
}
#else // !STD_FILL_N_UNSUPPORTED
using std::fill_n;
#endif // !STD_FILL_N_UNSUPPORTED

#if STD_MEMMOVE_UNSUPPORTED
// Provides alternative implementation for std::memmove(), if
// it is not supported.
static inline RT_API_ATTRS void memmove(
    void *dest, const void *src, std::size_t count) {
  char *to{reinterpret_cast<char *>(dest)};
  const char *from{reinterpret_cast<const char *>(src)};

  if (to == from) {
    return;
  }
  if (to + count <= from || from + count <= to) {
    std::memcpy(dest, src, count);
  } else if (to < from) {
    while (count--) {
      *to++ = *from++;
    }
  } else {
    to += count;
    from += count;
    while (count--) {
      *--to = *--from;
    }
  }
}
#else // !STD_MEMMOVE_UNSUPPORTED
using std::memmove;
#endif // !STD_MEMMOVE_UNSUPPORTED

#if STD_STRLEN_UNSUPPORTED
// Provides alternative implementation for std::strlen(), if
// it is not supported.
static inline RT_API_ATTRS std::size_t strlen(const char *str) {
  if (!str) {
    // Return 0 for nullptr.
    return 0;
  }
  const char *end = str;
  for (; *end != '\0'; ++end)
    ;
  return end - str;
}
#else // !STD_STRLEN_UNSUPPORTED
using std::strlen;
#endif // !STD_STRLEN_UNSUPPORTED

#if STD_MEMCMP_UNSUPPORTED
// Provides alternative implementation for std::memcmp(), if
// it is not supported.
static inline RT_API_ATTRS int memcmp(
    const void *RESTRICT lhs, const void *RESTRICT rhs, std::size_t count) {
  auto m1{reinterpret_cast<const unsigned char *>(lhs)};
  auto m2{reinterpret_cast<const unsigned char *>(rhs)};
  for (; count--; ++m1, ++m2) {
    int diff = *m1 - *m2;
    if (diff != 0) {
      return diff;
    }
  }
  return 0;
}
#else // !STD_MEMCMP_UNSUPPORTED
using std::memcmp;
#endif // !STD_MEMCMP_UNSUPPORTED

#if STD_REALLOC_UNSUPPORTED
static inline RT_API_ATTRS void *realloc(void *ptr, std::size_t newByteSize) {
  // Return nullptr and let the callers assert that.
  // TODO: we can provide a straightforward implementation
  // via malloc/memcpy/free.
  return nullptr;
}
#else // !STD_REALLOC_UNSUPPORTED
using std::realloc;
#endif // !STD_REALLOC_UNSUPPORTED

#if STD_MEMCHR_UNSUPPORTED
// Provides alternative implementation for std::memchr(), if
// it is not supported.
static inline RT_API_ATTRS const void *memchr(
    const void *ptr, int ch, std::size_t count) {
  auto buf{reinterpret_cast<const unsigned char *>(ptr)};
  auto c{static_cast<unsigned char>(ch)};
  for (; count--; ++buf) {
    if (*buf == c) {
      return buf;
    }
  }
  return nullptr;
}
#else // !STD_MEMCMP_UNSUPPORTED
using std::memchr;
#endif // !STD_MEMCMP_UNSUPPORTED

#if STD_STRCPY_UNSUPPORTED
// Provides alternative implementation for std::strcpy(), if
// it is not supported.
static inline RT_API_ATTRS char *strcpy(char *dest, const char *src) {
  char *result{dest};
  do {
    *dest++ = *src;
  } while (*src++ != '\0');
  return result;
}
#else // !STD_STRCPY_UNSUPPORTED
using std::strcpy;
#endif // !STD_STRCPY_UNSUPPORTED

} // namespace Fortran::runtime
#endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_