コード例 #1
0
ファイル: irclass.cpp プロジェクト: NilsBossung/ldc
LLGlobalVariable * IrStruct::getClassInfoSymbol()
{
    if (classInfo)
        return classInfo;

    // create the initZ symbol
    std::string initname("_D");
    initname.append(aggrdecl->mangle());

    if (aggrdecl->isInterfaceDeclaration())
        initname.append("11__InterfaceZ");
    else
        initname.append("7__ClassZ");

    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);

    ClassDeclaration* cinfo = ClassDeclaration::classinfo;
    DtoType(cinfo->type);
    IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass();
    assert(tc && "invalid ClassInfo type");

    // classinfos cannot be constants since they're used as locks for synchronized
    classInfo = new llvm::GlobalVariable(
        *gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname);

#if USE_METADATA
    // Generate some metadata on this ClassInfo if it's for a class.
    ClassDeclaration* classdecl = aggrdecl->isClassDeclaration();
    if (classdecl && !aggrdecl->isInterfaceDeclaration()) {
        // Gather information
        LLType* type = DtoType(aggrdecl->type);
        LLType* bodyType = llvm::cast<LLPointerType>(type)->getElementType();
        bool hasDestructor = (classdecl->dtor != NULL);
        bool hasCustomDelete = (classdecl->aggDelete != NULL);
        // Construct the fields
        MDNodeField* mdVals[CD_NumFields];
        mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType);
        mdVals[CD_Finalize] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor);
        mdVals[CD_CustomDelete] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete);
        // Construct the metadata and insert it into the module.
        llvm::SmallString<64> name;
        llvm::NamedMDNode* node = gIR->module->getOrInsertNamedMetadata(
            llvm::Twine(CD_PREFIX, initname).toStringRef(name));
        node->addOperand(llvm::MDNode::get(gIR->context(),
            llvm::makeArrayRef(mdVals, CD_NumFields)));
    }
#endif // USE_METADATA

    return classInfo;
}
コード例 #2
0
ファイル: classes.cpp プロジェクト: Philpax/ldc
DValue* DtoCastClass(Loc& loc, DValue* val, Type* _to)
{
    IF_LOG Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars());
    LOG_SCOPE;

    Type* to = _to->toBasetype();

    // class -> pointer
    if (to->ty == Tpointer) {
        IF_LOG Logger::println("to pointer");
        LLType* tolltype = DtoType(_to);
        LLValue* rval = DtoBitCast(val->getRVal(), tolltype);
        return new DImValue(_to, rval);
    }
    // class -> bool
    else if (to->ty == Tbool) {
        IF_LOG Logger::println("to bool");
        LLValue* llval = val->getRVal();
        LLValue* zero = LLConstant::getNullValue(llval->getType());
        return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero));
    }
    // class -> integer
    else if (to->isintegral()) {
        IF_LOG Logger::println("to %s", to->toChars());

        // get class ptr
        LLValue* v = val->getRVal();
        // cast to size_t
        v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), "");
        // cast to the final int type
        DImValue im(Type::tsize_t, v);
        return DtoCastInt(loc, &im, _to);
    }

    // must be class/interface
    assert(to->ty == Tclass);
    TypeClass* tc = static_cast<TypeClass*>(to);

    // from type
    Type* from = val->getType()->toBasetype();
    TypeClass* fc = static_cast<TypeClass*>(from);

    // x -> interface
    if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) {
        Logger::println("to interface");
        // interface -> interface
        if (fc->sym->isInterfaceDeclaration()) {
            Logger::println("from interface");
            return DtoDynamicCastInterface(loc, val, _to);
        }
        // class -> interface - static cast
        else if (it->isBaseOf(fc->sym,NULL)) {
            Logger::println("static down cast");

            // get the from class
            ClassDeclaration* cd = fc->sym->isClassDeclaration();
            DtoResolveClass(cd); // add this
            IrTypeClass* typeclass = stripModifiers(fc)->ctype->isClass();

            // find interface impl

            size_t i_index = typeclass->getInterfaceIndex(it);
            assert(i_index != ~0UL && "requesting interface that is not implemented by this class");

            // offset pointer
            LLValue* v = val->getRVal();
            LLValue* orig = v;
            v = DtoGEPi(v, 0, i_index);
            LLType* ifType = DtoType(_to);
            IF_LOG {
                Logger::cout() << "V = " << *v << std::endl;
                Logger::cout() << "T = " << *ifType << std::endl;
            }
            v = DtoBitCast(v, ifType);

            // Check whether the original value was null, and return null if so.
            // Sure we could have jumped over the code above in this case, but
            // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it
            // should be pretty cheap and perfectly safe even if the original was null.
            LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck");
            v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface");

            // return r-value
            return new DImValue(_to, v);
        }
コード例 #3
0
ファイル: irclass.cpp プロジェクト: NilsBossung/ldc
LLConstant * IrStruct::getClassInfoInterfaces()
{
    IF_LOG Logger::println("Building ClassInfo.interfaces");
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd);

    size_t n = interfacesWithVtbls.size();
    assert(stripModifiers(type)->irtype->isClass()->getNumInterfaceVtbls() == n &&
        "inconsistent number of interface vtables in this class");

    VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);

    if (n == 0)
        return getNullValue(DtoType(interfaces_idx->type));

