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