llvm-project

Форк
0
/
temporary-stack.cpp 
227 строк · 6.7 Кб
1
//===-- runtime/temporary-stack.cpp ---------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8

9
// Implements std::vector like storage for a dynamically resizable number of
10
// temporaries. For use in HLFIR lowering.
11

12
#include "flang/Runtime/temporary-stack.h"
13
#include "terminator.h"
14
#include "flang/ISO_Fortran_binding_wrapper.h"
15
#include "flang/Runtime/assign.h"
16
#include "flang/Runtime/descriptor.h"
17
#include "flang/Runtime/memory.h"
18

19
namespace {
20

21
using namespace Fortran::runtime;
22

23
// the number of elements to allocate when first creating the vector
24
constexpr size_t INITIAL_ALLOC = 8;
25

26
/// To store C style data. Does not run constructors/destructors.
27
/// Not using std::vector to avoid linking the runtime library to stdc++
28
template <bool COPY_VALUES> class DescriptorStorage final {
29
  using size_type = uint64_t; // see checkedMultiply()
30

31
  size_type capacity_{0};
32
  size_type size_{0};
33
  Descriptor **data_{nullptr};
34
  Terminator terminator_;
35

36
  // return true on overflow
37
  static bool checkedMultiply(size_type x, size_type y, size_type &res);
38

39
  void resize(size_type newCapacity);
40

41
  Descriptor *cloneDescriptor(const Descriptor &source);
42

43
public:
44
  DescriptorStorage(const char *sourceFile, int line);
45
  ~DescriptorStorage();
46

47
  // `new` but using the runtime allocation API
48
  static inline DescriptorStorage *allocate(const char *sourceFile, int line) {
49
    Terminator term{sourceFile, line};
50
    void *ptr = AllocateMemoryOrCrash(term, sizeof(DescriptorStorage));
51
    return new (ptr) DescriptorStorage{sourceFile, line};
52
  }
53

54
  // `delete` but using the runtime allocation API
55
  static inline void destroy(DescriptorStorage *instance) {
56
    instance->~DescriptorStorage();
57
    FreeMemory(instance);
58
  }
59

60
  // clones a descriptor into this storage
61
  void push(const Descriptor &source);
62

63
  // out must be big enough to hold a descriptor of the right rank and addendum
64
  void pop(Descriptor &out);
65

66
  // out must be big enough to hold a descriptor of the right rank and addendum
67
  void at(size_type i, Descriptor &out);
68
};
69

70
using ValueStack = DescriptorStorage</*COPY_VALUES=*/true>;
71
using DescriptorStack = DescriptorStorage</*COPY_VALUES=*/false>;
72
} // namespace
73

74
template <bool COPY_VALUES>
75
bool DescriptorStorage<COPY_VALUES>::checkedMultiply(
76
    size_type x, size_type y, size_type &res) {
77
  // TODO: c++20 [[unlikely]]
78
  if (x > UINT64_MAX / y) {
79
    return true;
80
  }
81
  res = x * y;
82
  return false;
83
}
84

85
template <bool COPY_VALUES>
86
void DescriptorStorage<COPY_VALUES>::resize(size_type newCapacity) {
87
  if (newCapacity <= capacity_) {
88
    return;
89
  }
90
  size_type bytes;
91
  if (checkedMultiply(newCapacity, sizeof(Descriptor *), bytes)) {
92
    terminator_.Crash("temporary-stack: out of memory");
93
  }
94
  Descriptor **newData =
95
      static_cast<Descriptor **>(AllocateMemoryOrCrash(terminator_, bytes));
96
  // "memcpy" in glibc has a "nonnull" attribute on the source pointer.
97
  // Avoid passing a null pointer, since it would result in an undefined
98
  // behavior.
99
  if (data_ != nullptr) {
100
    memcpy(newData, data_, capacity_ * sizeof(Descriptor *));
101
    FreeMemory(data_);
102
  }
103
  data_ = newData;
104
  capacity_ = newCapacity;
105
}
106

107
template <bool COPY_VALUES>
108
Descriptor *DescriptorStorage<COPY_VALUES>::cloneDescriptor(
109
    const Descriptor &source) {
110
  const std::size_t bytes = source.SizeInBytes();
111
  void *memory = AllocateMemoryOrCrash(terminator_, bytes);
112
  Descriptor *desc = new (memory) Descriptor{source};
113
  return desc;
114
}
115

