xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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.
ConstantEmitter(CIRGenFunction & cgf)54   ConstantEmitter(CIRGenFunction &cgf) : cgm(cgf.cgm), cgf(&cgf) {}
55 
56   ConstantEmitter(CIRGenModule &cgm, CIRGenFunction *cgf = nullptr)
cgm(cgm)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
initializeNonAbstract()109   void initializeNonAbstract() {
110     assert(!initializedNonAbstract);
111     initializedNonAbstract = true;
112     assert(!cir::MissingFeatures::addressSpace());
113   }
markIfFailed(mlir::Attribute init)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:
AbstractStateRAII(ConstantEmitter & emitter,bool value)129     AbstractStateRAII(ConstantEmitter &emitter, bool value)
130         : emitter(emitter), oldValue(emitter.abstract) {
131       emitter.abstract = value;
132     }
~AbstractStateRAII()133     ~AbstractStateRAII() { emitter.abstract = oldValue; }
134   };
135 };
136 
137 } // namespace clang::CIRGen
138 
139 #endif // CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H
140