// Build array of:
//
//     struct Interface
//     {
//         ClassInfo   classinfo;
//         void*[]     vtbl;
//         ptrdiff_t   offset;
//     }

    LLSmallVector<LLConstant*, 6> constants;
    constants.reserve(cd->vtblInterfaces->dim);

    LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type);
    LLType* voidptrptr_type = DtoType(
        Type::tvoid->pointerTo()->pointerTo());
    VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3);
    LLStructType* interface_type = isaStruct(DtoType(idx->type->nextOf()));
    assert(interface_type);

    for (size_t i = 0; i < n; ++i)
    {
        BaseClass* it = interfacesWithVtbls[i];

        IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars());

        IrStruct* irinter = it->base->ir.irStruct;
        assert(irinter && "interface has null IrStruct");
        IrTypeClass* itc = stripModifiers(irinter->type)->irtype->isClass();
        assert(itc && "null interface IrTypeClass");

        // classinfo
        LLConstant* ci = irinter->getClassInfoSymbol();
        ci = DtoBitCast(ci, classinfo_type);

        // vtbl
        LLConstant* vtb;
        // interface get a null
        if (cd->isInterfaceDeclaration())
        {
            vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type));
        }
        else
        {
            ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base);
            assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
            vtb = itv->second;
            vtb = DtoBitCast(vtb, voidptrptr_type);
            vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb);
        }

        // offset
        LLConstant* off = DtoConstSize_t(it->offset);

        // create Interface struct
        LLConstant* inits[3] = { ci, vtb, off };
        LLConstant* entry = LLConstantStruct::get(interface_type, llvm::makeArrayRef(inits, 3));
        constants.push_back(entry);
    }

    // create Interface[N]
    LLArrayType* array_type = llvm::ArrayType::get(interface_type, n);

    // create and apply initializer
    LLConstant* arr = LLConstantArray::get(array_type, constants);
    classInterfacesArray->setInitializer(arr);

    // return null, only baseclass provide interfaces
    if (cd->vtblInterfaces->dim == 0)
    {
        return getNullValue(DtoType(interfaces_idx->type));
    }

    // only the interface explicitly implemented by this class
    // (not super classes) should show in ClassInfo
    LLConstant* idxs[2] = {
        DtoConstSize_t(0),
        DtoConstSize_t(n - cd->vtblInterfaces->dim)
    };

    LLConstant* ptr = llvm::ConstantExpr::getGetElementPtr(
        classInterfacesArray, idxs, true);

    // return as a slice
    return DtoConstSlice( DtoConstSize_t(cd->vtblInterfaces->dim), ptr );
}
コード例 #4
0
ファイル: irclass.cpp プロジェクト: NilsBossung/ldc
void IrStruct::addBaseClassInits(
    std::vector<llvm::Constant*>& constants,
    ClassDeclaration* base,
    size_t& offset,
    size_t& field_index)
{
    if (base->baseClass)
    {
        addBaseClassInits(constants, base->baseClass, offset, field_index);
    }

    IrTypeClass* tc = stripModifiers(base->type)->irtype->isClass();
    assert(tc);

    // go through fields
    IrTypeAggr::iterator it;
    for (it = tc->def_begin(); it != tc->def_end(); ++it)
    {
        VarDeclaration* vd = *it;

        IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
        LOG_SCOPE;

        assert(vd->offset >= offset && "default fields not sorted by offset");

        // get next aligned offset for this type
        size_t alignedoffset = realignOffset(offset, vd->type);

        // insert explicit padding?
        if (alignedoffset < vd->offset)
        {
            add_zeros(constants, vd->offset - alignedoffset);
        }

        // add default type
        constants.push_back(get_default_initializer(vd, vd->init));

        // advance offset to right past this field
        offset = vd->offset + vd->type->size();
    }

    // has interface vtbls?
    if (base->vtblInterfaces && base->vtblInterfaces->dim > 0)
    {
        // false when it's not okay to use functions from super classes
        bool newinsts = (base == aggrdecl->isClassDeclaration());

        size_t inter_idx = interfacesWithVtbls.size();

        offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1);

        ArrayIter<BaseClass> it2(*base->vtblInterfaces);
        for (; !it2.done(); it2.next())
        {
            BaseClass* b = it2.get();
            constants.push_back(getInterfaceVtbl(b, newinsts, inter_idx));
            offset += PTRSIZE;

            // add to the interface list
            interfacesWithVtbls.push_back(b);
            inter_idx++;
        }
    }
}
コード例 #5
0
  void visit(ClassReferenceExp *e) override {
    IF_LOG Logger::print("ClassReferenceExp::toConstElem: %s @ %s\n",
                         e->toChars(), e->type->toChars());
    LOG_SCOPE;

    ClassDeclaration *origClass = e->originalClass();
    DtoResolveClass(origClass);
    StructLiteralExp *value = e->value;

    if (value->globalVar) {
      IF_LOG Logger::cout() << "Using existing global: " << *value->globalVar
                            << '\n';
    } else {
      value->globalVar = new llvm::GlobalVariable(
          p->module, origClass->type->ctype->isClass()->getMemoryLLType(),
          false, llvm::GlobalValue::InternalLinkage, nullptr, ".classref");

      std::map<VarDeclaration *, llvm::Constant *> varInits;

      // Unfortunately, ClassReferenceExp::getFieldAt is badly broken – it
      // places the base class fields _after_ those of the subclass.
      {
        const size_t nexprs = value->elements->dim;

        std::stack<ClassDeclaration *> classHierachy;
        ClassDeclaration *cur = origClass;
        while (cur) {
          classHierachy.push(cur);
          cur = cur->baseClass;
        }
        size_t i = 0;
        while (!classHierachy.empty()) {
          cur = classHierachy.top();
          classHierachy.pop();
          for (size_t j = 0; j < cur->fields.dim; ++j) {
            if ((*value->elements)[i]) {
              VarDeclaration *field = cur->fields[j];
              IF_LOG Logger::println("Getting initializer for: %s",
                                     field->toChars());
              LOG_SCOPE;
              varInits[field] = toConstElem((*value->elements)[i]);
            }
            ++i;
          }
        }
        assert(i == nexprs);
      }

      llvm::Constant *constValue =
          getIrAggr(origClass)->createInitializerConstant(varInits);

      if (constValue->getType() !=
          value->globalVar->getType()->getContainedType(0)) {
        auto finalGlobalVar = new llvm::GlobalVariable(
            p->module, constValue->getType(), false,
            llvm::GlobalValue::InternalLinkage, nullptr, ".classref");
        value->globalVar->replaceAllUsesWith(
            DtoBitCast(finalGlobalVar, value->globalVar->getType()));
        value->globalVar->eraseFromParent();
        value->globalVar = finalGlobalVar;
      }
      value->globalVar->setInitializer(constValue);
    }

    result = value->globalVar;

    if (e->type->ty == Tclass) {
      ClassDeclaration *targetClass = static_cast<TypeClass *>(e->type)->sym;
      if (InterfaceDeclaration *it = targetClass->isInterfaceDeclaration()) {
        assert(it->isBaseOf(origClass, NULL));

        IrTypeClass *typeclass = origClass->type->ctype->isClass();

        // find interface impl
        size_t i_index = typeclass->getInterfaceIndex(it);
        assert(i_index != ~0UL);

        // offset pointer
        result = DtoGEPi(result, 0, i_index);
      }
    }

    assert(e->type->ty == Tclass || e->type->ty == Tenum);
    result = DtoBitCast(result, DtoType(e->type));
  }