116
template <bool COPY_VALUES>
117
DescriptorStorage<COPY_VALUES>::DescriptorStorage(
118
    const char *sourceFile, int line)
119
    : terminator_{sourceFile, line} {
120
  resize(INITIAL_ALLOC);
121
}
122

123
template <bool COPY_VALUES>
124
DescriptorStorage<COPY_VALUES>::~DescriptorStorage() {
125
  for (size_type i = 0; i < size_; ++i) {
126
    Descriptor *element = data_[i];
127
    if constexpr (COPY_VALUES) {
128
      element->Destroy(false, true);
129
    }
130
    FreeMemory(element);
131
  }
132
  FreeMemory(data_);
133
}
134

135
template <bool COPY_VALUES>
136
void DescriptorStorage<COPY_VALUES>::push(const Descriptor &source) {
137
  if (size_ == capacity_) {
138
    size_type newSize;
139
    if (checkedMultiply(capacity_, 2, newSize)) {
140
      terminator_.Crash("temporary-stack: out of address space");
141
    }
142
    resize(newSize);
143
  }
144
  data_[size_] = cloneDescriptor(source);
145
  Descriptor &box = *data_[size_];
146
  size_ += 1;
147

148
  if constexpr (COPY_VALUES) {
149
    // copy the data pointed to by the box
150
    box.set_base_addr(nullptr);
151
    box.Allocate();
152
    RTNAME(AssignTemporary)
153
    (box, source, terminator_.sourceFileName(), terminator_.sourceLine());
154
  }
155
}
156

157
template <bool COPY_VALUES>
158
void DescriptorStorage<COPY_VALUES>::pop(Descriptor &out) {
159
  if (size_ == 0) {
160
    terminator_.Crash("temporary-stack: pop empty storage");
161
  }
162
  size_ -= 1;
163
  Descriptor *ptr = data_[size_];
164
  out = *ptr; // Descriptor::operator= handles the different sizes
165
  FreeMemory(ptr);
166
}
167

168
template <bool COPY_VALUES>
169
void DescriptorStorage<COPY_VALUES>::at(size_type i, Descriptor &out) {
170
  if (i >= size_) {
171
    terminator_.Crash("temporary-stack: out of bounds access");
172
  }
173
  Descriptor *ptr = data_[i];
174
  out = *ptr; // Descriptor::operator= handles the different sizes
175
}
176

177
inline static ValueStack *getValueStorage(void *opaquePtr) {
178
  return static_cast<ValueStack *>(opaquePtr);
179
}
180
inline static DescriptorStack *getDescriptorStorage(void *opaquePtr) {
181
  return static_cast<DescriptorStack *>(opaquePtr);
182
}
183

184
namespace Fortran::runtime {
185
extern "C" {
186
void *RTNAME(CreateValueStack)(const char *sourceFile, int line) {
187
  return ValueStack::allocate(sourceFile, line);
188
}
189

190
void RTNAME(PushValue)(void *opaquePtr, const Descriptor &value) {
191
  getValueStorage(opaquePtr)->push(value);
192
}
193

194
void RTNAME(PopValue)(void *opaquePtr, Descriptor &value) {
195
  getValueStorage(opaquePtr)->pop(value);
196
}
197

198
void RTNAME(ValueAt)(void *opaquePtr, uint64_t i, Descriptor &value) {
199
  getValueStorage(opaquePtr)->at(i, value);
200
}
201

202
void RTNAME(DestroyValueStack)(void *opaquePtr) {
203
  ValueStack::destroy(getValueStorage(opaquePtr));
204
}
205

206
void *RTNAME(CreateDescriptorStack)(const char *sourceFile, int line) {
207
  return DescriptorStack::allocate(sourceFile, line);
208
}
209

210
void RTNAME(PushDescriptor)(void *opaquePtr, const Descriptor &value) {
211
  getDescriptorStorage(opaquePtr)->push(value);
212
}
213

214
void RTNAME(PopDescriptor)(void *opaquePtr, Descriptor &value) {
215
  getDescriptorStorage(opaquePtr)->pop(value);
216
}
217

218
void RTNAME(DescriptorAt)(void *opaquePtr, uint64_t i, Descriptor &value) {
219
  getValueStorage(opaquePtr)->at(i, value);
220
}
221

222
void RTNAME(DestroyDescriptorStack)(void *opaquePtr) {
223
  DescriptorStack::destroy(getDescriptorStorage(opaquePtr));
224
}
225

226
} // extern "C"
227
} // namespace Fortran::runtime
228

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.