152 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// A helper class for emitting expressions and values as cir::ConstantOp10// and as initializers for global variables.11//12// Note: this is based on clang's LLVM IR codegen in ConstantEmitter.h, reusing13// this class interface makes it easier move forward with bringing CIR codegen14// to completion.15//16//===----------------------------------------------------------------------===//17 18#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H19#define CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H20 21#include "CIRGenFunction.h"22#include "CIRGenModule.h"23 24namespace clang::CIRGen {25 26class ConstantEmitter {27public:28 CIRGenModule &cgm;29 const CIRGenFunction *cgf;30 31private:32 bool abstract = false;33 34#ifndef NDEBUG35 // 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 // NDEBUG46 47 /// Whether we're in a constant context.48 bool inConstantContext = false;49 50public:51 /// Initialize this emission in the context of the given function.52 /// Use this if the expression might contain contextual references like53 /// 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 abstract65 /// 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 to71 // be immediately discarded without finalizing anything. Therefore, they72 // must also promise not to do anything that will, in the future, require73 // finalization:74 //75 // - using the CGF (if present) for anything other than establishing76 // semantic context; for example, an expression with ignored77 // side-effects must not be emitted as an abstract expression78 //79 // - doing anything that would not be safe to duplicate within an80 // initializer or to propagate to another context; for example,81 // side effects, or emitting an initialization that requires a82 // reference to its current location.83 mlir::Attribute emitForMemory(mlir::Attribute c, QualType destType);84 static mlir::Attribute emitForMemory(CIRGenModule &cgm, mlir::Attribute c,85 clang::QualType destTy);86 87 mlir::Attribute emitNullForMemory(mlir::Location loc, QualType t) {88 return emitNullForMemory(loc, cgm, t);89 }90 static mlir::Attribute emitNullForMemory(mlir::Location loc,91 CIRGenModule &cgm, QualType t);92 93 /// Try to emit the initializer of the given declaration as an abstract94 /// constant.95 mlir::Attribute tryEmitAbstractForInitializer(const VarDecl &d);96 97 /// Emit the result of the given expression as an abstract constant,98 /// asserting that it succeeded. This is only safe to do when the99 /// expression is known to be a constant expression with either a fairly100 /// simple type or a known simple form.101 mlir::Attribute emitAbstract(const Expr *e, QualType destType);102 mlir::Attribute emitAbstract(SourceLocation loc, const APValue &value,103 QualType destType);104 105 mlir::Attribute tryEmitConstantExpr(const ConstantExpr *ce);106 107 // These are private helper routines of the constant emitter that108 // can't actually be private because things are split out into helper109 // functions and classes.110 111 mlir::Attribute tryEmitPrivateForVarInit(const VarDecl &d);112 113 mlir::TypedAttr tryEmitPrivate(const Expr *e, QualType destType);114 mlir::Attribute tryEmitPrivate(const APValue &value, QualType destType);115 mlir::Attribute tryEmitPrivateForMemory(const Expr *e, QualType destTy);116 mlir::Attribute tryEmitPrivateForMemory(const APValue &value,117 QualType destTy);118 119private:120#ifndef NDEBUG121 void initializeNonAbstract() {122 assert(!initializedNonAbstract);123 initializedNonAbstract = true;124 assert(!cir::MissingFeatures::addressSpace());125 }126 mlir::Attribute markIfFailed(mlir::Attribute init) {127 if (!init)128 failed = true;129 return init;130 }131#else132 void initializeNonAbstract() {}133 mlir::Attribute markIfFailed(mlir::Attribute init) { return init; }134#endif // NDEBUG135 136 class AbstractStateRAII {137 ConstantEmitter &emitter;138 bool oldValue;139 140 public:141 AbstractStateRAII(ConstantEmitter &emitter, bool value)142 : emitter(emitter), oldValue(emitter.abstract) {143 emitter.abstract = value;144 }145 ~AbstractStateRAII() { emitter.abstract = oldValue; }146 };147};148 149} // namespace clang::CIRGen150 151#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H152