Exemple #1
0
void DtoResolveStruct(StructDeclaration* sd)
{
    // Make sure to resolve each struct type exactly once.
    if (sd->ir.resolved) return;
    sd->ir.resolved = true;

    Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars());
    LOG_SCOPE;

    // make sure type exists
    DtoType(sd->type);

    // if it's a forward declaration, all bets are off. The type should be enough
    if (sd->sizeok != 1)
        return;

    // create the IrAggr
    IrAggr* irstruct = new IrAggr(sd);
    sd->ir.irStruct = irstruct;

    // Set up our field metadata.
    for (ArrayIter<VarDeclaration> it(sd->fields); !it.done(); it.next())
    {
        VarDeclaration* vd = it.get();
        assert(!vd->ir.irField);
        (void)new IrField(vd);
    }

    // perform definition
    bool emitGlobalData = mustDefineSymbol(sd);
    if (emitGlobalData)
    {
        // emit the initZ symbol
        LLGlobalVariable* initZ = irstruct->getInitSymbol();

        // set initZ initializer
        initZ->setInitializer(irstruct->getDefaultInit());
    }

    // emit members
    if (sd->members)
    {
        for (ArrayIter<Dsymbol> it(sd->members); !it.done(); it.next())
        {
            it.get()->codegen(Type::sir);
        }
    }

    if (emitGlobalData)
    {
        // emit typeinfo
        DtoTypeInfoOf(sd->type);
    }
}
Exemple #2
0
  void visit(StructDeclaration *decl) override {
    IF_LOG Logger::println("StructDeclaration::codegen: '%s'",
                           decl->toPrettyChars());
    LOG_SCOPE

    if (decl->ir->isDefined()) {
      return;
    }

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

    if (!(decl->members && decl->symtab)) {
      return;
    }

    DtoResolveStruct(decl);
    decl->ir->setDefined();

    for (auto m : *decl->members) {
      m->accept(this);
    }

    // Skip __initZ and typeinfo for @compute device code.
    // TODO: support global variables and thus __initZ
    if (!irs->dcomputetarget) {
      // Define the __initZ symbol.
      IrAggr *ir = getIrAggr(decl);
      auto &initZ = ir->getInitSymbol();
      auto initGlobal = llvm::cast<LLGlobalVariable>(initZ);
      initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit());
      setLinkage(decl, initGlobal);

      // emit typeinfo
      DtoTypeInfoOf(decl->type, /*base=*/false);
    }

    // Emit __xopEquals/__xopCmp/__xtoHash.
    if (decl->xeq && decl->xeq != decl->xerreq) {
      decl->xeq->accept(this);
    }
    if (decl->xcmp && decl->xcmp != decl->xerrcmp) {
      decl->xcmp->accept(this);
    }
    if (decl->xhash) {
      decl->xhash->accept(this);
    }
  }
Exemple #3
0
  void visit(ClassDeclaration *decl) override {
    IF_LOG Logger::println("ClassDeclaration::codegen: '%s'",
                           decl->toPrettyChars());
    LOG_SCOPE

    assert(!irs->dcomputetarget);

    if (decl->ir->isDefined()) {
      return;
    }

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

    if (decl->members && decl->symtab) {
      DtoResolveClass(decl);
      decl->ir->setDefined();

      for (auto m : *decl->members) {
        m->accept(this);
      }

      IrAggr *ir = getIrAggr(decl);
      const auto lwc = DtoLinkage(decl);

      auto &initZ = ir->getInitSymbol();
      auto initGlobal = llvm::cast<LLGlobalVariable>(initZ);
      initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit());
      setLinkage(lwc, initGlobal);

      llvm::GlobalVariable *vtbl = ir->getVtblSymbol();
      vtbl->setInitializer(ir->getVtblInit());
      setLinkage(lwc, vtbl);

      llvm::GlobalVariable *classZ = ir->getClassInfoSymbol();
      if (!isSpeculativeType(decl->type)) {
        classZ->setInitializer(ir->getClassInfoInit());
        setLinkage(lwc, classZ);
      }
    }
  }
