| 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 | |