llvm-project/clang/lib/CodeGen/ConstantEmitter.h

181 lines
6.6 KiB
C
Raw Normal View History

//===--- ConstantEmitter.h - IR constant emission ---------------*- C++ -*-===//
//
// 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 llvm::Constants
// and as initializers for global variables.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H
#define LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
namespace clang {
namespace CodeGen {
class ConstantEmitter {
public:
CodeGenModule &CGM;
CodeGenFunction *CGF;
private:
bool Abstract = false;
/// 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;
/// Whether we're in a constant context.
bool InConstantContext = false;
/// The AST address space where this (non-abstract) initializer is going.
/// Used for generating appropriate placeholders.
Convert clang::LangAS to a strongly typed enum Summary: Convert clang::LangAS to a strongly typed enum Currently both clang AST address spaces and target specific address spaces are represented as unsigned which can lead to subtle errors if the wrong type is passed. It is especially confusing in the CodeGen files as it is not possible to see what kind of address space should be passed to a function without looking at the implementation. I originally made this change for our LLVM fork for the CHERI architecture where we make extensive use of address spaces to differentiate between capabilities and pointers. When merging the upstream changes I usually run into some test failures or runtime crashes because the wrong kind of address space is passed to a function. By converting the LangAS enum to a C++11 we can catch these errors at compile time. Additionally, it is now obvious from the function signature which kind of address space it expects. I found the following errors while writing this patch: - ItaniumRecordLayoutBuilder::LayoutField was passing a clang AST address space to TargetInfo::getPointer{Width,Align}() - TypePrinter::printAttributedAfter() prints the numeric value of the clang AST address space instead of the target address space. However, this code is not used so I kept the current behaviour - initializeForBlockHeader() in CGBlocks.cpp was passing LangAS::opencl_generic to TargetInfo::getPointer{Width,Align}() - CodeGenFunction::EmitBlockLiteral() was passing a AST address space to TargetInfo::getPointerWidth() - CGOpenMPRuntimeNVPTX::translateParameter() passed a target address space to Qualifiers::addAddressSpace() - CGOpenMPRuntimeNVPTX::getParameterAddress() was using llvm::Type::getPointerTo() with a AST address space - clang_getAddressSpace() returns either a LangAS or a target address space. As this is exposed to C I have kept the current behaviour and added a comment stating that it is probably not correct. Other than this the patch should not cause any functional changes. Reviewers: yaxunl, pcc, bader Reviewed By: yaxunl, bader Subscribers: jlebar, jholewinski, nhaehnle, Anastasia, cfe-commits Differential Revision: https://reviews.llvm.org/D38816 llvm-svn: 315871
2017-10-16 02:48:14 +08:00
LangAS DestAddressSpace;
llvm::SmallVector<std::pair<llvm::Constant *, llvm::GlobalVariable*>, 4>
PlaceholderAddresses;
public:
ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr)
: CGM(CGM), CGF(CGF) {}
/// Initialize this emission in the context of the given function.
2018-07-12 03:51:40 +08:00
/// Use this if the expression might contain contextual references like
/// block addresses or PredefinedExprs.
ConstantEmitter(CodeGenFunction &CGF)
: CGM(CGF.CGM), CGF(&CGF) {}
ConstantEmitter(const ConstantEmitter &other) = delete;
ConstantEmitter &operator=(const ConstantEmitter &other) = delete;
~ConstantEmitter();
/// Is the current emission context abstract?
bool isAbstract() const {
return Abstract;
}
/// Try to emit the initiaizer of the given declaration as an abstract
/// constant. If this succeeds, the emission must be finalized.
llvm::Constant *tryEmitForInitializer(const VarDecl &D);
Convert clang::LangAS to a strongly typed enum Summary: Convert clang::LangAS to a strongly typed enum Currently both clang AST address spaces and target specific address spaces are represented as unsigned which can lead to subtle errors if the wrong type is passed. It is especially confusing in the CodeGen files as it is not possible to see what kind of address space should be passed to a function without looking at the implementation. I originally made this change for our LLVM fork for the CHERI architecture where we make extensive use of address spaces to differentiate between capabilities and pointers. When merging the upstream changes I usually run into some test failures or runtime crashes because the wrong kind of address space is passed to a function. By converting the LangAS enum to a C++11 we can catch these errors at compile time. Additionally, it is now obvious from the function signature which kind of address space it expects. I found the following errors while writing this patch: - ItaniumRecordLayoutBuilder::LayoutField was passing a clang AST address space to TargetInfo::getPointer{Width,Align}() - TypePrinter::printAttributedAfter() prints the numeric value of the clang AST address space instead of the target address space. However, this code is not used so I kept the current behaviour - initializeForBlockHeader() in CGBlocks.cpp was passing LangAS::opencl_generic to TargetInfo::getPointer{Width,Align}() - CodeGenFunction::EmitBlockLiteral() was passing a AST address space to TargetInfo::getPointerWidth() - CGOpenMPRuntimeNVPTX::translateParameter() passed a target address space to Qualifiers::addAddressSpace() - CGOpenMPRuntimeNVPTX::getParameterAddress() was using llvm::Type::getPointerTo() with a AST address space - clang_getAddressSpace() returns either a LangAS or a target address space. As this is exposed to C I have kept the current behaviour and added a comment stating that it is probably not correct. Other than this the patch should not cause any functional changes. Reviewers: yaxunl, pcc, bader Reviewed By: yaxunl, bader Subscribers: jlebar, jholewinski, nhaehnle, Anastasia, cfe-commits Differential Revision: https://reviews.llvm.org/D38816 llvm-svn: 315871
2017-10-16 02:48:14 +08:00
llvm::Constant *tryEmitForInitializer(const Expr *E, LangAS destAddrSpace,
QualType destType);
Convert clang::LangAS to a strongly typed enum Summary: Convert clang::LangAS to a strongly typed enum Currently both clang AST address spaces and target specific address spaces are represented as unsigned which can lead to subtle errors if the wrong type is passed. It is especially confusing in the CodeGen files as it is not possible to see what kind of address space should be passed to a function without looking at the implementation. I originally made this change for our LLVM fork for the CHERI architecture where we make extensive use of address spaces to differentiate between capabilities and pointers. When merging the upstream changes I usually run into some test failures or runtime crashes because the wrong kind of address space is passed to a function. By converting the LangAS enum to a C++11 we can catch these errors at compile time. Additionally, it is now obvious from the function signature which kind of address space it expects. I found the following errors while writing this patch: - ItaniumRecordLayoutBuilder::LayoutField was passing a clang AST address space to TargetInfo::getPointer{Width,Align}() - TypePrinter::printAttributedAfter() prints the numeric value of the clang AST address space instead of the target address space. However, this code is not used so I kept the current behaviour - initializeForBlockHeader() in CGBlocks.cpp was passing LangAS::opencl_generic to TargetInfo::getPointer{Width,Align}() - CodeGenFunction::EmitBlockLiteral() was passing a AST address space to TargetInfo::getPointerWidth() - CGOpenMPRuntimeNVPTX::translateParameter() passed a target address space to Qualifiers::addAddressSpace() - CGOpenMPRuntimeNVPTX::getParameterAddress() was using llvm::Type::getPointerTo() with a AST address space - clang_getAddressSpace() returns either a LangAS or a target address space. As this is exposed to C I have kept the current behaviour and added a comment stating that it is probably not correct. Other than this the patch should not cause any functional changes. Reviewers: yaxunl, pcc, bader Reviewed By: yaxunl, bader Subscribers: jlebar, jholewinski, nhaehnle, Anastasia, cfe-commits Differential Revision: https://reviews.llvm.org/D38816 llvm-svn: 315871
2017-10-16 02:48:14 +08:00
llvm::Constant *emitForInitializer(const APValue &value, LangAS destAddrSpace,
QualType destType);
void finalize(llvm::GlobalVariable *global);
// 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.
/// Try to emit the initializer of the given declaration as an abstract
/// constant.
llvm::Constant *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.
llvm::Constant *emitAbstract(const Expr *E, QualType T);
llvm::Constant *emitAbstract(SourceLocation loc, const APValue &value,
QualType T);
/// Try to emit the result of the given expression as an abstract constant.
llvm::Constant *tryEmitAbstract(const Expr *E, QualType T);
llvm::Constant *tryEmitAbstractForMemory(const Expr *E, QualType T);
llvm::Constant *tryEmitAbstract(const APValue &value, QualType T);
llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T);
llvm::Constant *emitNullForMemory(QualType T) {
return emitNullForMemory(CGM, T);
}
llvm::Constant *emitForMemory(llvm::Constant *C, QualType T) {
return emitForMemory(CGM, C, T);
}
static llvm::Constant *emitNullForMemory(CodeGenModule &CGM, QualType T);
static llvm::Constant *emitForMemory(CodeGenModule &CGM, llvm::Constant *C,
QualType T);
// 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.
llvm::Constant *tryEmitPrivateForVarInit(const VarDecl &D);
llvm::Constant *tryEmitPrivate(const Expr *E, QualType T);
llvm::Constant *tryEmitPrivateForMemory(const Expr *E, QualType T);
llvm::Constant *tryEmitPrivate(const APValue &value, QualType T);
llvm::Constant *tryEmitPrivateForMemory(const APValue &value, QualType T);
/// Get the address of the current location. This is a constant
/// that will resolve, after finalization, to the address of the
/// 'signal' value that is registered with the emitter later.
llvm::GlobalValue *getCurrentAddrPrivate();
/// Register a 'signal' value with the emitter to inform it where to
/// resolve a placeholder. The signal value must be unique in the
/// initializer; it might, for example, be the address of a global that
/// refers to the current-address value in its own initializer.
///
/// Uses of the placeholder must be properly anchored before finalizing
/// the emitter, e.g. by being installed as the initializer of a global
/// variable. That is, it must be possible to replaceAllUsesWith
/// the placeholder with the proper address of the signal.
void registerCurrentAddrPrivate(llvm::Constant *signal,
llvm::GlobalValue *placeholder);
private:
Convert clang::LangAS to a strongly typed enum Summary: Convert clang::LangAS to a strongly typed enum Currently both clang AST address spaces and target specific address spaces are represented as unsigned which can lead to subtle errors if the wrong type is passed. It is especially confusing in the CodeGen files as it is not possible to see what kind of address space should be passed to a function without looking at the implementation. I originally made this change for our LLVM fork for the CHERI architecture where we make extensive use of address spaces to differentiate between capabilities and pointers. When merging the upstream changes I usually run into some test failures or runtime crashes because the wrong kind of address space is passed to a function. By converting the LangAS enum to a C++11 we can catch these errors at compile time. Additionally, it is now obvious from the function signature which kind of address space it expects. I found the following errors while writing this patch: - ItaniumRecordLayoutBuilder::LayoutField was passing a clang AST address space to TargetInfo::getPointer{Width,Align}() - TypePrinter::printAttributedAfter() prints the numeric value of the clang AST address space instead of the target address space. However, this code is not used so I kept the current behaviour - initializeForBlockHeader() in CGBlocks.cpp was passing LangAS::opencl_generic to TargetInfo::getPointer{Width,Align}() - CodeGenFunction::EmitBlockLiteral() was passing a AST address space to TargetInfo::getPointerWidth() - CGOpenMPRuntimeNVPTX::translateParameter() passed a target address space to Qualifiers::addAddressSpace() - CGOpenMPRuntimeNVPTX::getParameterAddress() was using llvm::Type::getPointerTo() with a AST address space - clang_getAddressSpace() returns either a LangAS or a target address space. As this is exposed to C I have kept the current behaviour and added a comment stating that it is probably not correct. Other than this the patch should not cause any functional changes. Reviewers: yaxunl, pcc, bader Reviewed By: yaxunl, bader Subscribers: jlebar, jholewinski, nhaehnle, Anastasia, cfe-commits Differential Revision: https://reviews.llvm.org/D38816 llvm-svn: 315871
2017-10-16 02:48:14 +08:00
void initializeNonAbstract(LangAS destAS) {
assert(!InitializedNonAbstract);
InitializedNonAbstract = true;
DestAddressSpace = destAS;
}
llvm::Constant *markIfFailed(llvm::Constant *init) {
if (!init)
Failed = true;
return init;
}
struct AbstractState {
bool OldValue;
size_t OldPlaceholdersSize;
};
AbstractState pushAbstract() {
AbstractState saved = { Abstract, PlaceholderAddresses.size() };
Abstract = true;
return saved;
}
llvm::Constant *validateAndPopAbstract(llvm::Constant *C, AbstractState save);
};
}
}
#endif