Exemple #4
0
  void visit(TypeInfoStructDeclaration *decl) override {
    IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s",
                           decl->toChars());
    LOG_SCOPE;

    // make sure struct is resolved
    assert(decl->tinfo->ty == Tstruct);
    TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo);
    StructDeclaration *sd = tc->sym;

    // check declaration in object.d
    const auto structTypeInfoType = getStructTypeInfoType();
    const auto structTypeInfoDecl = Type::typeinfostruct;

    // On x86_64, class TypeInfo_Struct contains 2 additional fields
    // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs
    // implementation. They are not present on any other cpu/os.
    const bool isX86_64 =
        global.params.targetTriple->getArch() == llvm::Triple::x86_64;
    const unsigned expectedFields = 11 + (isX86_64 ? 2 : 0);
    const unsigned actualFields =
        structTypeInfoDecl->fields.dim -
        1; // union of xdtor/xdtorti counts as 2 overlapping fields
    if (actualFields != expectedFields) {
      error(Loc(), "Unexpected number of `object.TypeInfo_Struct` fields; "
                   "druntime version does not match compiler");
      fatal();
    }

    RTTIBuilder b(structTypeInfoType);

    // handle opaque structs
    if (!sd->members) {
      Logger::println("is opaque struct, emitting dummy TypeInfo_Struct");

      b.push_null_void_array(); // name
      b.push_null_void_array(); // m_init
      b.push_null_vp();         // xtoHash
      b.push_null_vp();         // xopEquals
      b.push_null_vp();         // xopCmp
      b.push_null_vp();         // xtoString
      b.push_uint(0);           // m_flags
      b.push_null_vp();         // xdtor/xdtorti
      b.push_null_vp();         // xpostblit
      b.push_uint(0);           // m_align
      if (isX86_64) {
        b.push_null_vp();       // m_arg1
        b.push_null_vp();       // m_arg2
      }
      b.push_null_vp();         // m_RTInfo

      b.finalize(gvar);
      return;
    }

    // can't emit typeinfo for forward declarations
    if (sd->sizeok != SIZEOKdone) {
      sd->error("cannot emit `TypeInfo` for forward declaration");
      fatal();
    }

    DtoResolveStruct(sd);

    if (TemplateInstance *ti = sd->isInstantiated()) {
      if (!ti->needsCodegen()) {
        assert(ti->minst || sd->requestTypeInfo);

        // We won't emit ti, so emit the special member functions in here.
        if (sd->xeq && sd->xeq != StructDeclaration::xerreq &&
            sd->xeq->semanticRun >= PASSsemantic3) {
          Declaration_codegen(sd->xeq);
        }
        if (sd->xcmp && sd->xcmp != StructDeclaration::xerrcmp &&
            sd->xcmp->semanticRun >= PASSsemantic3) {
          Declaration_codegen(sd->xcmp);
        }
        if (FuncDeclaration *ftostr = search_toString(sd)) {
          if (ftostr->semanticRun >= PASSsemantic3)
            Declaration_codegen(ftostr);
        }
        if (sd->xhash && sd->xhash->semanticRun >= PASSsemantic3) {
          Declaration_codegen(sd->xhash);
        }
        if (sd->postblit && sd->postblit->semanticRun >= PASSsemantic3) {
          Declaration_codegen(sd->postblit);
        }
        if (sd->dtor && sd->dtor->semanticRun >= PASSsemantic3) {
          Declaration_codegen(sd->dtor);
        }
        if (sd->tidtor && sd->tidtor->semanticRun >= PASSsemantic3) {
          Declaration_codegen(sd->tidtor);
        }
      }
    }

    IrAggr *iraggr = getIrAggr(sd);

    // string name
    b.push_string(sd->toPrettyChars());

    // void[] m_init
    // The protocol is to write a null pointer for zero-initialized arrays. The
    // length field is always needed for tsize().
    llvm::Constant *initPtr;
    if (tc->isZeroInit(Loc())) {
      initPtr = getNullValue(getVoidPtrType());
    } else {
      initPtr = iraggr->getInitSymbol();
    }
    b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr);

    // function xtoHash
    FuncDeclaration *fd = sd->xhash;
    b.push_funcptr(fd);

    // function xopEquals
    fd = sd->xeq;
    b.push_funcptr(fd);

    // function xopCmp
    fd = sd->xcmp;
    b.push_funcptr(fd);

    // function xtoString
    fd = search_toString(sd);
    b.push_funcptr(fd);

    // uint m_flags
    unsigned hasptrs = tc->hasPointers() ? 1 : 0;
    b.push_uint(hasptrs);

    // function xdtor/xdtorti
    b.push_funcptr(sd->tidtor);

    // function xpostblit
    FuncDeclaration *xpostblit = sd->postblit;
    if (xpostblit && sd->postblit->storage_class & STCdisable) {
      xpostblit = nullptr;
    }
    b.push_funcptr(xpostblit);

    // uint m_align
    b.push_uint(DtoAlignment(tc));

    if (isX86_64) {
      // TypeInfo m_arg1
      // TypeInfo m_arg2
      Type *t = sd->arg1type;
      for (unsigned i = 0; i < 2; i++) {
        if (t) {
          t = merge(t);
          b.push_typeinfo(t);
        } else {
          b.push_null(getTypeInfoType());
        }

        t = sd->arg2type;
      }
    }

    // immutable(void)* m_RTInfo
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (sd->getRTInfo) {
      b.push(toConstElem(sd->getRTInfo, gIR));
    } else if (!tc->hasPointers()) {
      b.push_size_as_vp(0); // no pointers
    } else {
      b.push_size_as_vp(1); // has pointers
    }

    // finish
    b.finalize(gvar);
  }
