From b49cbeaaf1909539de166a9664e3ae7501fda705 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 17 May 2013 01:02:02 +0200 Subject: [PATCH] Factored out struct initializer constant generation. --- ir/irstruct.cpp | 80 +++-------------------------------------- ir/irtype.h | 2 ++ ir/irtypestruct.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++ ir/irtypestruct.h | 25 +++++++++++++ 4 files changed, 120 insertions(+), 75 deletions(-) diff --git a/ir/irstruct.cpp b/ir/irstruct.cpp index 0873f403..3e749cf9 100644 --- a/ir/irstruct.cpp +++ b/ir/irstruct.cpp @@ -213,19 +213,6 @@ std::vector IrStruct::createStructDefaultInitializer() ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -// yet another rewrite of the notorious StructInitializer. - -typedef std::pair VCPair; - -bool struct_init_data_sort(const VCPair& a, const VCPair& b) -{ - return (a.first && b.first) - ? a.first->offset < b.first->offset - : false; -} - -// this time a bit more inspired by the DMD code. - LLConstant * IrStruct::createStructInitializer(StructInitializer * si) { IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars()); @@ -236,7 +223,7 @@ LLConstant * IrStruct::createStructInitializer(StructInitializer * si) assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); // array of things to build - llvm::SmallVector data(aggrdecl->fields.dim); + llvm::SmallVector data(aggrdecl->fields.dim); // start by creating a map from initializer indices to field indices. // I have no fucking clue why dmd represents it like this :/ @@ -345,65 +332,8 @@ LLConstant * IrStruct::createStructInitializer(StructInitializer * si) fatal(); } - // sort data array by offset - std::sort(data.begin(), data.end(), struct_init_data_sort); - - // build array of constants and make sure explicit zero padding is inserted when necessary. - size_t offset = 0; - std::vector constants; - constants.reserve(n); - - for (size_t i = 0; i < n; i++) - { - VarDeclaration* vd = data[i].first; - if (vd == NULL) - continue; - - // get next aligned offset for this field - size_t alignedoffset = offset; - if (!packed) - { - alignedoffset = realignOffset(alignedoffset, vd->type); - } - - // insert explicit padding? - if (alignedoffset < vd->offset) - { - size_t diff = vd->offset - alignedoffset; - IF_LOG Logger::println("adding %zu bytes zero padding", diff); - add_zeros(constants, diff); - } - - IF_LOG Logger::println("adding field %s", vd->toChars()); - - constants.push_back(data[i].second); - offset = vd->offset + vd->type->size(); - } - - // tail padding? - if (offset < aggrdecl->structsize) - { - size_t diff = aggrdecl->structsize - offset; - IF_LOG Logger::println("adding %zu bytes zero padding", diff); - add_zeros(constants, diff); - } - - // get initializer type - LLStructType* <ype = si->ltype; - if (!ltype || ltype->isOpaque()) { - std::vector::iterator itr, end = constants.end(); - std::vector types; - for (itr = constants.begin(); itr != end; ++itr) - types.push_back((*itr)->getType()); - if (!ltype) - ltype = LLStructType::get(gIR->context(), types, packed); - else - ltype->setBody(types, packed); - } - - // build constant - assert(!constants.empty()); - llvm::Constant* c = LLConstantStruct::get(ltype, constants); - IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl; - return c; + llvm::Constant* init = + type->irtype->isStruct()->createInitializerConstant(data, si->ltype); + si->ltype = static_cast(init->getType()); + return init; } diff --git a/ir/irtype.h b/ir/irtype.h index 6d2826ba..21c78336 100644 --- a/ir/irtype.h +++ b/ir/irtype.h @@ -60,6 +60,8 @@ class IrTypeVector; class IrType { public: + virtual ~IrType() {} + /// virtual IrTypeAggr* isAggr() { return NULL; } /// diff --git a/ir/irtypestruct.cpp b/ir/irtypestruct.cpp index e46cdc9d..a7c473bc 100644 --- a/ir/irtypestruct.cpp +++ b/ir/irtypestruct.cpp @@ -36,6 +36,94 @@ IrTypeAggr::IrTypeAggr(AggregateDeclaration * ad) } ////////////////////////////////////////////////////////////////////////////// + +static bool struct_init_data_sort(const IrTypeAggr::VarInitConst& a, + const IrTypeAggr::VarInitConst& b) +{ + return (a.first && b.first) + ? a.first->offset < b.first->offset + : false; +} + +extern size_t add_zeros(std::vector& constants, size_t diff); + +llvm::Constant* IrTypeAggr::createInitializerConstant( + llvm::ArrayRef initializers, + llvm::StructType* initializerType) +{ + const bool packed = (dtype->ty == Tstruct) + ? dtype->alignsize() == 1 + : false; + + const size_t n = initializers.size(); + + // sort data array by offset + llvm::SmallVector data( + initializers.begin(), initializers.end()); + std::sort(data.begin(), data.end(), struct_init_data_sort); + + // build array of constants and make sure explicit zero padding is inserted when necessary. + size_t offset = 0; + std::vector constants; + constants.reserve(n); + + for (size_t i = 0; i < n; i++) + { + VarDeclaration* vd = data[i].first; + if (vd == NULL) + continue; + + // get next aligned offset for this field + size_t alignedoffset = offset; + if (!packed) + { + alignedoffset = realignOffset(alignedoffset, vd->type); + } + + // insert explicit padding? + if (alignedoffset < vd->offset) + { + size_t diff = vd->offset - alignedoffset; + IF_LOG Logger::println("adding %zu bytes zero padding", diff); + add_zeros(constants, diff); + } + + IF_LOG Logger::println("adding field %s", vd->toChars()); + + constants.push_back(initializers[i].second); + offset = vd->offset + vd->type->size(); + } + + // tail padding? + const size_t structsize = getTypePaddedSize(type); + if (offset < structsize) + { + size_t diff = structsize - offset; + IF_LOG Logger::println("adding %zu bytes zero padding", diff); + add_zeros(constants, diff); + } + + // get initializer type + if (!initializerType || initializerType->isOpaque()) + { + std::vector::iterator itr, end = constants.end(); + std::vector types; + types.reserve(constants.size()); + for (itr = constants.begin(); itr != end; ++itr) + types.push_back((*itr)->getType()); + if (!initializerType) + initializerType = LLStructType::get(gIR->context(), types, packed); + else + initializerType->setBody(types, packed); + } + + // build constant + assert(!constants.empty()); + llvm::Constant* c = LLConstantStruct::get(initializerType, constants); + IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl; + return c; +} + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irtypestruct.h b/ir/irtypestruct.h index f52dff45..eb64d988 100644 --- a/ir/irtypestruct.h +++ b/ir/irtypestruct.h @@ -16,9 +16,15 @@ #define __LDC_IR_IRTYPESTRUCT_H__ #include "ir/irtype.h" +#include "llvm/ADT/ArrayRef.h" +#include ////////////////////////////////////////////////////////////////////////////// +namespace llvm { + class StructType; +} + struct AggregateDeclaration; struct StructDeclaration; struct TypeStruct; @@ -40,6 +46,25 @@ public: /// iterator def_end() { return default_fields.end(); } + /// A pair of a member variable declaration and an associated initializer + /// constant. + typedef std::pair VarInitConst; + + /// Creates an initializer constant for the struct type with the given + /// fields set to the provided constants. The remaining space (not + /// explicitly specified fields, padding) is default-initialized. + /// + /// The optional initializerType parmeter can be used to specify the exact + /// LLVM type to use for the initializer. If non-null and non-opaque, the + /// type must exactly match the generated constant. This parameter is used + /// mainly for supporting legacy code. + /// + /// Note that in the general case (if e.g. unions are involved), the + /// returned type is not necessarily the same as getLLType(). + llvm::Constant* createInitializerConstant( + llvm::ArrayRef initializers, + llvm::StructType* initializerType = 0); + protected: /// IrTypeAggr(AggregateDeclaration* ad);