ldc/gen/structs.cpp
2014-10-05 16:08:52 +04:00

210 lines
6.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- structs.cpp -------------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "aggregate.h"
#include "declaration.h"
#include "init.h"
#include "module.h"
#include "mtype.h"
#include "gen/arrays.h"
#include "gen/dvalue.h"
#include "gen/functions.h"
#include "gen/irstate.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/structs.h"
#include "gen/tollvm.h"
#include "ir/iraggr.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/ManagedStatic.h"
#include <algorithm>
//////////////////////////////////////////////////////////////////////////////////////////
void DtoResolveStruct(StructDeclaration* sd)
{
DtoResolveStruct(sd, sd->loc);
}
void DtoResolveStruct(StructDeclaration* sd, Loc& callerLoc)
{
// Make sure to resolve each struct type exactly once.
if (sd->ir.isResolved()) return;
sd->ir.setResolved();
IF_LOG Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars());
LOG_SCOPE;
// make sure type exists
DtoType(sd->type);
// if it's a forward declaration, all bets are off. The type should be enough
if (sd->sizeok != SIZEOKdone)
{
error(callerLoc, "struct %s.%s unknown size", sd->getModule()->toChars(), sd->toChars());
fatal();
}
// create the IrAggr
getIrAggr(sd, true);
// Set up our field metadata.
for (VarDeclarations::iterator I = sd->fields.begin(),
E = sd->fields.end();
I != E; ++I)
{
VarDeclaration *vd = *I;
IF_LOG {
if (isIrFieldCreated(vd))
Logger::println("struct field already exists");
}
getIrField(vd, true);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// D STRUCT UTILITIES ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs)
{
Type* t = lhs->getType()->toBasetype();
assert(t->ty == Tstruct);
// set predicate
llvm::ICmpInst::Predicate cmpop;
if (op == TOKequal || op == TOKidentity)
cmpop = llvm::ICmpInst::ICMP_EQ;
else
cmpop = llvm::ICmpInst::ICMP_NE;
// call memcmp
size_t sz = getTypePaddedSize(DtoType(t));
LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz));
return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false));
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
{
IF_LOG Logger::println("indexing struct field %s:", vd->toPrettyChars());
LOG_SCOPE;
DtoResolveStruct(sd);
// vd must be a field
IrField* field = getIrField(vd);
assert(field);
// get the start pointer
LLType* st = getPtrToType(DtoType(sd->type));
// cast to the formal struct type
src = DtoBitCast(src, st);
// gep to the index
assert(vd->ident);
LLValue* val = DtoGEPi(src, 0, field->index, vd->ident->toChars());
// do we need to offset further? (union area)
if (field->unionOffset)
{
// cast to void*
val = DtoBitCast(val, getVoidPtrType());
// offset
val = DtoGEPi1(val, field->unionOffset);
}
// cast it to the right type
val = DtoBitCast(val, getPtrToType(i1ToI8(DtoType(vd->type))));
IF_LOG Logger::cout() << "value: " << *val << '\n';
return val;
}
//////////////////////////////////////////////////////////////////////////////////////////
/// Return the type returned by DtoUnpaddedStruct called on a value of the
/// specified type.
/// Union types will get expanded into a struct, with a type for each member.
LLType* DtoUnpaddedStructType(Type* dty) {
assert(dty->ty == Tstruct);
typedef llvm::DenseMap<Type*, llvm::StructType*> CacheT;
static llvm::ManagedStatic<CacheT> cache;
CacheT::iterator it = cache->find(dty);
if (it != cache->end())
return it->second;
TypeStruct* sty = static_cast<TypeStruct*>(dty);
VarDeclarations& fields = sty->sym->fields;
std::vector<LLType*> types;
types.reserve(fields.dim);
for (unsigned i = 0; i < fields.dim; i++) {
LLType* fty;
if (fields[i]->type->ty == Tstruct) {
// Nested structs are the only members that can contain padding
fty = DtoUnpaddedStructType(fields[i]->type);
} else {
fty = DtoType(fields[i]->type);
}
types.push_back(fty);
}
LLStructType* Ty = LLStructType::get(gIR->context(), types);
cache->insert(std::make_pair(dty, Ty));
return Ty;
}
/// Return the struct value represented by v without the padding fields.
/// Unions will be expanded, with a value for each member.
/// Note: v must be a pointer to a struct, but the return value will be a
/// first-class struct value.
LLValue* DtoUnpaddedStruct(Type* dty, LLValue* v) {
assert(dty->ty == Tstruct);
TypeStruct* sty = static_cast<TypeStruct*>(dty);
VarDeclarations& fields = sty->sym->fields;
LLValue* newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty));
for (unsigned i = 0; i < fields.dim; i++) {
LLValue* fieldptr = DtoIndexStruct(v, sty->sym, fields[i]);
LLValue* fieldval;
if (fields[i]->type->ty == Tstruct) {
// Nested structs are the only members that can contain padding
fieldval = DtoUnpaddedStruct(fields[i]->type, fieldptr);
} else {
fieldval = DtoLoad(fieldptr);
}
newval = DtoInsertValue(newval, fieldval, i);
}
return newval;
}
/// Undo the transformation performed by DtoUnpaddedStruct, writing to lval.
void DtoPaddedStruct(Type* dty, LLValue* v, LLValue* lval) {
assert(dty->ty == Tstruct);
TypeStruct* sty = static_cast<TypeStruct*>(dty);
VarDeclarations& fields = sty->sym->fields;
for (unsigned i = 0; i < fields.dim; i++) {
LLValue* fieldptr = DtoIndexStruct(lval, sty->sym, fields[i]);
LLValue* fieldval = DtoExtractValue(v, i);
if (fields[i]->type->ty == Tstruct) {
// Nested structs are the only members that can contain padding
DtoPaddedStruct(fields[i]->type, fieldval, fieldptr);
} else {
DtoStore(fieldval, fieldptr);
}
}
}