Пример #1
0
LLConstant* DtoConstStringPtr(const char* str, const char* section)
{
    llvm::StringRef s(str);
    LLConstant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true);
    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
        *gIR->module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, ".str");
    if (section) gvar->setSection(section);
    gvar->setUnnamedAddr(true);
    LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) };
    return llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true);
}
Пример #2
0
void RTTIBuilder::finalize(IrGlobal* tid)
{
    // create the inititalizer
    LLConstant* tiInit = LLConstantStruct::get(gIR->context(), &inits[0], inits.size(), false);

    // refine global type
    llvm::cast<llvm::OpaqueType>(tid->type.get())->refineAbstractTypeTo(tiInit->getType());

    // set the initializer
    isaGlobalVar(tid->value)->setInitializer(tiInit);
}
Пример #3
0
LLConstant* DtoConstString(const char* str)
{
    llvm::StringRef s(str ? str : "");
    LLConstant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true);
    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
        *gIR->module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, ".str");
    gvar->setUnnamedAddr(true);
    LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) };
    return DtoConstSlice(
        DtoConstSize_t(s.size()),
        llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true),
        Type::tchar->arrayOf()
    );
}
Пример #4
0
  void visit(VarExp *e) override {
    IF_LOG Logger::print("VarExp::toConstElem: %s @ %s\n", e->toChars(),
                         e->type->toChars());
    LOG_SCOPE;

    if (SymbolDeclaration *sdecl = e->var->isSymbolDeclaration()) {
      // this seems to be the static initialiser for structs
      Type *sdecltype = sdecl->type->toBasetype();
      IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
      assert(sdecltype->ty == Tstruct);
      TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
      DtoResolveStruct(ts->sym);
      result = getIrAggr(ts->sym)->getDefaultInit();
      return;
    }

    if (TypeInfoDeclaration *ti = e->var->isTypeInfoDeclaration()) {
      LLType *vartype = DtoType(e->type);
      result = DtoTypeInfoOf(ti->tinfo, false);
      if (result->getType() != getPtrToType(vartype)) {
        result = llvm::ConstantExpr::getBitCast(result, vartype);
      }
      return;
    }

    VarDeclaration *vd = e->var->isVarDeclaration();
    if (vd && vd->isConst() && vd->_init) {
      if (vd->inuse) {
        e->error("recursive reference %s", e->toChars());
        result = llvm::UndefValue::get(DtoType(e->type));
      } else {
        vd->inuse++;
        // return the initializer
        result = DtoConstInitializer(e->loc, e->type, vd->_init);
        vd->inuse--;
      }
    }
    // fail
    else {
      e->error("non-constant expression %s", e->toChars());
      result = llvm::UndefValue::get(DtoType(e->type));
    }
  }
Пример #5
0
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd)
{
//     The layout is:
//        {
//         void **vptr;
//         monitor_t monitor;
//         byte[] initializer;     // static initialization data
//         char[] name;        // class name
//         void *[] vtbl;
//         Interface[] interfaces;
//         ClassInfo *base;        // base class
//         void *destructor;
//         void *invariant;        // class invariant
//         uint flags;
//         void *deallocator;
//         OffsetTypeInfo[] offTi;
//         void *defaultConstructor;
//         version(D_Version2)
//              immutable(void)* m_RTInfo;
//         else
//              TypeInfo typeinfo; // since dmd 1.045
//        }

    Logger::println("DtoDefineClassInfo(%s)", cd->toChars());
    LOG_SCOPE;

    assert(cd->type->ty == Tclass);
    TypeClass* cdty = static_cast<TypeClass*>(cd->type);

    IrStruct* ir = cd->ir.irStruct;
    assert(ir);

    ClassDeclaration* cinfo = ClassDeclaration::classinfo;

    if (cinfo->fields.dim != 12)
    {
        error("object.d ClassInfo class is incorrect");
        fatal();
    }

    // use the rtti builder
    RTTIBuilder b(ClassDeclaration::classinfo);

    LLConstant* c;

    LLType* voidPtr = getVoidPtrType();
    LLType* voidPtrPtr = getPtrToType(voidPtr);

    // byte[] init
    if (cd->isInterfaceDeclaration())
    {
        b.push_null_void_array();
    }
    else
    {
        LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType();
        size_t initsz = getTypePaddedSize(cd_type);
        b.push_void_array(initsz, ir->getInitSymbol());
    }

    // class name
    // code from dmd
    const char *name = cd->ident->toChars();
    size_t namelen = strlen(name);
    if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
    {
        name = cd->toPrettyChars();
        namelen = strlen(name);
    }
    b.push_string(name);

    // vtbl array
    if (cd->isInterfaceDeclaration())
    {
        b.push_array(0, getNullValue(voidPtrPtr));
    }
    else
    {
        c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr);
        b.push_array(cd->vtbl.dim, c);
    }

    // interfaces array
    b.push(ir->getClassInfoInterfaces());

    // base classinfo
    // interfaces never get a base , just the interfaces[]
    if (cd->baseClass && !cd->isInterfaceDeclaration())
        b.push_classinfo(cd->baseClass);
    else
        b.push_null(cinfo->type);

    // destructor
    if (cd->isInterfaceDeclaration())
        b.push_null_vp();
    else
        b.push(build_class_dtor(cd));

    // invariant
    VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]);
    b.push_funcptr(cd->inv, invVar->type);

    // uint flags
    unsigned flags;
    if (cd->isInterfaceDeclaration())
        flags = 4 | cd->isCOMinterface() | 32;
    else
        flags = build_classinfo_flags(cd);
    b.push_uint(flags);

    // deallocator
    b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo());

    // offset typeinfo
    VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]);

