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