192 lines · c
1//===--- ConstantEmitter.h - IR constant emission ---------------*- C++ -*-===//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 llvm::Constants10// and as initializers for global variables.11//12//===----------------------------------------------------------------------===//13 14#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H15#define LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H16 17#include "CodeGenFunction.h"18#include "CodeGenModule.h"19 20namespace clang {21namespace CodeGen {22 23class ConstantEmitter {24public:25 CodeGenModule &CGM;26 CodeGenFunction *const CGF;27 28private:29 bool Abstract = false;30 31 /// Whether non-abstract components of the emitter have been initialized.32 bool InitializedNonAbstract = false;33 34 /// Whether the emitter has been finalized.35 bool Finalized = false;36 37 /// Whether the constant-emission failed.38 bool Failed = false;39 40 /// Whether we're in a constant context.41 bool InConstantContext = false;42 43 /// The AST address space where this (non-abstract) initializer is going.44 /// Used for generating appropriate placeholders.45 LangAS DestAddressSpace = LangAS::Default;46 47 llvm::SmallVector<std::pair<llvm::Constant *, llvm::GlobalVariable*>, 4>48 PlaceholderAddresses;49 50public:51 ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr)52 : CGM(CGM), CGF(CGF) {}53 54 /// Initialize this emission in the context of the given function.55 /// Use this if the expression might contain contextual references like56 /// block addresses or PredefinedExprs.57 ConstantEmitter(CodeGenFunction &CGF)58 : CGM(CGF.CGM), CGF(&CGF) {}59 60 ConstantEmitter(const ConstantEmitter &other) = delete;61 ConstantEmitter &operator=(const ConstantEmitter &other) = delete;62 63 ~ConstantEmitter();64 65 /// Is the current emission context abstract?66 bool isAbstract() const {67 return Abstract;68 }69 70 bool isInConstantContext() const { return InConstantContext; }71 void setInConstantContext(bool var) { InConstantContext = var; }72 73 /// Try to emit the initiaizer of the given declaration as an abstract74 /// constant. If this succeeds, the emission must be finalized.75 llvm::Constant *tryEmitForInitializer(const VarDecl &D);76 llvm::Constant *tryEmitForInitializer(const Expr *E, LangAS destAddrSpace,77 QualType destType);78 llvm::Constant *emitForInitializer(const APValue &value, LangAS destAddrSpace,79 QualType destType);80 81 void finalize(llvm::GlobalVariable *global);82 83 // All of the "abstract" emission methods below permit the emission to84 // be immediately discarded without finalizing anything. Therefore, they85 // must also promise not to do anything that will, in the future, require86 // finalization:87 //88 // - using the CGF (if present) for anything other than establishing89 // semantic context; for example, an expression with ignored90 // side-effects must not be emitted as an abstract expression91 //92 // - doing anything that would not be safe to duplicate within an93 // initializer or to propagate to another context; for example,94 // side effects, or emitting an initialization that requires a95 // reference to its current location.96 97 /// Try to emit the initializer of the given declaration as an abstract98 /// constant.99 llvm::Constant *tryEmitAbstractForInitializer(const VarDecl &D);100 101 /// Emit the result of the given expression as an abstract constant,102 /// asserting that it succeeded. This is only safe to do when the103 /// expression is known to be a constant expression with either a fairly104 /// simple type or a known simple form.105 llvm::Constant *emitAbstract(const Expr *E, QualType T);106 llvm::Constant *107 emitAbstract(SourceLocation loc, const APValue &value, QualType T,108 bool EnablePtrAuthFunctionTypeDiscrimination = true);109 110 /// Try to emit the result of the given expression as an abstract constant.111 llvm::Constant *tryEmitAbstract(const Expr *E, QualType T);112 llvm::Constant *tryEmitAbstractForMemory(const Expr *E, QualType T);113 114 llvm::Constant *tryEmitAbstract(const APValue &value, QualType T);115 llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T);116 117 llvm::Constant *tryEmitConstantSignedPointer(llvm::Constant *Ptr,118 PointerAuthQualifier Auth);119 120 llvm::Constant *tryEmitConstantExpr(const ConstantExpr *CE);121 122 llvm::Constant *emitNullForMemory(QualType T) {123 return emitNullForMemory(CGM, T);124 }125 llvm::Constant *emitForMemory(llvm::Constant *C, QualType T) {126 return emitForMemory(CGM, C, T);127 }128 129 static llvm::Constant *emitNullForMemory(CodeGenModule &CGM, QualType T);130 static llvm::Constant *emitForMemory(CodeGenModule &CGM, llvm::Constant *C,131 QualType T);132 133 // These are private helper routines of the constant emitter that134 // can't actually be private because things are split out into helper135 // functions and classes.136 137 llvm::Constant *tryEmitPrivateForVarInit(const VarDecl &D);138 139 llvm::Constant *tryEmitPrivate(const Expr *E, QualType T);140 llvm::Constant *tryEmitPrivateForMemory(const Expr *E, QualType T);141 142 llvm::Constant *143 tryEmitPrivate(const APValue &value, QualType T,144 bool EnablePtrAuthFunctionTypeDiscrimination = true);145 llvm::Constant *tryEmitPrivateForMemory(const APValue &value, QualType T);146 147 /// Get the address of the current location. This is a constant148 /// that will resolve, after finalization, to the address of the149 /// 'signal' value that is registered with the emitter later.150 llvm::GlobalValue *getCurrentAddrPrivate();151 152 /// Register a 'signal' value with the emitter to inform it where to153 /// resolve a placeholder. The signal value must be unique in the154 /// initializer; it might, for example, be the address of a global that155 /// refers to the current-address value in its own initializer.156 ///157 /// Uses of the placeholder must be properly anchored before finalizing158 /// the emitter, e.g. by being installed as the initializer of a global159 /// variable. That is, it must be possible to replaceAllUsesWith160 /// the placeholder with the proper address of the signal.161 void registerCurrentAddrPrivate(llvm::Constant *signal,162 llvm::GlobalValue *placeholder);163 164private:165 void initializeNonAbstract(LangAS destAS) {166 assert(!InitializedNonAbstract);167 InitializedNonAbstract = true;168 DestAddressSpace = destAS;169 }170 llvm::Constant *markIfFailed(llvm::Constant *init) {171 if (!init)172 Failed = true;173 return init;174 }175 176 struct AbstractState {177 bool OldValue;178 size_t OldPlaceholdersSize;179 };180 AbstractState pushAbstract() {181 AbstractState saved = { Abstract, PlaceholderAddresses.size() };182 Abstract = true;183 return saved;184 }185 llvm::Constant *validateAndPopAbstract(llvm::Constant *C, AbstractState save);186};187 188}189}190 191#endif192