1 | //===----------------------------------------------------------------------===// |
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 | // A helper class for emitting expressions and values as cir::ConstantOp |
10 | // and as initializers for global variables. |
11 | // |
12 | // Note: this is based on clang's LLVM IR codegen in ConstantEmitter.h, reusing |
13 | // this class interface makes it easier move forward with bringing CIR codegen |
14 | // to completion. |
15 | // |
16 | //===----------------------------------------------------------------------===// |
17 | |
18 | #ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H |
19 | #define CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H |
20 | |
21 | #include "CIRGenFunction.h" |
22 | #include "CIRGenModule.h" |
23 | |
24 | namespace clang::CIRGen { |
25 | |
26 | class ConstantEmitter { |
27 | public: |
28 | CIRGenModule &cgm; |
29 | const CIRGenFunction *cgf; |
30 | |
31 | private: |
32 | bool abstract = false; |
33 | |
34 | #ifndef NDEBUG |
35 | // Variables used for asserting state consistency. |
36 | |
37 | /// Whether non-abstract components of the emitter have been initialized. |
38 | bool initializedNonAbstract = false; |
39 | |
40 | /// Whether the emitter has been finalized. |
41 | bool finalized = false; |
42 | |
43 | /// Whether the constant-emission failed. |
44 | bool failed = false; |
45 | #endif // NDEBUG |
46 | |
47 | /// Whether we're in a constant context. |
48 | bool inConstantContext = false; |
49 | |
50 | public: |
51 | /// Initialize this emission in the context of the given function. |
52 | /// Use this if the expression might contain contextual references like |
53 | /// block addresses or PredefinedExprs. |
54 | ConstantEmitter(CIRGenFunction &cgf) : cgm(cgf.cgm), cgf(&cgf) {} |
55 | |
56 | ConstantEmitter(CIRGenModule &cgm, CIRGenFunction *cgf = nullptr) |
57 | : cgm(cgm), cgf(cgf) {} |
58 | |
59 | ConstantEmitter(const ConstantEmitter &other) = delete; |
60 | ConstantEmitter &operator=(const ConstantEmitter &other) = delete; |
61 | |
62 | ~ConstantEmitter(); |
63 | |
64 | /// Try to emit the initializer of the given declaration as an abstract |
65 | /// constant. If this succeeds, the emission must be finalized. |
66 | mlir::Attribute tryEmitForInitializer(const VarDecl &d); |
67 | |
68 | void finalize(cir::GlobalOp gv); |
69 | |
70 | // All of the "abstract" emission methods below permit the emission to |
71 | // be immediately discarded without finalizing anything. Therefore, they |
72 | // must also promise not to do anything that will, in the future, require |
73 | // finalization: |
74 | // |
75 | // - using the CGF (if present) for anything other than establishing |
76 | // semantic context; for example, an expression with ignored |
77 | // side-effects must not be emitted as an abstract expression |
78 | // |
79 | // - doing anything that would not be safe to duplicate within an |
80 | // initializer or to propagate to another context; for example, |
81 | // side effects, or emitting an initialization that requires a |
82 | // reference to its current location. |
83 | mlir::Attribute emitForMemory(mlir::Attribute c, QualType t); |
84 | |
85 | /// Try to emit the initializer of the given declaration as an abstract |
86 | /// constant. |
87 | mlir::Attribute tryEmitAbstractForInitializer(const VarDecl &d); |
88 | |
89 | /// Emit the result of the given expression as an abstract constant, |
90 | /// asserting that it succeeded. This is only safe to do when the |
91 | /// expression is known to be a constant expression with either a fairly |
92 | /// simple type or a known simple form. |
93 | mlir::Attribute emitAbstract(SourceLocation loc, const APValue &value, |
94 | QualType t); |
95 | |
96 | mlir::Attribute tryEmitConstantExpr(const ConstantExpr *ce); |
97 | |
98 | // These are private helper routines of the constant emitter that |
99 | // can't actually be private because things are split out into helper |
100 | // functions and classes. |
101 | |
102 | mlir::Attribute tryEmitPrivateForVarInit(const VarDecl &d); |
103 | |
104 | mlir::Attribute tryEmitPrivate(const APValue &value, QualType destType); |
105 | mlir::Attribute tryEmitPrivateForMemory(const APValue &value, QualType t); |
106 | |
107 | private: |
108 | #ifndef NDEBUG |
109 | void initializeNonAbstract() { |
110 | assert(!initializedNonAbstract); |
111 | initializedNonAbstract = true; |
112 | assert(!cir::MissingFeatures::addressSpace()); |
113 | } |
114 | mlir::Attribute markIfFailed(mlir::Attribute init) { |
115 | if (!init) |
116 | failed = true; |
117 | return init; |
118 | } |
119 | #else |
120 | void initializeNonAbstract() {} |
121 | mlir::Attribute markIfFailed(mlir::Attribute init) { return init; } |
122 | #endif // NDEBUG |
123 | |
124 | class AbstractStateRAII { |
125 | ConstantEmitter &emitter; |
126 | bool oldValue; |
127 | |
128 | public: |
129 | AbstractStateRAII(ConstantEmitter &emitter, bool value) |
130 | : emitter(emitter), oldValue(emitter.abstract) { |
131 | emitter.abstract = value; |
132 | } |
133 | ~AbstractStateRAII() { emitter.abstract = oldValue; } |
134 | }; |
135 | }; |
136 | |
137 | } // namespace clang::CIRGen |
138 | |
139 | #endif // CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H |
140 | |