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