#if GENERATE_OFFTI

    if (cd->isInterfaceDeclaration())
        b.push_null(offTiVar->type);
    else
        b.push(build_offti_array(cd, DtoType(offTiVar->type)));

#else // GENERATE_OFFTI

    b.push_null(offTiVar->type);

#endif // GENERATE_OFFTI

    // default constructor
    VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]);
    b.push_funcptr(cd->defaultCtor, defConstructorVar->type);

#if DMDV2
    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (cd->getRTInfo)
        b.push(cd->getRTInfo->toConstElem(gIR));
    else if (flags & 2)
        b.push_size_as_vp(0);       // no pointers
    else
        b.push_size_as_vp(1);       // has pointers
#else
    // typeinfo - since 1.045
    b.push_typeinfo(cd->type);
#endif

    /*size_t n = inits.size();
    for (size_t i=0; i<n; ++i)
    {
        Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n';
    }*/

    // build the initializer
    LLType *initType = ir->classInfo->getType()->getContainedType(0);
    LLConstant* finalinit = b.get_constant(isaStruct(initType));

    //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n';
    ir->constClassInfo = finalinit;

    // sanity check
    assert(finalinit->getType() == initType &&
        "__ClassZ initializer does not match the ClassInfo type");

    // return initializer
    return finalinit;
}
Пример #6
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;
}
Пример #7
0
  void visit(AddrExp *e) override {
    IF_LOG Logger::println("AddrExp::toConstElem: %s @ %s", e->toChars(),
                           e->type->toChars());
    LOG_SCOPE;
    // FIXME: this should probably be generalized more so we don't
    // need to have a case for each thing we can take the address of

    // address of global variable
    if (e->e1->op == TOKvar) {
      VarExp *vexp = static_cast<VarExp *>(e->e1);
      LLConstant *c = DtoConstSymbolAddress(e->loc, vexp->var);
      result = c ? DtoBitCast(c, DtoType(e->type)) : nullptr;
    }
    // address of indexExp
    else if (e->e1->op == TOKindex) {
      IndexExp *iexp = static_cast<IndexExp *>(e->e1);

      // indexee must be global static array var
      assert(iexp->e1->op == TOKvar);
      VarExp *vexp = static_cast<VarExp *>(iexp->e1);
      VarDeclaration *vd = vexp->var->isVarDeclaration();
      assert(vd);
      assert(vd->type->toBasetype()->ty == Tsarray);
      DtoResolveVariable(vd);
      assert(isIrGlobalCreated(vd));

      // get index
      LLConstant *index = toConstElem(iexp->e2);
      assert(index->getType() == DtoSize_t());

      // gep
      LLConstant *idxs[2] = {DtoConstSize_t(0), index};
      LLConstant *val = isaConstant(getIrGlobal(vd)->value);
      val = DtoBitCast(val, DtoType(vd->type->pointerTo()));
#if LDC_LLVM_VER >= 307
      LLConstant *gep = llvm::ConstantExpr::getGetElementPtr(
          isaPointer(val)->getElementType(), val, idxs, true);
#else
      LLConstant *gep = llvm::ConstantExpr::getGetElementPtr(val, idxs, true);
#endif

      // bitcast to requested type
      assert(e->type->toBasetype()->ty == Tpointer);
      result = DtoBitCast(gep, DtoType(e->type));
    } else if (e->e1->op == TOKstructliteral) {
      StructLiteralExp *se = static_cast<StructLiteralExp *>(e->e1);

      if (se->globalVar) {
        IF_LOG Logger::cout() << "Returning existing global: " << *se->globalVar
                              << '\n';
        result = se->globalVar;
        return;
      }

      se->globalVar = new llvm::GlobalVariable(
          p->module, DtoType(e->e1->type), false,
          llvm::GlobalValue::InternalLinkage, nullptr, ".structliteral");

      llvm::Constant *constValue = toConstElem(se);
      if (constValue->getType() !=
          se->globalVar->getType()->getContainedType(0)) {
        auto finalGlobalVar = new llvm::GlobalVariable(
            p->module, constValue->getType(), false,
            llvm::GlobalValue::InternalLinkage, nullptr, ".structliteral");
        se->globalVar->replaceAllUsesWith(
            DtoBitCast(finalGlobalVar, se->globalVar->getType()));
        se->globalVar->eraseFromParent();
        se->globalVar = finalGlobalVar;
      }
      se->globalVar->setInitializer(constValue);
      se->globalVar->setAlignment(DtoAlignment(se->type));

      result = se->globalVar;
    } else if (e->e1->op == TOKslice) {
      e->error("non-constant expression '%s'", e->toChars());
      if (!global.gag) {
        fatal();
      }
      result = llvm::UndefValue::get(DtoType(e->type));
    }
    // not yet supported
    else {
      e->error("constant expression '%s' not yet implemented", e->toChars());
      fatal();
    }
  }