Exemple #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);

    IrAggr* ir = cd->ir.irAggr;
    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);

    // 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

    /*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;
}
Exemple #6
0
void DtoResolveClass(ClassDeclaration* cd)
{
    // make sure the base classes are processed first
    ArrayIter<BaseClass> base_iter(cd->baseclasses);
    while (base_iter.more())
    {
        BaseClass* bc = base_iter.get();
        if (bc)
        {
            bc->base->codegen(Type::sir);
        }
        base_iter.next();
    }

    if (cd->ir.resolved) return;
    cd->ir.resolved = true;

    Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
    LOG_SCOPE;

    // make sure type exists
    DtoType(cd->type);

    // create IrAggr
    assert(cd->ir.irAggr == NULL);
    IrAggr* irAggr = new IrAggr(cd);
    cd->ir.irAggr = irAggr;

    // make sure all fields really get their ir field
    ArrayIter<VarDeclaration> it(cd->fields);
    for (; !it.done(); it.next())
    {
        VarDeclaration* vd = it.get();
        if (vd->ir.irField == NULL) {
            new IrField(vd);
        } else {
            IF_LOG Logger::println("class field already exists!!!");
        }
    }

    bool needs_def = mustDefineSymbol(cd);

    // emit the ClassZ symbol
    LLGlobalVariable* ClassZ = irAggr->getClassInfoSymbol();

    // emit the interfaceInfosZ symbol if necessary
    if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0)
        irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built

    // interface only emit typeinfo and classinfo
    if (cd->isInterfaceDeclaration())
    {
        irAggr->initializeInterface();
    }
    else
    {
        // emit the initZ symbol
        LLGlobalVariable* initZ = irAggr->getInitSymbol();
        // emit the vtblZ symbol
        LLGlobalVariable* vtblZ = irAggr->getVtblSymbol();

        // perform definition
        if (needs_def)
        {
            // set symbol initializers
            initZ->setInitializer(irAggr->getDefaultInit());
            vtblZ->setInitializer(irAggr->getVtblInit());
        }
    }

    // emit members
    if (cd->members)
    {
        ArrayIter<Dsymbol> it(*cd->members);
        while (!it.done())
        {
            Dsymbol* member = it.get();
            if (member)
                member->codegen(Type::sir);
            it.next();
        }
    }

    if (needs_def)
    {
        // emit typeinfo
        DtoTypeInfoOf(cd->type);

        // define classinfo
        ClassZ->setInitializer(irAggr->getClassInfoInit());
    }
}
Exemple #7
0
    void visit(TypeInfoStructDeclaration *decl)
    {
        IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars());
        LOG_SCOPE;

        // make sure struct is resolved
        assert(decl->tinfo->ty == Tstruct);
        TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo);
        StructDeclaration *sd = tc->sym;

        // handle opaque structs
        if (!sd->members) {
            RTTIBuilder b(Type::typeinfostruct);
            b.finalize(getIrGlobal(decl));
            return;
        }

        // can't emit typeinfo for forward declarations
        if (sd->sizeok != SIZEOKdone)
        {
            sd->error("cannot emit TypeInfo for forward declaration");
            fatal();
        }

        DtoResolveStruct(sd);
        IrAggr* iraggr = getIrAggr(sd);

        RTTIBuilder b(Type::typeinfostruct);

        // char[] name
        b.push_string(sd->toPrettyChars());

        // void[] init
        // The protocol is to write a null pointer for zero-initialized arrays. The
        // length field is always needed for tsize().
        llvm::Constant *initPtr;
        if (tc->isZeroInit(Loc()))
            initPtr = getNullValue(getVoidPtrType());
        else
            initPtr = iraggr->getInitSymbol();
        b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr);

        // well use this module for all overload lookups

        // toHash
        FuncDeclaration* fd = sd->xhash;
        b.push_funcptr(fd);

        // opEquals
        fd = sd->xeq;
        b.push_funcptr(fd);

        // opCmp
        fd = sd->xcmp;
        b.push_funcptr(fd);

        // toString
        fd = search_toString(sd);
        b.push_funcptr(fd);

        // uint m_flags;
        unsigned hasptrs = tc->hasPointers() ? 1 : 0;
        b.push_uint(hasptrs);

        // On x86_64, class TypeInfo_Struct contains 2 additional fields
        // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs
        // implementation. They are not present on any other cpu/os.
        assert((global.params.targetTriple.getArch() != llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 11) ||
               (global.params.targetTriple.getArch() == llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 13));

        //void function(void*)                    xdtor;
        b.push_funcptr(sd->dtor);

        //void function(void*)                    xpostblit;
        FuncDeclaration *xpostblit = sd->postblit;
        if (xpostblit && sd->postblit->storage_class & STCdisable)
            xpostblit = 0;
        b.push_funcptr(xpostblit);

        //uint m_align;
        b.push_uint(tc->alignsize());

        if (global.params.is64bit)
        {
            // TypeInfo m_arg1;
            // TypeInfo m_arg2;
            Type *t = sd->arg1type;
            for (unsigned i = 0; i < 2; i++)
            {
                if (t)
                {
                    t = t->merge();
                    b.push_typeinfo(t);
                }
                else
                    b.push_null(Type::dtypeinfo->type);

                t = sd->arg2type;
            }
        }

        // immutable(void)* m_RTInfo;
        // The cases where getRTInfo is null are not quite here, but the code is
        // modelled after what DMD does.
        if (sd->getRTInfo)
            b.push(toConstElem(sd->getRTInfo, gIR));
        else if (!tc->hasPointers())
            b.push_size_as_vp(0);       // no pointers
        else
            b.push_size_as_vp(1);       // has pointers

        // finish
        b.finalize(getIrGlobal(decl));
    }