Mercurial > projects > ldc
diff gen/structs.cpp @ 1353:45aca7e7cc88
Remove struct padding when passing or returning in registers on x86-64 (extern(D) only)
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Thu, 14 May 2009 20:36:55 +0200 |
parents | c8b9406d84ca |
children | 8ca25bd765a3 |
line wrap: on
line diff
--- a/gen/structs.cpp Thu May 14 17:23:55 2009 +0200 +++ b/gen/structs.cpp Thu May 14 20:36:55 2009 +0200 @@ -1,6 +1,8 @@ #include <algorithm> #include "gen/llvm.h" +#include "llvm/AbstractTypeUser.h" +#include "llvm/ADT/DenseMap.h" #include "mtype.h" #include "aggregate.h" @@ -332,3 +334,80 @@ return values; } +/// 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::PATypeHolder> CacheT; + static CacheT cache; + CacheT::iterator it = cache.find(dty); + if (it != cache.end()) + return it->second; + + TypeStruct* sty = (TypeStruct*) dty; + Array& fields = sty->sym->fields; + + std::vector<const LLType*> types; + + for (unsigned i = 0; i < fields.dim; i++) { + VarDeclaration* vd = (VarDeclaration*) fields.data[i]; + const LLType* fty; + if (vd->type->ty == Tstruct) { + // Nested structs are the only members that can contain padding + fty = DtoUnpaddedStructType(vd->type); + } else { + fty = DtoType(vd->type); + } + types.push_back(fty); + } + LLType* Ty = LLStructType::get(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 = (TypeStruct*) dty; + Array& fields = sty->sym->fields; + + LLValue* newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty)); + + for (unsigned i = 0; i < fields.dim; i++) { + VarDeclaration* vd = (VarDeclaration*) fields.data[i]; + LLValue* fieldptr = DtoIndexStruct(v, sty->sym, vd); + LLValue* fieldval; + if (vd->type->ty == Tstruct) { + // Nested structs are the only members that can contain padding + fieldval = DtoUnpaddedStruct(vd->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 = (TypeStruct*) dty; + Array& fields = sty->sym->fields; + + for (unsigned i = 0; i < fields.dim; i++) { + VarDeclaration* vd = (VarDeclaration*) fields.data[i]; + LLValue* fieldptr = DtoIndexStruct(lval, sty->sym, vd); + LLValue* fieldval = DtoExtractValue(v, i); + if (vd->type->ty == Tstruct) { + // Nested structs are the only members that can contain padding + DtoPaddedStruct(vd->type, fieldval, fieldptr); + } else { + DtoStore(fieldval, fieldptr); + } + } +}