Пример #8
0
void VarDeclaration::codegen(Ir* p)
{
    Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars());
    LOG_SCOPE;

    if (type->ty == Terror)
    {   error("had semantic errors when compiling");
        return;
    }

    // just forward aliases
    if (aliassym)
    {
        Logger::println("alias sym");
        toAlias()->codegen(p);
        return;
    }

    // output the parent aggregate first
    if (AggregateDeclaration* ad = isMember())
        ad->codegen(p);

    // global variable
    if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init))
    {
        Logger::println("data segment");

    #if 0 // TODO:
        assert(!(storage_class & STCmanifest) &&
            "manifest constant being codegen'd!");
    #endif

        // don't duplicate work
        if (this->ir.resolved) return;
        this->ir.resolved = true;
        this->ir.declared = true;

        this->ir.irGlobal = new IrGlobal(this);

        Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());

        const bool isLLConst = isConst() && init;
        const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this);

        assert(!ir.initialized);
        ir.initialized = gIR->dmodule;
        std::string llName(mangle());

        // Since the type of a global must exactly match the type of its
        // initializer, we cannot know the type until after we have emitted the
        // latter (e.g. in case of unions, …). However, it is legal for the
        // initializer to refer to the address of the variable. Thus, we first
        // create a global with the generic type (note the assignment to
        // this->ir.irGlobal->value!), and in case we also do an initializer
        // with a different type later, swap it out and replace any existing
        // uses with bitcasts to the previous type.
        llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module,
            i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName,
            isThreadlocal());
        this->ir.irGlobal->value = gvar;

        // Check if we are defining or just declaring the global in this module.
        if (!(storage_class & STCextern) && mustDefineSymbol(this))
        {
            // Build the initializer. Might use this->ir.irGlobal->value!
            LLConstant *initVal = DtoConstInitializer(loc, type, init);

            // In case of type mismatch, swap out the variable.
            if (initVal->getType() != gvar->getType()->getElementType())
            {
                llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc,
                    *gIR->module, initVal->getType(), isLLConst, llLinkage, 0,
                    "", // We take on the name of the old global below.
                    isThreadlocal());

                newGvar->takeName(gvar);

                llvm::Constant* newValue =
                    llvm::ConstantExpr::getBitCast(newGvar, gvar->getType());
                gvar->replaceAllUsesWith(newValue);

                gvar->eraseFromParent();
                gvar = newGvar;
                this->ir.irGlobal->value = newGvar;
            }

            // Now, set the initializer.
            assert(!ir.irGlobal->constInit);
            ir.irGlobal->constInit = initVal;
            gvar->setInitializer(initVal);

            // Also set up the edbug info.
            DtoDwarfGlobalVariable(gvar, this);
        }

        // Set the alignment (it is important not to use type->alignsize because
        // VarDeclarations can have an align() attribute independent of the type
        // as well).
        if (alignment != STRUCTALIGN_DEFAULT)
            gvar->setAlignment(alignment);

        // If this global is used from a naked function, we need to create an
        // artificial "use" for it, or it could be removed by the optimizer if
        // the only reference to it is in inline asm.
        if (nakedUse)
            gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType()));

        if (Logger::enabled())
            Logger::cout() << *gvar << '\n';
    }
}