//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // A helper class for emitting expressions and values as cir::ConstantOp // and as initializers for global variables. // // Note: this is based on clang's LLVM IR codegen in ConstantEmitter.h, reusing // this class interface makes it easier move forward with bringing CIR codegen // to completion. // //===----------------------------------------------------------------------===// #ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H #define CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H #include "CIRGenFunction.h" #include "CIRGenModule.h" namespace clang::CIRGen { class ConstantEmitter { public: CIRGenModule &cgm; const CIRGenFunction *cgf; private: bool abstract = false; #ifndef NDEBUG // Variables used for asserting state consistency. /// Whether non-abstract components of the emitter have been initialized. bool initializedNonAbstract = false; /// Whether the emitter has been finalized. bool finalized = false; /// Whether the constant-emission failed. bool failed = false; #endif // NDEBUG /// Whether we're in a constant context. bool inConstantContext = false; public: /// Initialize this emission in the context of the given function. /// Use this if the expression might contain contextual references like /// block addresses or PredefinedExprs. ConstantEmitter(CIRGenFunction &cgf) : cgm(cgf.cgm), cgf(&cgf) {} ConstantEmitter(CIRGenModule &cgm, CIRGenFunction *cgf = nullptr) : cgm(cgm), cgf(cgf) {} ConstantEmitter(const ConstantEmitter &other) = delete; ConstantEmitter &operator=(const ConstantEmitter &other) = delete; ~ConstantEmitter(); /// Try to emit the initializer of the given declaration as an abstract /// constant. If this succeeds, the emission must be finalized. mlir::Attribute tryEmitForInitializer(const VarDecl &d); void finalize(cir::GlobalOp gv); // All of the "abstract" emission methods below permit the emission to // be immediately discarded without finalizing anything. Therefore, they // must also promise not to do anything that will, in the future, require // finalization: // // - using the CGF (if present) for anything other than establishing // semantic context; for example, an expression with ignored // side-effects must not be emitted as an abstract expression // // - doing anything that would not be safe to duplicate within an // initializer or to propagate to another context; for example, // side effects, or emitting an initialization that requires a // reference to its current location. mlir::Attribute emitForMemory(mlir::Attribute c, QualType t); /// Try to emit the initializer of the given declaration as an abstract /// constant. mlir::Attribute tryEmitAbstractForInitializer(const VarDecl &d); /// Emit the result of the given expression as an abstract constant, /// asserting that it succeeded. This is only safe to do when the /// expression is known to be a constant expression with either a fairly /// simple type or a known simple form. mlir::Attribute emitAbstract(SourceLocation loc, const APValue &value, QualType t); mlir::Attribute tryEmitConstantExpr(const ConstantExpr *ce); // These are private helper routines of the constant emitter that // can't actually be private because things are split out into helper // functions and classes. mlir::Attribute tryEmitPrivateForVarInit(const VarDecl &d); mlir::Attribute tryEmitPrivate(const APValue &value, QualType destType); mlir::Attribute tryEmitPrivateForMemory(const APValue &value, QualType t); private: #ifndef NDEBUG void initializeNonAbstract() { assert(!initializedNonAbstract); initializedNonAbstract = true; assert(!cir::MissingFeatures::addressSpace()); } mlir::Attribute markIfFailed(mlir::Attribute init) { if (!init) failed = true; return init; } #else void initializeNonAbstract() {} mlir::Attribute markIfFailed(mlir::Attribute init) { return init; } #endif // NDEBUG class AbstractStateRAII { ConstantEmitter &emitter; bool oldValue; public: AbstractStateRAII(ConstantEmitter &emitter, bool value) : emitter(emitter), oldValue(emitter.abstract) { emitter.abstract = value; } ~AbstractStateRAII() { emitter.abstract = oldValue; } }; }; } // namespace clang::CIRGen #endif // CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H