//===--- 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 "CGObjCRuntime.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/Support/Compiler.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
namespace {
class VISIBILITY_HIDDEN ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
bool Packed;
unsigned NextFieldOffsetInBytes;
std::vector<llvm::Constant *> Elements;
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
: CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0) { }
bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
const Expr *InitExpr) {
uint64_t FieldOffsetInBytes = FieldOffset / 8;
assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
&& "Field offset mismatch!");
// Emit the field.
llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF);
if (!C)
return false;
unsigned FieldAlignment = getAlignment(C);
// Round up the field offset to the alignment of the field type.
uint64_t AlignedNextFieldOffsetInBytes =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
std::vector<llvm::Constant *> PackedElements;
assert(!Packed && "Alignment is wrong even with a packed struct!");
// Convert the struct to a packed struct.
uint64_t ElementOffsetInBytes = 0;
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
llvm::Constant *C = Elements[i];
unsigned ElementAlign =
CGM.getTargetData().getABITypeAlignment(C->getType());
uint64_t AlignedElementOffsetInBytes =
llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
// We need some padding.
uint64_t NumBytes =
AlignedElementOffsetInBytes - ElementOffsetInBytes;
const llvm::Type *Ty = llvm::Type::Int8Ty;
if (NumBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumBytes);
llvm::Constant *Padding = llvm::Constant::getNullValue(Ty);
PackedElements.push_back(Padding);
ElementOffsetInBytes += getSizeInBytes(Padding);
}
PackedElements.push_back(C);
ElementOffsetInBytes += getSizeInBytes(C);
}
assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
"Packing the struct changed its size!");
Elements = PackedElements;
Packed = true;
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(C);
NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C);
return true;
}
bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
const Expr *InitExpr) {
llvm::ConstantInt *CI =
cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr,
Field->getType(),
CGF));
// FIXME: Can this ever happen?
if (!CI)
return false;
if (FieldOffset > NextFieldOffsetInBytes * 8) {
// We need to add padding.
uint64_t NumBytes =
llvm::RoundUpToAlignment(FieldOffset -
NextFieldOffsetInBytes * 8, 8) / 8;
AppendPadding(NumBytes);
}
uint64_t FieldSize =
Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
llvm::APInt FieldValue = CI->getValue();
// Promote the size of FieldValue if necessary
// FIXME: This should never occur, but currently it can because initializer
// constants are cast to bool, and because clang is not enforcing bitfield
// width limits.
if (FieldSize > FieldValue.getBitWidth