Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===// |
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 | // This class provides a convenient interface for building complex |
||
10 | // global initializers of the sort that are frequently required for |
||
11 | // language ABIs. |
||
12 | // |
||
13 | //===----------------------------------------------------------------------===// |
||
14 | |||
15 | #ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H |
||
16 | #define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H |
||
17 | |||
18 | #include "llvm/ADT/ArrayRef.h" |
||
19 | #include "llvm/ADT/SmallVector.h" |
||
20 | #include "llvm/IR/Constants.h" |
||
21 | #include "llvm/IR/GlobalValue.h" |
||
22 | #include "clang/AST/CharUnits.h" |
||
23 | #include "clang/CodeGen/ConstantInitFuture.h" |
||
24 | |||
25 | #include <vector> |
||
26 | |||
27 | namespace clang { |
||
28 | namespace CodeGen { |
||
29 | |||
30 | class CodeGenModule; |
||
31 | |||
32 | /// A convenience builder class for complex constant initializers, |
||
33 | /// especially for anonymous global structures used by various language |
||
34 | /// runtimes. |
||
35 | /// |
||
36 | /// The basic usage pattern is expected to be something like: |
||
37 | /// ConstantInitBuilder builder(CGM); |
||
38 | /// auto toplevel = builder.beginStruct(); |
||
39 | /// toplevel.addInt(CGM.SizeTy, widgets.size()); |
||
40 | /// auto widgetArray = builder.beginArray(); |
||
41 | /// for (auto &widget : widgets) { |
||
42 | /// auto widgetDesc = widgetArray.beginStruct(); |
||
43 | /// widgetDesc.addInt(CGM.SizeTy, widget.getPower()); |
||
44 | /// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName())); |
||
45 | /// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl())); |
||
46 | /// widgetDesc.finishAndAddTo(widgetArray); |
||
47 | /// } |
||
48 | /// widgetArray.finishAndAddTo(toplevel); |
||
49 | /// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align, |
||
50 | /// /*constant*/ true); |
||
51 | class ConstantInitBuilderBase { |
||
52 | struct SelfReference { |
||
53 | llvm::GlobalVariable *Dummy; |
||
54 | llvm::SmallVector<llvm::Constant*, 4> Indices; |
||
55 | |||
56 | SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {} |
||
57 | }; |
||
58 | CodeGenModule &CGM; |
||
59 | llvm::SmallVector<llvm::Constant*, 16> Buffer; |
||
60 | std::vector<SelfReference> SelfReferences; |
||
61 | bool Frozen = false; |
||
62 | |||
63 | friend class ConstantInitFuture; |
||
64 | friend class ConstantAggregateBuilderBase; |
||
65 | template <class, class> |
||
66 | friend class ConstantAggregateBuilderTemplateBase; |
||
67 | |||
68 | protected: |
||
69 | explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {} |
||
70 | |||
71 | ~ConstantInitBuilderBase() { |
||
72 | assert(Buffer.empty() && "didn't claim all values out of buffer"); |
||
73 | assert(SelfReferences.empty() && "didn't apply all self-references"); |
||
74 | } |
||
75 | |||
76 | private: |
||
77 | llvm::GlobalVariable *createGlobal(llvm::Constant *initializer, |
||
78 | const llvm::Twine &name, |
||
79 | CharUnits alignment, |
||
80 | bool constant = false, |
||
81 | llvm::GlobalValue::LinkageTypes linkage |
||
82 | = llvm::GlobalValue::InternalLinkage, |
||
83 | unsigned addressSpace = 0); |
||
84 | |||
85 | ConstantInitFuture createFuture(llvm::Constant *initializer); |
||
86 | |||
87 | void setGlobalInitializer(llvm::GlobalVariable *GV, |
||
88 | llvm::Constant *initializer); |
||
89 | |||
90 | void resolveSelfReferences(llvm::GlobalVariable *GV); |
||
91 | |||
92 | void abandon(size_t newEnd); |
||
93 | }; |
||
94 | |||
95 | /// A concrete base class for struct and array aggregate |
||
96 | /// initializer builders. |
||
97 | class ConstantAggregateBuilderBase { |
||
98 | protected: |
||
99 | ConstantInitBuilderBase &Builder; |
||
100 | ConstantAggregateBuilderBase *Parent; |
||
101 | size_t Begin; |
||
102 | mutable size_t CachedOffsetEnd = 0; |
||
103 | bool Finished = false; |
||
104 | bool Frozen = false; |
||
105 | bool Packed = false; |
||
106 | mutable CharUnits CachedOffsetFromGlobal; |
||
107 | |||
108 | llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() { |
||
109 | return Builder.Buffer; |
||
110 | } |
||
111 | |||
112 | const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const { |
||
113 | return Builder.Buffer; |
||
114 | } |
||
115 | |||
116 | ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder, |
||
117 | ConstantAggregateBuilderBase *parent) |
||
118 | : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) { |
||
119 | if (parent) { |
||
120 | assert(!parent->Frozen && "parent already has child builder active"); |
||
121 | parent->Frozen = true; |
||
122 | } else { |
||
123 | assert(!builder.Frozen && "builder already has child builder active"); |
||
124 | builder.Frozen = true; |
||
125 | } |
||
126 | } |
||
127 | |||
128 | ~ConstantAggregateBuilderBase() { |
||
129 | assert(Finished && "didn't finish aggregate builder"); |
||
130 | } |
||
131 | |||
132 | void markFinished() { |
||
133 | assert(!Frozen && "child builder still active"); |
||
134 | assert(!Finished && "builder already finished"); |
||
135 | Finished = true; |
||
136 | if (Parent) { |
||
137 | assert(Parent->Frozen && |
||
138 | "parent not frozen while child builder active"); |
||
139 | Parent->Frozen = false; |
||
140 | } else { |
||
141 | assert(Builder.Frozen && |
||
142 | "builder not frozen while child builder active"); |
||
143 | Builder.Frozen = false; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | public: |
||
148 | // Not copyable. |
||
149 | ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete; |
||
150 | ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &) |
||
151 | = delete; |
||
152 | |||
153 | // Movable, mostly to allow returning. But we have to write this out |
||
154 | // properly to satisfy the assert in the destructor. |
||
155 | ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other) |
||
156 | : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin), |
||
157 | CachedOffsetEnd(other.CachedOffsetEnd), |
||
158 | Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed), |
||
159 | CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) { |
||
160 | other.Finished = true; |
||
161 | } |
||
162 | ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other) |
||
163 | = delete; |
||
164 | |||
165 | /// Return the number of elements that have been added to |
||
166 | /// this struct or array. |
||
167 | size_t size() const { |
||
168 | assert(!this->Finished && "cannot query after finishing builder"); |
||
169 | assert(!this->Frozen && "cannot query while sub-builder is active"); |
||
170 | assert(this->Begin <= this->getBuffer().size()); |
||
171 | return this->getBuffer().size() - this->Begin; |
||
172 | } |
||
173 | |||
174 | /// Return true if no elements have yet been added to this struct or array. |
||
175 | bool empty() const { |
||
176 | return size() == 0; |
||
177 | } |
||
178 | |||
179 | /// Abandon this builder completely. |
||
180 | void abandon() { |
||
181 | markFinished(); |
||
182 | Builder.abandon(Begin); |
||
183 | } |
||
184 | |||
185 | /// Add a new value to this initializer. |
||
186 | void add(llvm::Constant *value) { |
||
187 | assert(value && "adding null value to constant initializer"); |
||
188 | assert(!Finished && "cannot add more values after finishing builder"); |
||
189 | assert(!Frozen && "cannot add values while subbuilder is active"); |
||
190 | Builder.Buffer.push_back(value); |
||
191 | } |
||
192 | |||
193 | /// Add an integer value of type size_t. |
||
194 | void addSize(CharUnits size); |
||
195 | |||
196 | /// Add an integer value of a specific type. |
||
197 | void addInt(llvm::IntegerType *intTy, uint64_t value, |
||
198 | bool isSigned = false) { |
||
199 | add(llvm::ConstantInt::get(intTy, value, isSigned)); |
||
200 | } |
||
201 | |||
202 | /// Add a null pointer of a specific type. |
||
203 | void addNullPointer(llvm::PointerType *ptrTy) { |
||
204 | add(llvm::ConstantPointerNull::get(ptrTy)); |
||
205 | } |
||
206 | |||
207 | /// Add a bitcast of a value to a specific type. |
||
208 | void addBitCast(llvm::Constant *value, llvm::Type *type) { |
||
209 | add(llvm::ConstantExpr::getBitCast(value, type)); |
||
210 | } |
||
211 | |||
212 | /// Add a bunch of new values to this initializer. |
||
213 | void addAll(llvm::ArrayRef<llvm::Constant *> values) { |
||
214 | assert(!Finished && "cannot add more values after finishing builder"); |
||
215 | assert(!Frozen && "cannot add values while subbuilder is active"); |
||
216 | Builder.Buffer.append(values.begin(), values.end()); |
||
217 | } |
||
218 | |||
219 | /// Add a relative offset to the given target address, i.e. the |
||
220 | /// static difference between the target address and the address |
||
221 | /// of the relative offset. The target must be known to be defined |
||
222 | /// in the current linkage unit. The offset will have the given |
||
223 | /// integer type, which must be no wider than intptr_t. Some |
||
224 | /// targets may not fully support this operation. |
||
225 | void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) { |
||
226 | add(getRelativeOffset(type, target)); |
||
227 | } |
||
228 | |||
229 | /// Same as addRelativeOffset(), but instead relative to an element in this |
||
230 | /// aggregate, identified by its index. |
||
231 | void addRelativeOffsetToPosition(llvm::IntegerType *type, |
||
232 | llvm::Constant *target, size_t position) { |
||
233 | add(getRelativeOffsetToPosition(type, target, position)); |
||
234 | } |
||
235 | |||
236 | /// Add a relative offset to the target address, plus a small |
||
237 | /// constant offset. This is primarily useful when the relative |
||
238 | /// offset is known to be a multiple of (say) four and therefore |
||
239 | /// the tag can be used to express an extra two bits of information. |
||
240 | void addTaggedRelativeOffset(llvm::IntegerType *type, |
||
241 | llvm::Constant *address, |
||
242 | unsigned tag) { |
||
243 | llvm::Constant *offset = getRelativeOffset(type, address); |
||
244 | if (tag) { |
||
245 | offset = llvm::ConstantExpr::getAdd(offset, |
||
246 | llvm::ConstantInt::get(type, tag)); |
||
247 | } |
||
248 | add(offset); |
||
249 | } |
||
250 | |||
251 | /// Return the offset from the start of the initializer to the |
||
252 | /// next position, assuming no padding is required prior to it. |
||
253 | /// |
||
254 | /// This operation will not succeed if any unsized placeholders are |
||
255 | /// currently in place in the initializer. |
||
256 | CharUnits getNextOffsetFromGlobal() const { |
||
257 | assert(!Finished && "cannot add more values after finishing builder"); |
||
258 | assert(!Frozen && "cannot add values while subbuilder is active"); |
||
259 | return getOffsetFromGlobalTo(Builder.Buffer.size()); |
||
260 | } |
||
261 | |||
262 | /// An opaque class to hold the abstract position of a placeholder. |
||
263 | class PlaceholderPosition { |
||
264 | size_t Index; |
||
265 | friend class ConstantAggregateBuilderBase; |
||
266 | PlaceholderPosition(size_t index) : Index(index) {} |
||
267 | }; |
||
268 | |||
269 | /// Add a placeholder value to the structure. The returned position |
||
270 | /// can be used to set the value later; it will not be invalidated by |
||
271 | /// any intermediate operations except (1) filling the same position or |
||
272 | /// (2) finishing the entire builder. |
||
273 | /// |
||
274 | /// This is useful for emitting certain kinds of structure which |
||
275 | /// contain some sort of summary field, generally a count, before any |
||
276 | /// of the data. By emitting a placeholder first, the structure can |
||
277 | /// be emitted eagerly. |
||
278 | PlaceholderPosition addPlaceholder() { |
||
279 | assert(!Finished && "cannot add more values after finishing builder"); |
||
280 | assert(!Frozen && "cannot add values while subbuilder is active"); |
||
281 | Builder.Buffer.push_back(nullptr); |
||
282 | return Builder.Buffer.size() - 1; |
||
283 | } |
||
284 | |||
285 | /// Add a placeholder, giving the expected type that will be filled in. |
||
286 | PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType); |
||
287 | |||
288 | /// Fill a previously-added placeholder. |
||
289 | void fillPlaceholderWithInt(PlaceholderPosition position, |
||
290 | llvm::IntegerType *type, uint64_t value, |
||
291 | bool isSigned = false) { |
||
292 | fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned)); |
||
293 | } |
||
294 | |||
295 | /// Fill a previously-added placeholder. |
||
296 | void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) { |
||
297 | assert(!Finished && "cannot change values after finishing builder"); |
||
298 | assert(!Frozen && "cannot add values while subbuilder is active"); |
||
299 | llvm::Constant *&slot = Builder.Buffer[position.Index]; |
||
300 | assert(slot == nullptr && "placeholder already filled"); |
||
301 | slot = value; |
||
302 | } |
||
303 | |||
304 | /// Produce an address which will eventually point to the next |
||
305 | /// position to be filled. This is computed with an indexed |
||
306 | /// getelementptr rather than by computing offsets. |
||
307 | /// |
||
308 | /// The returned pointer will have type T*, where T is the given type. This |
||
309 | /// type can differ from the type of the actual element. |
||
310 | llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type); |
||
311 | |||
312 | /// Produce an address which points to a position in the aggregate being |
||
313 | /// constructed. This is computed with an indexed getelementptr rather than by |
||
314 | /// computing offsets. |
||
315 | /// |
||
316 | /// The returned pointer will have type T*, where T is the given type. This |
||
317 | /// type can differ from the type of the actual element. |
||
318 | llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position); |
||
319 | |||
320 | llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition( |
||
321 | llvm::SmallVectorImpl<llvm::Constant*> &indices) { |
||
322 | getGEPIndicesTo(indices, Builder.Buffer.size()); |
||
323 | return indices; |
||
324 | } |
||
325 | |||
326 | protected: |
||
327 | llvm::Constant *finishArray(llvm::Type *eltTy); |
||
328 | llvm::Constant *finishStruct(llvm::StructType *structTy); |
||
329 | |||
330 | private: |
||
331 | void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices, |
||
332 | size_t position) const; |
||
333 | |||
334 | llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType, |
||
335 | llvm::Constant *target); |
||
336 | |||
337 | llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType, |
||
338 | llvm::Constant *target, |
||
339 | size_t position); |
||
340 | |||
341 | CharUnits getOffsetFromGlobalTo(size_t index) const; |
||
342 | }; |
||
343 | |||
344 | template <class Impl, class Traits> |
||
345 | class ConstantAggregateBuilderTemplateBase |
||
346 | : public Traits::AggregateBuilderBase { |
||
347 | using super = typename Traits::AggregateBuilderBase; |
||
348 | public: |
||
349 | using InitBuilder = typename Traits::InitBuilder; |
||
350 | using ArrayBuilder = typename Traits::ArrayBuilder; |
||
351 | using StructBuilder = typename Traits::StructBuilder; |
||
352 | using AggregateBuilderBase = typename Traits::AggregateBuilderBase; |
||
353 | |||
354 | protected: |
||
355 | ConstantAggregateBuilderTemplateBase(InitBuilder &builder, |
||
356 | AggregateBuilderBase *parent) |
||
357 | : super(builder, parent) {} |
||
358 | |||
359 | Impl &asImpl() { return *static_cast<Impl*>(this); } |
||
360 | |||
361 | public: |
||
362 | ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { |
||
363 | return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy); |
||
364 | } |
||
365 | |||
366 | StructBuilder beginStruct(llvm::StructType *ty = nullptr) { |
||
367 | return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty); |
||
368 | } |
||
369 | |||
370 | /// Given that this builder was created by beginning an array or struct |
||
371 | /// component on the given parent builder, finish the array/struct |
||
372 | /// component and add it to the parent. |
||
373 | /// |
||
374 | /// It is an intentional choice that the parent is passed in explicitly |
||
375 | /// despite it being redundant with information already kept in the |
||
376 | /// builder. This aids in readability by making it easier to find the |
||
377 | /// places that add components to a builder, as well as "bookending" |
||
378 | /// the sub-builder more explicitly. |
||
379 | void finishAndAddTo(AggregateBuilderBase &parent) { |
||
380 | assert(this->Parent == &parent && "adding to non-parent builder"); |
||
381 | parent.add(asImpl().finishImpl()); |
||
382 | } |
||
383 | |||
384 | /// Given that this builder was created by beginning an array or struct |
||
385 | /// directly on a ConstantInitBuilder, finish the array/struct and |
||
386 | /// create a global variable with it as the initializer. |
||
387 | template <class... As> |
||
388 | llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { |
||
389 | assert(!this->Parent && "finishing non-root builder"); |
||
390 | return this->Builder.createGlobal(asImpl().finishImpl(), |
||
391 | std::forward<As>(args)...); |
||
392 | } |
||
393 | |||
394 | /// Given that this builder was created by beginning an array or struct |
||
395 | /// directly on a ConstantInitBuilder, finish the array/struct and |
||
396 | /// set it as the initializer of the given global variable. |
||
397 | void finishAndSetAsInitializer(llvm::GlobalVariable *global) { |
||
398 | assert(!this->Parent && "finishing non-root builder"); |
||
399 | return this->Builder.setGlobalInitializer(global, asImpl().finishImpl()); |
||
400 | } |
||
401 | |||
402 | /// Given that this builder was created by beginning an array or struct |
||
403 | /// directly on a ConstantInitBuilder, finish the array/struct and |
||
404 | /// return a future which can be used to install the initializer in |
||
405 | /// a global later. |
||
406 | /// |
||
407 | /// This is useful for allowing a finished initializer to passed to |
||
408 | /// an API which will build the global. However, the "future" preserves |
||
409 | /// a dependency on the original builder; it is an error to pass it aside. |
||
410 | ConstantInitFuture finishAndCreateFuture() { |
||
411 | assert(!this->Parent && "finishing non-root builder"); |
||
412 | return this->Builder.createFuture(asImpl().finishImpl()); |
||
413 | } |
||
414 | }; |
||
415 | |||
416 | template <class Traits> |
||
417 | class ConstantArrayBuilderTemplateBase |
||
418 | : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, |
||
419 | Traits> { |
||
420 | using super = |
||
421 | ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>; |
||
422 | |||
423 | public: |
||
424 | using InitBuilder = typename Traits::InitBuilder; |
||
425 | using AggregateBuilderBase = typename Traits::AggregateBuilderBase; |
||
426 | |||
427 | private: |
||
428 | llvm::Type *EltTy; |
||
429 | |||
430 | template <class, class> |
||
431 | friend class ConstantAggregateBuilderTemplateBase; |
||
432 | |||
433 | protected: |
||
434 | ConstantArrayBuilderTemplateBase(InitBuilder &builder, |
||
435 | AggregateBuilderBase *parent, |
||
436 | llvm::Type *eltTy) |
||
437 | : super(builder, parent), EltTy(eltTy) {} |
||
438 | |||
439 | private: |
||
440 | /// Form an array constant from the values that have been added to this |
||
441 | /// builder. |
||
442 | llvm::Constant *finishImpl() { |
||
443 | return AggregateBuilderBase::finishArray(EltTy); |
||
444 | } |
||
445 | }; |
||
446 | |||
447 | /// A template class designed to allow other frontends to |
||
448 | /// easily customize the builder classes used by ConstantInitBuilder, |
||
449 | /// and thus to extend the API to work with the abstractions they |
||
450 | /// prefer. This would probably not be necessary if C++ just |
||
451 | /// supported extension methods. |
||
452 | template <class Traits> |
||
453 | class ConstantStructBuilderTemplateBase |
||
454 | : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder, |
||
455 | Traits> { |
||
456 | using super = |
||
457 | ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>; |
||
458 | |||
459 | public: |
||
460 | using InitBuilder = typename Traits::InitBuilder; |
||
461 | using AggregateBuilderBase = typename Traits::AggregateBuilderBase; |
||
462 | |||
463 | private: |
||
464 | llvm::StructType *StructTy; |
||
465 | |||
466 | template <class, class> |
||
467 | friend class ConstantAggregateBuilderTemplateBase; |
||
468 | |||
469 | protected: |
||
470 | ConstantStructBuilderTemplateBase(InitBuilder &builder, |
||
471 | AggregateBuilderBase *parent, |
||
472 | llvm::StructType *structTy) |
||
473 | : super(builder, parent), StructTy(structTy) { |
||
474 | if (structTy) this->Packed = structTy->isPacked(); |
||
475 | } |
||
476 | |||
477 | public: |
||
478 | void setPacked(bool packed) { |
||
479 | this->Packed = packed; |
||
480 | } |
||
481 | |||
482 | /// Use the given type for the struct if its element count is correct. |
||
483 | /// Don't add more elements after calling this. |
||
484 | void suggestType(llvm::StructType *structTy) { |
||
485 | if (this->size() == structTy->getNumElements()) { |
||
486 | StructTy = structTy; |
||
487 | } |
||
488 | } |
||
489 | |||
490 | private: |
||
491 | /// Form an array constant from the values that have been added to this |
||
492 | /// builder. |
||
493 | llvm::Constant *finishImpl() { |
||
494 | return AggregateBuilderBase::finishStruct(StructTy); |
||
495 | } |
||
496 | }; |
||
497 | |||
498 | /// A template class designed to allow other frontends to |
||
499 | /// easily customize the builder classes used by ConstantInitBuilder, |
||
500 | /// and thus to extend the API to work with the abstractions they |
||
501 | /// prefer. This would probably not be necessary if C++ just |
||
502 | /// supported extension methods. |
||
503 | template <class Traits> |
||
504 | class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase { |
||
505 | protected: |
||
506 | ConstantInitBuilderTemplateBase(CodeGenModule &CGM) |
||
507 | : ConstantInitBuilderBase(CGM) {} |
||
508 | |||
509 | public: |
||
510 | using InitBuilder = typename Traits::InitBuilder; |
||
511 | using ArrayBuilder = typename Traits::ArrayBuilder; |
||
512 | using StructBuilder = typename Traits::StructBuilder; |
||
513 | |||
514 | ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { |
||
515 | return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy); |
||
516 | } |
||
517 | |||
518 | StructBuilder beginStruct(llvm::StructType *structTy = nullptr) { |
||
519 | return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy); |
||
520 | } |
||
521 | }; |
||
522 | |||
523 | class ConstantInitBuilder; |
||
524 | class ConstantStructBuilder; |
||
525 | class ConstantArrayBuilder; |
||
526 | |||
527 | struct ConstantInitBuilderTraits { |
||
528 | using InitBuilder = ConstantInitBuilder; |
||
529 | using AggregateBuilderBase = ConstantAggregateBuilderBase; |
||
530 | using ArrayBuilder = ConstantArrayBuilder; |
||
531 | using StructBuilder = ConstantStructBuilder; |
||
532 | }; |
||
533 | |||
534 | /// The standard implementation of ConstantInitBuilder used in Clang. |
||
535 | class ConstantInitBuilder |
||
536 | : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> { |
||
537 | public: |
||
538 | explicit ConstantInitBuilder(CodeGenModule &CGM) : |
||
539 | ConstantInitBuilderTemplateBase(CGM) {} |
||
540 | }; |
||
541 | |||
542 | /// A helper class of ConstantInitBuilder, used for building constant |
||
543 | /// array initializers. |
||
544 | class ConstantArrayBuilder |
||
545 | : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> { |
||
546 | template <class Traits> |
||
547 | friend class ConstantInitBuilderTemplateBase; |
||
548 | |||
549 | // The use of explicit qualification is a GCC workaround. |
||
550 | template <class Impl, class Traits> |
||
551 | friend class CodeGen::ConstantAggregateBuilderTemplateBase; |
||
552 | |||
553 | ConstantArrayBuilder(ConstantInitBuilder &builder, |
||
554 | ConstantAggregateBuilderBase *parent, |
||
555 | llvm::Type *eltTy) |
||
556 | : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {} |
||
557 | }; |
||
558 | |||
559 | /// A helper class of ConstantInitBuilder, used for building constant |
||
560 | /// struct initializers. |
||
561 | class ConstantStructBuilder |
||
562 | : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> { |
||
563 | template <class Traits> |
||
564 | friend class ConstantInitBuilderTemplateBase; |
||
565 | |||
566 | // The use of explicit qualification is a GCC workaround. |
||
567 | template <class Impl, class Traits> |
||
568 | friend class CodeGen::ConstantAggregateBuilderTemplateBase; |
||
569 | |||
570 | ConstantStructBuilder(ConstantInitBuilder &builder, |
||
571 | ConstantAggregateBuilderBase *parent, |
||
572 | llvm::StructType *structTy) |
||
573 | : ConstantStructBuilderTemplateBase(builder, parent, structTy) {} |
||
574 | }; |
||
575 | |||
576 | } // end namespace CodeGen |
||
577 | } // end namespace clang |
||
578 | |||
579 | #endif |