コード例 #6
0
  void visit(CastExp *e) override {
    IF_LOG Logger::print("CastExp::toConstElem: %s @ %s\n", e->toChars(),
                         e->type->toChars());
    LOG_SCOPE;

    LLType *lltype = DtoType(e->type);
    Type *tb = e->to->toBasetype();

    // string literal to dyn array:
    // reinterpret the string data as an array, calculate the length
    if (e->e1->op == TOKstring && tb->ty == Tarray) {
#if 0
            StringExp *strexp = static_cast<StringExp*>(e1);
            size_t datalen = strexp->sz * strexp->len;
            Type* eltype = tb->nextOf()->toBasetype();
            if (datalen % eltype->size() != 0) {
                error("the sizes don't line up");
                return e1->toConstElem(p);
            }
            size_t arrlen = datalen / eltype->size();
#endif
      e->error("ct cast of string to dynamic array not fully implemented");
      result = toConstElem(e->e1);
    }
    // pointer to pointer
    else if (tb->ty == Tpointer && e->e1->type->toBasetype()->ty == Tpointer) {
      result = llvm::ConstantExpr::getBitCast(toConstElem(e->e1), lltype);
    }
    // global variable to pointer
    else if (tb->ty == Tpointer && e->e1->op == TOKvar) {
      VarDeclaration *vd =
          static_cast<VarExp *>(e->e1)->var->isVarDeclaration();
      assert(vd);
      DtoResolveVariable(vd);
      LLConstant *value =
          isIrGlobalCreated(vd) ? isaConstant(getIrGlobal(vd)->value) : nullptr;
      if (!value) {
        goto Lerr;
      }
      Type *type = vd->type->toBasetype();
      if (type->ty == Tarray || type->ty == Tdelegate) {
        LLConstant *idxs[2] = {DtoConstSize_t(0), DtoConstSize_t(1)};
#if LDC_LLVM_VER >= 307
        value = llvm::ConstantExpr::getGetElementPtr(
            isaPointer(value)->getElementType(), value, idxs, true);
#else
        value = llvm::ConstantExpr::getGetElementPtr(value, idxs, true);
#endif
      }
      result = DtoBitCast(value, DtoType(tb));
    } else if (tb->ty == Tclass && e->e1->type->ty == Tclass &&
               e->e1->op == TOKclassreference) {
      auto cd = static_cast<ClassReferenceExp *>(e->e1)->originalClass();
      llvm::Constant *instance = toConstElem(e->e1);
      if (InterfaceDeclaration *it =
              static_cast<TypeClass *>(tb)->sym->isInterfaceDeclaration()) {
        assert(it->isBaseOf(cd, NULL));

        IrTypeClass *typeclass = cd->type->ctype->isClass();

        // find interface impl
        size_t i_index = typeclass->getInterfaceIndex(it);
        assert(i_index != ~0UL);

        // offset pointer
        instance = DtoGEPi(instance, 0, i_index);
      }
      result = DtoBitCast(instance, DtoType(tb));
    } else {
      goto Lerr;
    }
    return;

  Lerr:
    e->error("cannot cast %s to %s at compile time", e->e1->type->toChars(),
             e->type->toChars());
    if (!global.gag) {
      fatal();
    }
    result = llvm::UndefValue::get(DtoType(e->type));
  }