//===--- CGExprConstant.cpp - Emit LLVM Code from Constant Expressions ----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code to emit Constant Expr nodes as LLVM code.
//
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
//===----------------------------------------------------------------------===//
// ConstStructBuilder
//===----------------------------------------------------------------------===//
namespace {
class ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
bool Packed;
unsigned NextFieldOffsetInBytes;
unsigned LLVMStructAlignment;
std::vector<llvm::Constant *> Elements;
public:
static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
InitListExpr *ILE);
private:
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
: CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
LLVMStructAlignment(1) { }
bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitExpr);
void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::ConstantInt *InitExpr);
void AppendPadding(uint64_t NumBytes);
void AppendTailPadding(uint64_t RecordSize);
void ConvertStructToPacked();
bool Build(InitListExpr *ILE);
unsigned getAlignment(const llvm::Constant *C) const {
if (Packed) return 1;
return CGM.getTargetData().getABITypeAlignment(C->getType());
}
uint64_t getSizeInBytes(const llvm::Constant *C) const {
return CGM.getTargetData().getTypeAllocSize(C->getType());
}
};
bool ConstStructBuilder::
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitCst) {
uint64_t FieldOffsetInBytes = FieldOffset / 8;
assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
&& "Field offset mismatch!");
unsigned FieldAlignment = getAlignment(InitCst);
// Round up the field offset to the alignment of the field type.
uint64_t AlignedNextFieldOffsetInBytes =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
assert(!Packed && "Alignment is wrong even with a packed struct!");
// Convert the struct to a packed struct.
ConvertStructToPacked();
AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
}
if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
// We need to append padding.
AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
"Did not add enough padding!");
AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
}
// Add the field.
Elements.push_back(InitCst);
NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes +
getSizeInBytes(InitCst);
if (Packed)
assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
else
LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
return true;
}
void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
uint64_t FieldOffset,
llvm::ConstantInt *CI) {
if (FieldOff