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
24namespace clang::CIRGen {
25
26class ConstantEmitter {
27public:
28 CIRGenModule &cgm;
29 const CIRGenFunction *cgf;
30
31private:
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
50public:
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
107private:
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

source code of clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h