Example #1
0
// return a constant array of type arrTypeD initialized with a constant value, or that constant value
LLConstant* FillSArrayDims(Type* arrTypeD, LLConstant* init)
{
    if (arrTypeD->ty == Tsarray)
    {
        init = FillSArrayDims(arrTypeD->nextOf(), init);
        size_t dim = static_cast<TypeSArray*>(arrTypeD)->dim->toUInteger();
        LLArrayType* arrty = LLArrayType::get(init->getType(), dim);
        return LLConstantArray::get(arrty, std::vector<LLConstant*>(dim, init));
    }
    return init;
}
Example #2
0
// return a constant array of type arrTypeD initialized with a constant value,
// or that constant value
static llvm::Constant *FillSArrayDims(Type *arrTypeD, llvm::Constant *init) {
  // Check whether we actually need to expand anything.
  // KLUDGE: We don't have the initializer type here, so we can only check
  // the size without doing an expensive recursive D <-> LLVM type comparison.
  // The better way to solve this would be to just fix the initializer
  // codegen in any place where a scalar initializer might still be generated.
  if (gDataLayout->getTypeStoreSize(init->getType()) >= arrTypeD->size()) {
    return init;
  }

  if (arrTypeD->ty == Tsarray) {
    init = FillSArrayDims(arrTypeD->nextOf(), init);
    size_t dim = static_cast<TypeSArray *>(arrTypeD)->dim->toUInteger();
    llvm::ArrayType *arrty = llvm::ArrayType::get(init->getType(), dim);
    return llvm::ConstantArray::get(arrty,
                                    std::vector<llvm::Constant *>(dim, init));
  }
  return init;
}
Example #3
0
void IrAggr::addFieldInitializers(
    llvm::SmallVectorImpl<llvm::Constant *> &constants,
    const VarInitMap &explicitInitializers, AggregateDeclaration *decl,
    unsigned &offset, bool populateInterfacesWithVtbls) {

  if (ClassDeclaration *cd = decl->isClassDeclaration()) {
    if (cd->baseClass) {
      addFieldInitializers(constants, explicitInitializers, cd->baseClass,
                           offset, populateInterfacesWithVtbls);
    }

    // has interface vtbls?
    if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) {
      // Align interface infos to pointer size.
      unsigned aligned =
          (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1);
      if (offset < aligned) {
        add_zeros(constants, offset, aligned);
        offset = aligned;
      }

      // false when it's not okay to use functions from super classes
      bool newinsts = (cd == aggrdecl->isClassDeclaration());

      size_t inter_idx = interfacesWithVtbls.size();
      for (auto bc : *cd->vtblInterfaces) {
        constants.push_back(getInterfaceVtbl(bc, newinsts, inter_idx));
        offset += Target::ptrsize;
        inter_idx++;

        if (populateInterfacesWithVtbls)
          interfacesWithVtbls.push_back(bc);
      }
    }
  }

  AggrTypeBuilder b(false, offset);
  b.addAggregate(decl, &explicitInitializers, AggrTypeBuilder::Aliases::Skip);
  offset = b.currentOffset();

  const size_t baseLLFieldIndex = constants.size();
  const size_t numNewLLFields = b.defaultTypes().size();
  constants.resize(constants.size() + numNewLLFields, nullptr);

  // add explicit and non-overlapping implicit initializers
  for (const auto &pair : b.varGEPIndices()) {
    const auto field = pair.first;
    const size_t fieldIndex = pair.second;

    const auto explicitIt = explicitInitializers.find(field);
    llvm::Constant *init = (explicitIt != explicitInitializers.end()
                                ? explicitIt->second
                                : getDefaultInitializer(field));

    constants[baseLLFieldIndex + fieldIndex] =
        FillSArrayDims(field->type, init);
  }

  // zero out remaining padding fields
  for (size_t i = 0; i < numNewLLFields; i++) {
    auto &init = constants[baseLLFieldIndex + i];
    if (!init)
      init = llvm::Constant::getNullValue(b.defaultTypes()[i]);
  }
}
Example #4
0
std::vector<LLConstant*> DtoStructLiteralValues(const StructDeclaration* sd,
                                                const std::vector<LLConstant*>& inits)
{
    // get arrays
    size_t nvars = sd->fields.dim;
    VarDeclaration** vars = (VarDeclaration**)sd->fields.data;

    assert(inits.size() == nvars);

    // first locate all explicit initializers
    std::vector<VarDeclaration*> explicitInits;
    for (size_t i=0; i < nvars; i++)
    {
        if (inits[i])
        {
            explicitInits.push_back(vars[i]);
        }
    }

    // vector of values to build aggregate from
    std::vector<LLConstant*> values;

    // offset trackers
    size_t lastoffset = 0;
    size_t lastsize = 0;

    // index of next explicit init
    size_t exidx = 0;
    // number of explicit inits
    size_t nex = explicitInits.size();

    // for through each field and build up the struct, padding with zeros
    size_t i;
    for (i=0; i<nvars; i++)
    {
        VarDeclaration* var = vars[i];

        // get var info
        size_t os = var->offset;
        size_t sz = var->type->size();

        // get next explicit
        VarDeclaration* nextVar = NULL;
        size_t nextOs = 0;
        if (exidx < nex)
        {
            nextVar = explicitInits[exidx];
            nextOs = nextVar->offset;
        }
        // none, rest is defaults
        else
        {
            break;
        }

        // not explicit initializer, default initialize if there is room, otherwise skip
        if (!inits[i])
        {
            // default init if there is room
            // (past current offset) and (small enough to fit before next explicit)
            if ((os >= lastoffset + lastsize) && (os+sz <= nextOs))
            {
                // add any 0 padding needed before this field
                if (os > lastoffset + lastsize)
                {
                    //printf("1added %lu zeros\n", os - lastoffset - lastsize);
                    add_zeros(values, os - lastoffset - lastsize);
                }

                // get field default init
                IrField* f = var->ir.irField;
                assert(f);
                values.push_back(f->getDefaultInit());

                lastoffset = os;
                lastsize = sz;
                //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
            }
            // skip
            continue;
        }

        assert(nextVar == var);

        LLConstant* init = FillSArrayDims(var->type, inits[i]);
        values.push_back(init);

        // update offsets
        lastoffset = os;
        // sometimes size of the initializer is less than size of the variable,
        // so make sure that lastsize is correct
        if (inits[i]->getType()->isSized())
            sz = ceil(gDataLayout->getTypeSizeInBits(init->getType()) / 8.0);
        lastsize = sz;

        // go to next explicit init
        exidx++;

        //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz);
    }

    // fill out rest with default initializers
    LLType* structtype = DtoType(sd->type);
    size_t structsize = getTypePaddedSize(structtype);

    // FIXME: this could probably share some code with the above
    if (structsize > lastoffset+lastsize)
    {
        for (/*continue from first loop*/; i < nvars; i++)
        {
            VarDeclaration* var = vars[i];

            // get var info
            size_t os = var->offset;
            size_t sz = var->type->size();

            // skip?
            if (os < lastoffset + lastsize)
                continue;

            // add any 0 padding needed before this field
            if (os > lastoffset + lastsize)
            {
                //printf("2added %lu zeros\n", os - lastoffset - lastsize);
                add_zeros(values, os - lastoffset - lastsize);
            }

            // get field default init
            IrField* f = var->ir.irField;
            assert(f);
            values.push_back(f->getDefaultInit());

            lastoffset = os;
            lastsize = sz;
            //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
        }
    }

    // add any 0 padding needed at the end of the literal
    if (structsize > lastoffset+lastsize)
    {
        //printf("3added %lu zeros\n", structsize - lastoffset - lastsize);
        add_zeros(values, structsize - lastoffset - lastsize);
    }

    return values;
}
Example #5
0
void IrAggr::addFieldInitializers(
    llvm::SmallVectorImpl<llvm::Constant*>& constants,
    const VarInitMap& explicitInitializers,
    AggregateDeclaration* decl,
    unsigned& offset,
    bool populateInterfacesWithVtbls
    )
{
    if (ClassDeclaration* cd = decl->isClassDeclaration())
    {
        if (cd->baseClass)
        {
            addFieldInitializers(constants, explicitInitializers,
                cd->baseClass, offset, populateInterfacesWithVtbls);
        }
    }

    // Build up vector with one-to-one mapping to field indices.
    const size_t n = decl->fields.dim;
    llvm::SmallVector<VarInitConst, 16> data(n);

    // Fill in explicit initializers.
    for (size_t i = 0; i < n; ++i)
    {
        VarDeclaration* vd = decl->fields[i];
        VarInitMap::const_iterator expl = explicitInitializers.find(vd);
        if (expl != explicitInitializers.end())
            data[i] = *expl;
    }

    // Fill in implicit initializers
    for (size_t i = 0; i < n; i++)
    {
        if (data[i].first) continue;

        VarDeclaration* vd = decl->fields[i];

        /* Skip void initializers for unions. DMD bug 3991:
            union X
            {
                int   a = void;
                dchar b = 'a';
            }
        */
        if (decl->isUnionDeclaration() && vd->init && vd->init->isVoidInitializer())
            continue;

        unsigned vd_begin = vd->offset;
        unsigned vd_end = vd_begin + vd->type->size();

        /* Skip zero size fields like zero-length static arrays, LDC issue 812:
            class B {
                ubyte[0] test;
            }
        */
        if (vd_begin == vd_end)
            continue;

        // make sure it doesn't overlap any explicit initializers.
        bool overlaps = false;
        if (type->ty == Tstruct)
        {
            // Only structs and unions can have overlapping fields.
            for (size_t j = 0; j < n; ++j)
            {
                if (i == j || !data[j].first)
                    continue;

                VarDeclaration* it = decl->fields[j];
                unsigned f_begin = it->offset;
                unsigned f_end = f_begin + it->type->size();

                if (vd_begin >= f_end || vd_end <= f_begin)
                    continue;

                overlaps = true;
                break;
            }
        }
        // add if no overlap found
        if (!overlaps)
        {
            IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset);
            LOG_SCOPE;

            data[i].first = vd;
            data[i].second = get_default_initializer(vd, NULL);
        }
    }

    // Sort data array by offset.
    // TODO: Figure out whether this is really necessary, fields should already
    // be in offset order. Not having do do this would mean we could use a plain
    // llvm::Constant* vector for initializers and avoid all the VarInitConst business.
    std::sort(data.begin(), data.end(), struct_init_data_sort);

    // build array of constants and make sure explicit zero padding is inserted when necessary.
    for (size_t i = 0; i < n; i++)
    {
        VarDeclaration* vd = data[i].first;
        if (vd == NULL)
            continue;

        // Explicitly zero the padding as per TDPL ยง7.1.1. Otherwise, it would
        // be left uninitialized by LLVM.
        if (offset < vd->offset)
        {
            add_zeros(constants, offset, vd->offset);
            offset = vd->offset;
        }

        IF_LOG Logger::println("adding field %s", vd->toChars());

        constants.push_back(FillSArrayDims(vd->type, data[i].second));
        offset += getMemberSize(vd->type);
    }

    if (ClassDeclaration* cd = decl->isClassDeclaration())
    {
        // has interface vtbls?
        if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0)
        {
            // Align interface infos to pointer size.
            unsigned aligned = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1);
            if (offset < aligned)
            {
                add_zeros(constants, offset, aligned);
                offset = aligned;
            }

            // false when it's not okay to use functions from super classes
            bool newinsts = (cd == aggrdecl->isClassDeclaration());

            size_t inter_idx = interfacesWithVtbls.size();

            offset = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1);

            for (BaseClasses::iterator I = cd->vtblInterfaces->begin(),
                                       E = cd->vtblInterfaces->end();
                                       I != E; ++I)
            {
                constants.push_back(getInterfaceVtbl(*I, newinsts, inter_idx));
                offset += Target::ptrsize;
                inter_idx++;

                if (populateInterfacesWithVtbls)
                    interfacesWithVtbls.push_back(*I);
            }
        }
    }
}