//===-- 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 ////////////////////////////////////////////////////////////////////////////////////////// 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; assert(!isIrFieldCreated(vd)); 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 CacheT; static llvm::ManagedStatic cache; CacheT::iterator it = cache->find(dty); if (it != cache->end()) return it->second; TypeStruct* sty = static_cast(dty); VarDeclarations& fields = sty->sym->fields; std::vector 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(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(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); } } }