Пример #1
0
DValue *binMin(Loc &loc, Type *type, DValue *lhs, Expression *rhs,
               bool loadLhsAfterRhs) {
  Type *lhsType = lhs->type->toBasetype();
  Type *rhsType = rhs->type->toBasetype();

  if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) {
    Logger::println("Subtracting integer from pointer");
    return emitPointerOffset(loc, lhs, rhs, true, type, loadLhsAfterRhs);
  }

  auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs);

  if (lhsType->ty == Tpointer && rhsType->ty == Tpointer) {
    LLValue *l = DtoRVal(rvals.lhs);
    LLValue *r = DtoRVal(rvals.rhs);
    LLType *llSizeT = DtoSize_t();
    l = gIR->ir->CreatePtrToInt(l, llSizeT);
    r = gIR->ir->CreatePtrToInt(r, llSizeT);
    LLValue *diff = gIR->ir->CreateSub(l, r);
    LLType *llType = DtoType(type);
    if (diff->getType() != llType)
      diff = gIR->ir->CreateIntToPtr(diff, llType);
    return new DImValue(type, diff);
  }

  if (type->ty == Tnull)
    return DtoNullValue(type, loc);
  if (type->iscomplex())
    return DtoComplexMin(loc, type, rvals.lhs, rvals.rhs);

  LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type));
  LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type));

  if (auto aa = isAssociativeArrayAndNull(type, l, r))
    return aa;

  LLValue *res = (type->isfloating() ? gIR->ir->CreateFSub(l, r)
                                     : gIR->ir->CreateSub(l, r));

  return new DImValue(type, res);
}
Пример #2
0
LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs)
{
    Type* t = lhs->getType()->toBasetype();
    assert(t->ty == Tstruct);

    // set predicate
    llvm::ICmpInst::Predicate cmpop;
    if (op == TOKequal || op == TOKidentity)
        cmpop = llvm::ICmpInst::ICMP_EQ;
    else
        cmpop = llvm::ICmpInst::ICMP_NE;

    // empty struct? EQ always true, NE always false
    if (static_cast<TypeStruct*>(t)->sym->fields.dim == 0)
        return DtoConstBool(cmpop == llvm::ICmpInst::ICMP_EQ);

    // call memcmp
    size_t sz = getTypePaddedSize(DtoType(t));
    LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz));
    return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false));
}
Пример #3
0
LLStructType* DtoModuleReferenceType()
{
    if (gIR->moduleRefType)
        return gIR->moduleRefType;

    // this is a recursive type so start out with a struct without body
    LLStructType* st = LLStructType::create(gIR->context(), "ModuleReference");

    // add members
    LLType *types[] = {
        getPtrToType(st),
        DtoType(Module::moduleinfo->type->pointerTo())
    };

    // resolve type
    st->setBody(types);

    // done
    gIR->moduleRefType = st;
    return st;
}
Пример #4
0
LLValue *DtoBinFloatsEquals(Loc &loc, DValue *lhs, DValue *rhs, TOK op) {
  LLValue *res = nullptr;
  if (op == TOKequal || op == TOKnotequal) {
    LLValue *l = DtoRVal(lhs);
    LLValue *r = DtoRVal(rhs);
    res = (op == TOKequal ? gIR->ir->CreateFCmpOEQ(l, r)
                          : gIR->ir->CreateFCmpUNE(l, r));
    if (lhs->type->toBasetype()->ty == Tvector) {
      res = mergeVectorEquals(res, op);
    }
  } else {
    const auto cmpop =
        op == TOKidentity ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE;
    LLValue *sz = DtoConstSize_t(getTypeStoreSize(DtoType(lhs->type)));
    LLValue *val = DtoMemCmp(makeLValue(loc, lhs), makeLValue(loc, rhs), sz);
    res = gIR->ir->CreateICmp(cmpop, val,
                              LLConstantInt::get(val->getType(), 0, false));
  }
  assert(res);
  return res;
}
Пример #5
0
void RTTIBuilder::push_array(llvm::Constant *CI, uint64_t dim, Type *valtype,
                             Dsymbol *mangle_sym) {
  std::string tmpStr(valtype->arrayOf()->toChars());
  tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), '['), tmpStr.end());
  tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), ']'), tmpStr.end());
  tmpStr.append("arr");

  std::string initname(mangle_sym ? mangle(mangle_sym) : ".ldc");
  initname.append(".rtti.");
  initname.append(tmpStr);
  initname.append(".data");

  const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT());

  auto G = new LLGlobalVariable(gIR->module, CI->getType(), true,
                                lwc.first, CI, initname);
  setLinkage(lwc, G);
  G->setAlignment(DtoAlignment(valtype));

  push_array(dim, DtoBitCast(G, DtoType(valtype->pointerTo())));
}
Пример #6
0
llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
{
    // handle for C vararg intrinsics
    if (DtoIsVaIntrinsic(fdecl))
        return DtoVaFunctionType(fdecl);

    Type *dthis=0, *dnest=0;

    if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) {
        FuncDeclaration *p = fdecl->parent->isFuncDeclaration();
        assert(p);
        AggregateDeclaration *ad = p->isMember2();
        assert(ad);
        dnest = Type::tvoid->pointerTo();
    } else
    if (fdecl->needThis()) {
        if (AggregateDeclaration* ad = fdecl->isMember2()) {
            IF_LOG Logger::println("isMember = this is: %s", ad->type->toChars());
            dthis = ad->type;
            LLType* thisty = DtoType(dthis);
            //Logger::cout() << "this llvm type: " << *thisty << '\n';
            if (ad->isStructDeclaration())
                thisty = getPtrToType(thisty);
        }
        else {
            IF_LOG Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind());
            llvm_unreachable("needThis, but invalid parent declaration.");
        }
    }
    else if (fdecl->isNested()) {
        dnest = Type::tvoid->pointerTo();
    }

    LLFunctionType* functype = DtoFunctionType(fdecl->type, getIrFunc(fdecl, true)->irFty, dthis, dnest,
                                               fdecl->isMain(), fdecl->isCtorDeclaration(),
                                               fdecl->llvmInternal == LLVMintrinsic);

    return functype;
}
Пример #7
0
void TypeInfoEnumDeclaration::llvmDefine()
{
    Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    RTTIBuilder b(Type::typeinfoenum);

    assert(tinfo->ty == Tenum);
    TypeEnum *tc = static_cast<TypeEnum *>(tinfo);
    EnumDeclaration *sd = tc->sym;

    // TypeInfo base
    b.push_typeinfo(sd->memtype);

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

    // void[] init
    // emit void[] with the default initialier, the array is null if the default
    // initializer is zero
    if (!sd->defaultval || tinfo->isZeroInit(0))
    {
        b.push_null_void_array();
    }
    // otherwise emit a void[] with the default initializer
    else
    {
        LLType* memty = DtoType(sd->memtype);
#if DMDV2
        LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !isLLVMUnsigned(sd->memtype));
#else
        LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !isLLVMUnsigned(sd->memtype));
#endif
        b.push_void_array(C, sd->memtype, sd);
    }

    // finish
    b.finalize(ir.irGlobal);
}
Пример #8
0
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name)
{
    // sanity checks
    assert(fdecl->isVirtual());
    assert(!fdecl->isFinal());
    assert(fdecl->vtblIndex > 0); // 0 is always ClassInfo/Interface*
    assert(inst->getType()->toBasetype()->ty == Tclass);

    // get instance
    LLValue* vthis = inst->getRVal();
    if (Logger::enabled())
        Logger::cout() << "vthis: " << *vthis << '\n';

    LLValue* funcval = vthis;
    // get the vtbl for objects
    funcval = DtoGEPi(funcval, 0, 0, "tmp");
    // load vtbl ptr
    funcval = DtoLoad(funcval);
    // index vtbl
    std::string vtblname = name;
    vtblname.append("@vtbl");
    funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str());
    // load funcptr
    funcval = DtoAlignedLoad(funcval);

    if (Logger::enabled())
        Logger::cout() << "funcval: " << *funcval << '\n';

    // cast to final funcptr type
    funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type)));

    // postpone naming until after casting to get the name in call instructions
    funcval->setName(name);

    if (Logger::enabled())
        Logger::cout() << "funcval casted: " << *funcval << '\n';

    return funcval;
}
Пример #9
0
DValue* DtoCastInterfaceToObject(DValue* val, Type* to)
{
    // call:
    // Object _d_toObject(void* p)

    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject");
    LLFunctionType* funcTy = func->getFunctionType();

    // void* p
    LLValue* tmp = val->getRVal();
    tmp = DtoBitCast(tmp, funcTy->getParamType(0));

    // call it
    LLValue* ret = gIR->CreateCallOrInvoke(func, tmp, "tmp").getInstruction();

    // cast return value
    if (to != NULL)
        ret = DtoBitCast(ret, DtoType(to));
    else
        to = ClassDeclaration::object->type;

    return new DImValue(to, ret);
}
Пример #10
0
LLStructType* DtoInterfaceInfoType()
{
    if (gIR->interfaceInfoType)
        return gIR->interfaceInfoType;

    // build interface info type
    LLSmallVector<LLType*, 3> types;
    // ClassInfo classinfo
    ClassDeclaration* cd2 = ClassDeclaration::classinfo;
    DtoResolveClass(cd2);
    types.push_back(DtoType(cd2->type));
    // void*[] vtbl
    LLSmallVector<LLType*, 2> vtbltypes;
    vtbltypes.push_back(DtoSize_t());
    LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::getInt8Ty(gIR->context())));
    vtbltypes.push_back(byteptrptrty);
    types.push_back(LLStructType::get(gIR->context(), vtbltypes));
    // int offset
    types.push_back(LLType::getInt32Ty(gIR->context()));
    // create type
    gIR->interfaceInfoType = LLStructType::get(gIR->context(), types);

    return gIR->interfaceInfoType;
}
Пример #11
0
LLConstant *DtoConstFP(Type *t, longdouble value) {
  LLType *llty = DtoType(t);
  assert(llty->isFloatingPointTy());

  if (llty == LLType::getFloatTy(gIR->context()) ||
      llty == LLType::getDoubleTy(gIR->context())) {
    return LLConstantFP::get(llty, value);
  }
  if (llty == LLType::getX86_FP80Ty(gIR->context())) {
    uint64_t bits[] = {0, 0};
    bits[0] = *reinterpret_cast<uint64_t *>(&value);
    bits[1] =
        *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1);
    return LLConstantFP::get(gIR->context(), APFloat(APFloat::x87DoubleExtended,
                                                     APInt(80, 2, bits)));
  }
  if (llty == LLType::getFP128Ty(gIR->context())) {
    union {
      longdouble ld;
      uint64_t bits[2];
    } t;
    t.ld = value;
    return LLConstantFP::get(gIR->context(),
                             APFloat(APFloat::IEEEquad, APInt(128, 2, t.bits)));
  }
  if (llty == LLType::getPPC_FP128Ty(gIR->context())) {
    uint64_t bits[] = {0, 0};
    bits[0] = *reinterpret_cast<uint64_t *>(&value);
    bits[1] =
        *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1);
    return LLConstantFP::get(
        gIR->context(), APFloat(APFloat::PPCDoubleDouble, APInt(128, 2, bits)));
  }

  llvm_unreachable("Unknown floating point type encountered");
}
Пример #12
0
void DtoResolveClass(ClassDeclaration *cd) {
  if (cd->ir->isResolved()) {
    return;
  }
  cd->ir->setResolved();

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

  // make sure the base classes are processed first
  for (auto bc : *cd->baseclasses) {
    DtoResolveClass(bc->sym);
  }

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

  // create IrAggr
  IrAggr *irAggr = getIrAggr(cd, true);

  // make sure all fields really get their ir field
  for (auto vd : cd->fields) {
    IF_LOG {
      if (isIrFieldCreated(vd)) {
        Logger::println("class field already exists");
      }
    }
    getIrField(vd, true);
  }

  // interface only emit typeinfo and classinfo
  if (cd->isInterfaceDeclaration()) {
    irAggr->initializeInterface();
  }
}
Пример #13
0
IrTypePointer* IrTypePointer::get(Type* dt)
{
    assert(!dt->ctype);
    assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type");

    LLType* elemType;
    if (dt->ty == Tnull)
    {
        elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext());
    }
    else
    {
        elemType = i1ToI8(voidToI8(DtoType(dt->nextOf())));

        // DtoType could have already created the same type, e.g. for
        // dt == Node* in struct Node { Node* n; }.
        if (dt->ctype)
            return dt->ctype->isPointer();
    }

    IrTypePointer* t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0));
    dt->ctype = t;
    return t;
}
Пример #14
0
DValue* DtoDynamicCastObject(DValue* val, Type* _to)
{
    // call:
    // Object _d_dynamic_cast(Object o, ClassInfo c)

    ClassDeclaration::object->codegen(Type::sir);
    ClassDeclaration::classinfo->codegen(Type::sir);

    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast");
    LLFunctionType* funcTy = func->getFunctionType();

    std::vector<LLValue*> args;

    // Object o
    LLValue* obj = val->getRVal();
    obj = DtoBitCast(obj, funcTy->getParamType(0));
    assert(funcTy->getParamType(0) == obj->getType());

    // ClassInfo c
    TypeClass* to = static_cast<TypeClass*>(_to->toBasetype());
    to->sym->codegen(Type::sir);

    LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol();
    // unfortunately this is needed as the implementation of object differs somehow from the declaration
    // this could happen in user code as well :/
    cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
    assert(funcTy->getParamType(1) == cinfo->getType());

    // call it
    LLValue* ret = gIR->CreateCallOrInvoke2(func, obj, cinfo, "tmp").getInstruction();

    // cast return value
    ret = DtoBitCast(ret, DtoType(_to));

    return new DImValue(_to, ret);
}
Пример #15
0
DValue* DtoNestedVariable(Loc& loc, Type* astype, VarDeclaration* vd, bool byref)
{
    IF_LOG Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars());
    LOG_SCOPE;

    ////////////////////////////////////
    // Locate context value

    Dsymbol* vdparent = vd->toParent2();
    assert(vdparent);

    IrFunction* irfunc = gIR->func();

    // Check whether we can access the needed frame
    FuncDeclaration *fd = irfunc->decl;
    while (fd != vdparent) {
        if (fd->isStatic()) {
            error(loc, "function %s cannot access frame of function %s", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars());
            return new DVarValue(astype, vd, llvm::UndefValue::get(getPtrToType(DtoType(astype))));
        }
        fd = getParentFunc(fd, false);
        assert(fd);
    }

    // is the nested variable in this scope?
    if (vdparent == irfunc->decl)
    {
        LLValue* val = vd->ir.getIrValue();
        return new DVarValue(astype, vd, val);
    }

    LLValue *dwarfValue = 0;
    std::vector<LLValue*> dwarfAddr;

    // get the nested context
    LLValue* ctx = 0;
    if (irfunc->nestedVar) {
        // If this function has its own nested context struct, always load it.
        ctx = irfunc->nestedVar;
        dwarfValue = ctx;
    } else if (irfunc->decl->isMember2()) {
        // If this is a member function of a nested class without its own
        // context, load the vthis member.
        AggregateDeclaration* cd = irfunc->decl->isMember2();
        LLValue* val = irfunc->thisArg;
        if (cd->isClassDeclaration())
            val = DtoLoad(val);
        ctx = DtoLoad(DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis"));
    } else {
        // Otherwise, this is a simple nested function, load from the context
        // argument.
        ctx = DtoLoad(irfunc->nestArg);
        dwarfValue = irfunc->nestArg;
        if (global.params.symdebug)
            gIR->DBuilder.OpDeref(dwarfAddr);
    }
    assert(ctx);

    DtoCreateNestedContextType(vdparent->isFuncDeclaration());
    assert(vd->ir.irLocal);

    ////////////////////////////////////
    // Extract variable from nested context

    LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType));
    IF_LOG {
        Logger::cout() << "Context: " << *val << '\n';
        Logger::cout() << "of type: " << *irfunc->frameType << '\n';
    }

    unsigned vardepth = vd->ir.irLocal->nestedDepth;
    unsigned funcdepth = irfunc->depth;

    IF_LOG {
        Logger::cout() << "Variable: " << vd->toChars() << '\n';
        Logger::cout() << "Variable depth: " << vardepth << '\n';
        Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n';
        Logger::cout() << "Function depth: " << funcdepth << '\n';
    }

    if (vardepth == funcdepth) {
        // This is not always handled above because functions without
        // variables accessed by nested functions don't create new frames.
        IF_LOG Logger::println("Same depth");
    } else {
        // Load frame pointer and index that...
        if (dwarfValue && global.params.symdebug) {
            gIR->DBuilder.OpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth);
            gIR->DBuilder.OpDeref(dwarfAddr);
        }
        IF_LOG Logger::println("Lower depth");
        val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
        IF_LOG Logger::cout() << "Frame index: " << *val << '\n';
        val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str());
        IF_LOG Logger::cout() << "Frame: " << *val << '\n';
    }

    int idx = vd->ir.irLocal->nestedIndex;
    assert(idx != -1 && "Nested context not yet resolved for variable.");

    if (dwarfValue && global.params.symdebug)
        gIR->DBuilder.OpOffset(dwarfAddr, val, idx);

    val = DtoGEPi(val, 0, idx, vd->toChars());
    IF_LOG {
        Logger::cout() << "Addr: " << *val << '\n';
        Logger::cout() << "of type: " << *val->getType() << '\n';
    }
    if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) {
        val = DtoAlignedLoad(val);
        //dwarfOpDeref(dwarfAddr);
        IF_LOG {
            Logger::cout() << "Was byref, now: " << *val << '\n';
            Logger::cout() << "of type: " << *val->getType() << '\n';
        }
    }
Пример #16
0
void IrTypeClass::addBaseClassData(
    std::vector<llvm::Type *> & defaultTypes,
    ClassDeclaration * base,
    size_t & offset,
    size_t & field_index)
{
    if (base->baseClass)
    {
        addBaseClassData(defaultTypes, base->baseClass, offset, field_index);
    }

    // FIXME: merge code with structs in IrTypeAggr

    // mirror the sd->fields array but only fill in contributors
    size_t n = base->fields.dim;
    LLSmallVector<VarDeclaration*, 16> data(n, NULL);
    default_fields.reserve(n);

    // first fill in the fields with explicit initializers
    VarDeclarationIter field_it(base->fields);
    for (; field_it.more(); field_it.next())
    {
        // init is !null for explicit inits
        if (field_it->init != NULL)
        {
            IF_LOG Logger::println("adding explicit initializer for struct field %s",
                field_it->toChars());

            data[field_it.index] = *field_it;

            size_t f_begin = field_it->offset;
            size_t f_end = f_begin + field_it->type->size();

            // make sure there is no overlap
            for (size_t i = 0; i < field_it.index; i++)
            {
                if (data[i] != NULL)
                {
                    VarDeclaration* vd = data[i];
                    size_t v_begin = vd->offset;
                    size_t v_end = v_begin + vd->type->size();

                    if (v_begin >= f_end || v_end <= f_begin)
                        continue;

                    base->error(vd->loc, "has overlapping initialization for %s and %s",
                        field_it->toChars(), vd->toChars());
                }
            }
        }
    }

    if (global.errors)
    {
        fatal();
    }

    // fill in default initializers
    field_it = VarDeclarationIter(base->fields);
    for (;field_it.more(); field_it.next())
    {
        if (data[field_it.index])
            continue;

        size_t f_begin = field_it->offset;
        size_t f_end = f_begin + field_it->type->size();

        // make sure it doesn't overlap anything explicit
        bool overlaps = false;
        for (size_t i = 0; i < n; i++)
        {
            if (data[i])
            {
                size_t v_begin = data[i]->offset;
                size_t v_end = v_begin + data[i]->type->size();

                if (v_begin >= f_end || v_end <= f_begin)
                    continue;

                overlaps = true;
                break;
            }
        }

        // if no overlap was found, add the default initializer
        if (!overlaps)
        {
            IF_LOG Logger::println("adding default initializer for struct field %s",
                field_it->toChars());
            data[field_it.index] = *field_it;
        }
    }

    // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary.

    // first we sort the list by offset
    std::sort(data.begin(), data.end(), var_offset_sort_cb);

    // add types to list
    for (size_t i = 0; i < n; i++)
    {
        VarDeclaration* vd = data[i];

        if (vd == NULL)
            continue;

        assert(vd->offset >= offset && "it's a bug... most likely DMD bug 2481");

        // add to default field list
        if (cd == base)
            default_fields.push_back(vd);

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

        // insert explicit padding?
        if (alignedoffset < vd->offset)
        {
            field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
        }

        // add default type
        defaultTypes.push_back(DtoType(vd->type));

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

        // create ir field
        vd->aggrIndex = (unsigned)field_index;
        ++field_index;
    }

    // any interface implementations?
    if (base->vtblInterfaces && base->vtblInterfaces->dim > 0)
    {
        bool new_instances = (base == cd);

        ArrayIter<BaseClass> it2(*base->vtblInterfaces);

        VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
	Type* first = interfaces_idx->type->nextOf()->pointerTo();

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

        for (; !it2.done(); it2.next())
        {
            BaseClass* b = it2.get();
            IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars());

            FuncDeclarations arr;
            b->fillVtbl(cd, &arr, new_instances);

            llvm::Type* ivtbl_type = llvm::StructType::get(gIR->context(), buildVtblType(first, &arr));
            defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0));

            offset += PTRSIZE;

            // add to the interface map
            addInterfaceToMap(b->base, field_index);
            field_index++;

            // inc count
            num_interface_vtbls++;
        }
    }

#if 0
    // tail padding?
    if (offset < base->structsize)
    {
        field_index += add_zeros(defaultTypes, base->structsize - offset);
        offset = base->structsize;
    }
#endif
}
Пример #17
0
std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd,
                                                 const std::vector<llvm::Value*>& inits,
                                                 bool isConst)
{
    // 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<llvm::Value*> 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);

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

        // add the expression value
        values.push_back(inits[i]);

        // update offsets
        lastoffset = os;
#if DMDV2
        // sometimes size of the initializer is less than size of the variable,
        // so make sure that lastsize is correct
        if (inits[i]->getType()->isSized())
            lastsize = ceil(gTargetData->getTypeSizeInBits(inits[i]->getType()) / 8.0);
        else
#endif
        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;
}
Пример #18
0
IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt, llvm::BasicBlock* end)
: finallyBody(NULL)
{
    target = llvm::BasicBlock::Create(gIR->context(), "catch", gIR->topfunc(), end);
    gIR->scope() = IRScope(target,end);

    // assign storage to catch var
    if(catchstmt->var) {
        // use the same storage for all exceptions that are not accessed in
        // nested functions
    #if DMDV2
        if(!catchstmt->var->nestedrefs.dim) {
    #else
        if(!catchstmt->var->nestedref) {
    #endif
            assert(!catchstmt->var->ir.irLocal);
            catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var);
            LLValue* catch_var = gIR->func()->gen->landingPadInfo.getExceptionStorage();
            catchstmt->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(catchstmt->var->type)));
        }

        // this will alloca if we haven't already and take care of nested refs
        DtoDeclarationExp(catchstmt->var);

        // the exception will only be stored in catch_var. copy it over if necessary
        if(catchstmt->var->ir.irLocal->value != gIR->func()->gen->landingPadInfo.getExceptionStorage()) {
            LLValue* exc = gIR->ir->CreateBitCast(DtoLoad(gIR->func()->gen->landingPadInfo.getExceptionStorage()), DtoType(catchstmt->var->type));
            DtoStore(exc, catchstmt->var->ir.irLocal->value);
        }
    }

    // emit handler, if there is one
    // handler is zero for instance for 'catch { debug foo(); }'
    if(catchstmt->handler)
        catchstmt->handler->toIR(gIR);

    if (!gIR->scopereturned())
        gIR->ir->CreateBr(end);

    assert(catchstmt->type);
    catchType = catchstmt->type->toBasetype()->isClassHandle();
    assert(catchType);
    catchType->codegen(Type::sir);
}

IRLandingPadInfo::IRLandingPadInfo(Statement* finallystmt)
: target(NULL), finallyBody(finallystmt), catchType(NULL)
{

}


void IRLandingPad::addCatch(Catch* catchstmt, llvm::BasicBlock* end)
{
    unpushed_infos.push_front(IRLandingPadInfo(catchstmt, end));
}
Пример #19
0
DValue* DtoNewClass(Loc& loc, TypeClass* tc, NewExp* newexp)
{
    // resolve type
    DtoResolveClass(tc->sym);

    // allocate
    LLValue* mem;
    if (newexp->onstack)
    {
        // FIXME align scope class to its largest member
        mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), 0, ".newclass_alloca");
    }
    // custom allocator
    else if (newexp->allocator)
    {
        DtoResolveFunction(newexp->allocator);
        DFuncValue dfn(newexp->allocator, getIrFunc(newexp->allocator)->func);
        DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs);
        mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom");
    }
    // default allocator
    else
    {
        llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_newclass");
        LLConstant* ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type));
        mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction();
        mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc");
    }

    // init
    DtoInitClass(tc, mem);

    // init inner-class outer reference
    if (newexp->thisexp)
    {
        Logger::println("Resolving outer class");
        LOG_SCOPE;
        DValue* thisval = toElem(newexp->thisexp);
        unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
        LLValue* src = thisval->getRVal();
        LLValue* dst = DtoGEPi(mem, 0, idx);
        IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
        DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType())));
    }
    // set the context for nested classes
    else if (tc->sym->isNested() && tc->sym->vthis)
    {
        DtoResolveNestedContext(loc, tc->sym, mem);
    }

    // call constructor
    if (newexp->member)
    {
        Logger::println("Calling constructor");
        assert(newexp->arguments != NULL);
        DtoResolveFunction(newexp->member);
        DFuncValue dfn(newexp->member, getIrFunc(newexp->member)->func, mem);
        return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments);
    }

    // return default constructed class
    return new DImValue(tc, mem);
}
Пример #20
0
DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {
  // D2:
  // call:
  // extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void*
  // pkey)
  // or
  // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)

  // first get the runtime function
  llvm::Function *func = getRuntimeFunction(
      loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
  LLFunctionType *funcTy = func->getFunctionType();

  // aa param
  LLValue *aaval = lvalue ? aa->getLVal() : aa->getRVal();
  aaval = DtoBitCast(aaval, funcTy->getParamType(0));

  // pkey param
  LLValue *pkey = makeLValue(loc, key);
  pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2));

  // call runtime
  LLValue *ret;
  if (lvalue) {
    LLValue *rawAATI =
        DtoTypeInfoOf(aa->type->unSharedOf()->mutableOf(), false);
    LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1));
    LLValue *valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
    ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey,
                                  "aa.index")
              .getInstruction();
  } else {
    LLValue *keyti = DtoBitCast(to_keyti(aa), funcTy->getParamType(1));
    ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index")
              .getInstruction();
  }

  // cast return value
  LLType *targettype = DtoPtrToType(type);
  if (ret->getType() != targettype) {
    ret = DtoBitCast(ret, targettype);
  }

  // Only check bounds for rvalues ('aa[key]').
  // Lvalue use ('aa[key] = value') auto-adds an element.
  if (!lvalue && gIR->emitArrayBoundsChecks()) {
    llvm::BasicBlock *failbb = llvm::BasicBlock::Create(
        gIR->context(), "aaboundscheckfail", gIR->topfunc());
    llvm::BasicBlock *okbb =
        llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc());

    LLValue *nullaa = LLConstant::getNullValue(ret->getType());
    LLValue *cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck");
    gIR->ir->CreateCondBr(cond, okbb, failbb);

    // set up failbb to call the array bounds error runtime function

    gIR->scope() = IRScope(failbb);

    llvm::Function *errorfn =
        getRuntimeFunction(loc, gIR->module, "_d_arraybounds");
    gIR->CreateCallOrInvoke(
        errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc),
        DtoConstUint(loc.linnum));

    // the function does not return
    gIR->ir->CreateUnreachable();

    // if ok, proceed in okbb
    gIR->scope() = IRScope(okbb);
  }
  return new DVarValue(type, ret);
}
Пример #21
0
void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
{
    // save and rewrite scope
    IRScope savedscope = gIR->scope();
    gIR->scope() = IRScope(inBB,savedscope.end);

    // personality fn
    llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
    // create landingpad
    LLType *retType = LLStructType::get(LLType::getInt8PtrTy(gIR->context()), LLType::getInt32Ty(gIR->context()), NULL);
    llvm::LandingPadInst *landingPad = gIR->ir->CreateLandingPad(retType, personality_fn, 0);
    LLValue* eh_ptr = DtoExtractValue(landingPad, 0);
    LLValue* eh_sel = DtoExtractValue(landingPad, 1);

    // add landingpad clauses, emit finallys and 'if' chain to catch the exception
    llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for);
    std::deque<IRLandingPadInfo> infos = this->infos;
    std::stack<size_t> nInfos = this->nInfos;
    std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend();
    bool isFirstCatch = true;
    for(rit = infos.rbegin(); rit != rend; ++rit)
    {
        // if it's a finally, emit its code
        if(rit->finallyBody)
        {
            size_t n = this->nInfos.top();
            this->infos.resize(n);
            this->nInfos.pop();
            rit->finallyBody->toIR(gIR);
            landingPad->setCleanup(true);
        }
        // otherwise it's a catch and we'll add a if-statement
        else
        {
            // if it is a first catch and some catch allocated storage, store exception object
            if(isFirstCatch && catch_var)
            {
                LLType* objectTy = DtoType(ClassDeclaration::object->type);
                gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
                isFirstCatch = false;
            }
            // create next block
            llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend());
            // get class info symbol
            LLValue *classInfo = rit->catchType->ir.irStruct->getClassInfoSymbol();
            // add that symbol as landing pad clause
            landingPad->addClause(classInfo);
            // call llvm.eh.typeid.for to get class info index in the exception table
            classInfo = DtoBitCast(classInfo, getPtrToType(DtoType(Type::tint8)));
            LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo);
            // check exception selector (eh_sel) against the class info index
            gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next);
            gIR->scope() = IRScope(next, gIR->scopeend());
        }
    }

    // restore landing pad infos
    this->infos = infos;
    this->nInfos = nInfos;

    // no catch matched and all finallys executed - resume unwind
    llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind");
    gIR->ir->CreateCall(unwind_resume_fn, eh_ptr);
    gIR->ir->CreateUnreachable();

    // restore scope
    gIR->scope() = savedscope;
}
Пример #22
0
LLConstant * IrStruct::getVtblInit()
{
    if (constVtbl)
        return constVtbl;

    IF_LOG Logger::println("Building vtbl initializer");
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd && "not class");

    std::vector<llvm::Constant*> constants;
    constants.reserve(cd->vtbl.dim);

    // start with the classinfo
    llvm::Constant* c = getClassInfoSymbol();
    c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type));
    constants.push_back(c);

    // add virtual function pointers
    size_t n = cd->vtbl.dim;
    for (size_t i = 1; i < n; i++)
    {
        Dsymbol* dsym = static_cast<Dsymbol*>(cd->vtbl.data[i]);
        assert(dsym && "null vtbl member");

        FuncDeclaration* fd = dsym->isFuncDeclaration();
        assert(fd && "vtbl entry not a function");

        if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody))
        {
            c = getNullValue(DtoType(fd->type->pointerTo()));
        }
        else
        {
            fd->codegen(Type::sir);
            assert(fd->ir.irFunc && "invalid vtbl function");
            c = fd->ir.irFunc->func;
#if DMDV2
            if (cd->isFuncHidden(fd))
            {   /* fd is hidden from the view of this class.
                 * If fd overlaps with any function in the vtbl[], then
                 * issue 'hidden' error.
                 */
                for (size_t j = 1; j < n; j++)
                {   if (j == i)
                        continue;
                    FuncDeclaration *fd2 = static_cast<Dsymbol *>(cd->vtbl.data[j])->isFuncDeclaration();
                    if (!fd2->ident->equals(fd->ident))
                        continue;
                    if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd))
                    {
                        if (global.params.warnings)
                        {
                            TypeFunction *tf = static_cast<TypeFunction *>(fd->type);
                            if (tf->ty == Tfunction)
                                error("%s%s is hidden by %s\n", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), toChars());
                            else
                                error("%s is hidden by %s\n", fd->toPrettyChars(), toChars());
                        }
                        c = DtoBitCast(LLVM_D_GetRuntimeFunction(gIR->module, "_d_hidden_func"), c->getType());
                        break;
                    }
                }
            }
#endif
        }
        constants.push_back(c);
    }

    // build the constant struct
    LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl();
    constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants);

#if 0
   IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl;
   IF_LOG Logger::cout() << "vtbl type: " << *stripModifiers(type)->irtype->isClass()->getVtbl() << std::endl;
#endif

#if 0

    size_t nc = constants.size();

    for (size_t i = 0; i < nc; ++i)
    {
        if (constVtbl->getOperand(i)->getType() != vtblTy->getContainedType(i))
        {
            Logger::cout() << "type mismatch for entry # " << i << " in vtbl initializer" << std::endl;

            constVtbl->getOperand(i)->dump();
            vtblTy->getContainedType(i)->dump();
        }
    }

#endif

    assert(constVtbl->getType() == stripModifiers(type)->irtype->isClass()->getVtbl() &&
        "vtbl initializer type mismatch");

    return constVtbl;
}
Пример #23
0
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);
        }
Пример #24
0
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 );
}
Пример #25
0
void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
{
    // save and rewrite scope
    IRScope savedscope = gIR->scope();
    gIR->scope() = IRScope(inBB,savedscope.end);

    // eh_ptr = llvm.eh.exception();
    llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception);
    LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn);

    // build selector arguments
    LLSmallVector<LLValue*, 6> selectorargs;

    // put in classinfos in the right order
    bool hasFinally = false;
    bool hasCatch = false;
    std::deque<IRLandingPadInfo>::iterator it = infos.begin(), end = infos.end();
    for(; it != end; ++it)
    {
        if(it->finallyBody)
            hasFinally = true;
        else
        {
            hasCatch = true;
            assert(it->catchType);
            assert(it->catchType->ir.irStruct);
            selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->getClassInfoSymbol());
        }
    }
    // if there's a finally, the eh table has to have a 0 action
    if(hasFinally)
        selectorargs.push_back(DtoConstUint(0));

    // personality fn
    llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
    LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::getInt8Ty(gIR->context())));
    selectorargs.insert(selectorargs.begin(), personality_fn_arg);

    // eh storage target
    selectorargs.insert(selectorargs.begin(), eh_ptr);

    // if there is a catch and some catch allocated storage, store exception object
    if(hasCatch && catch_var)
    {
        const LLType* objectTy = DtoType(ClassDeclaration::object->type);
        gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
    }

    // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>);
    llvm::Function* eh_selector_fn = GET_INTRINSIC_DECL(eh_selector);
    LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end());

    // emit finallys and 'if' chain to catch the exception
    llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for);
    std::deque<IRLandingPadInfo> infos = this->infos;
    std::stack<size_t> nInfos = this->nInfos;
    std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend();
    for(rit = infos.rbegin(); rit != rend; ++rit)
    {
        // if it's a finally, emit its code
        if(rit->finallyBody)
        {
            size_t n = this->nInfos.top();
            this->infos.resize(n);
            this->nInfos.pop();
            rit->finallyBody->toIR(gIR);
        }
        // otherwise it's a catch and we'll add a if-statement
        else
        {
            llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend());
            LLValue *classInfo = DtoBitCast(rit->catchType->ir.irStruct->getClassInfoSymbol(),
                                            getPtrToType(DtoType(Type::tint8)));
            LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo);
            gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next);
            gIR->scope() = IRScope(next, gIR->scopeend());
        }
    }

    // restore landing pad infos
    this->infos = infos;
    this->nInfos = nInfos;

    // no catch matched and all finallys executed - resume unwind
    llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind");
    gIR->ir->CreateCall(unwind_resume_fn, eh_ptr);
    gIR->ir->CreateUnreachable();

    gIR->scope() = savedscope;
}
Пример #26
0
void DtoResolveStruct(StructDeclaration* sd)
{
    // don't do anything if already been here
    if (sd->ir.resolved) return;
    // make sure above works :P
    sd->ir.resolved = true;

    // log what we're doing
    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 IrStruct
    IrStruct* irstruct = new IrStruct(sd);
    sd->ir.irStruct = irstruct;

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

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

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

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

    if (needs_def)
    {
        // emit typeinfo
        DtoTypeInfoOf(sd->type);
    }
}
Пример #27
0
LLType* DtoType(Type* t)
{
    t = stripModifiers( t );

    if (t->ctype)
    {
        return t->ctype->getLLType();
    }

    IF_LOG Logger::println("Building type: %s", t->toChars());
    LOG_SCOPE;

    assert(t);
    switch (t->ty)
    {
    // basic types
    case Tvoid:
    case Tint8:
    case Tuns8:
    case Tint16:
    case Tuns16:
    case Tint32:
    case Tuns32:
    case Tint64:
    case Tuns64:
    case Tint128:
    case Tuns128:
    case Tfloat32:
    case Tfloat64:
    case Tfloat80:
    case Timaginary32:
    case Timaginary64:
    case Timaginary80:
    case Tcomplex32:
    case Tcomplex64:
    case Tcomplex80:
    //case Tbit:
    case Tbool:
    case Tchar:
    case Twchar:
    case Tdchar:
    {
        return IrTypeBasic::get(t)->getLLType();
    }

    // pointers
    case Tnull:
    case Tpointer:
    {
        return IrTypePointer::get(t)->getLLType();
    }

    // arrays
    case Tarray:
    {
        return IrTypeArray::get(t)->getLLType();
    }

    case Tsarray:
    {
        return IrTypeSArray::get(t)->getLLType();
    }

    // aggregates
    case Tstruct:
    {
        TypeStruct* ts = static_cast<TypeStruct*>(t);
        if (ts->sym->type->ctype)
        {
            // This should not happen, but the frontend seems to be buggy. Not
            // sure if this is the best way to handle the situation, but we
            // certainly don't want to override ts->sym->type->ctype.
            IF_LOG Logger::cout() << "Struct with multiple Types detected: " <<
                ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl;
            return ts->sym->type->ctype->getLLType();
        }
        return IrTypeStruct::get(ts->sym)->getLLType();
    }
    case Tclass:
    {
        TypeClass* tc = static_cast<TypeClass*>(t);
        if (tc->sym->type->ctype)
        {
            // See Tstruct case.
            IF_LOG Logger::cout() << "Class with multiple Types detected: " <<
                tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl;
            return tc->sym->type->ctype->getLLType();
        }
        return IrTypeClass::get(tc->sym)->getLLType();
    }

    // functions
    case Tfunction:
    {
        return IrTypeFunction::get(t)->getLLType();
    }

    // delegates
    case Tdelegate:
    {
        return IrTypeDelegate::get(t)->getLLType();
    }

    // typedefs
    // enum

    // FIXME: maybe just call toBasetype first ?
    case Tenum:
    {
        Type* bt = t->toBasetype();
        assert(bt);
        return DtoType(bt);
    }

    // associative arrays
    case Taarray:
        return getVoidPtrType();

    case Tvector:
    {
        return IrTypeVector::get(t)->getLLType();
    }

/*
    Not needed atm as VarDecls for tuples are rewritten as a string of
    VarDecls for the fields (u -> _u_field_0, ...)

    case Ttuple:
    {
        TypeTuple* ttupl = static_cast<TypeTuple*>(t);
        return DtoStructTypeFromArguments(ttupl->arguments);
    }
*/

    default:
        llvm_unreachable("Unknown class of D Type!");
    }
    return 0;
}
Пример #28
0
static void buildRuntimeModule() {
  Logger::println("building runtime module");
  M = new llvm::Module("ldc internal runtime", gIR->context());

  Type *voidTy = Type::tvoid;
  Type *boolTy = Type::tbool;
  Type *ubyteTy = Type::tuns8;
  Type *intTy = Type::tint32;
  Type *uintTy = Type::tuns32;
  Type *ulongTy = Type::tuns64;
  Type *sizeTy = Type::tsize_t;
  Type *dcharTy = Type::tdchar;

  Type *voidPtrTy = Type::tvoidptr;
  Type *voidArrayTy = Type::tvoid->arrayOf();
  Type *voidArrayPtrTy = voidArrayTy->pointerTo();
  Type *stringTy = Type::tchar->arrayOf();
  Type *wstringTy = Type::twchar->arrayOf();
  Type *dstringTy = Type::tdchar->arrayOf();

  // Ensure that the declarations exist before creating llvm types for them.
  ensureDecl(ClassDeclaration::object, "Object");
  ensureDecl(Type::typeinfoclass, "TypeInfo_Class");
  ensureDecl(Type::dtypeinfo, "DTypeInfo");
  ensureDecl(Type::typeinfoassociativearray, "TypeInfo_AssociativeArray");
  ensureDecl(Module::moduleinfo, "ModuleInfo");

  Type *objectTy = ClassDeclaration::object->type;
  Type *classInfoTy = Type::typeinfoclass->type;
  Type *typeInfoTy = Type::dtypeinfo->type;
  Type *aaTypeInfoTy = Type::typeinfoassociativearray->type;
  Type *moduleInfoPtrTy = Module::moduleinfo->type->pointerTo();
  // The AA type is a struct that only contains a ptr
  Type *aaTy = voidPtrTy;

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // Construct some attribute lists used below (possibly multiple times)
  AttrSet NoAttrs, Attr_NoAlias(NoAttrs, 0, llvm::Attribute::NoAlias),
      Attr_NoUnwind(NoAttrs, ~0U, llvm::Attribute::NoUnwind),
      Attr_ReadOnly(NoAttrs, ~0U, llvm::Attribute::ReadOnly),
      Attr_ReadOnly_NoUnwind(Attr_ReadOnly, ~0U, llvm::Attribute::NoUnwind),
      Attr_ReadOnly_1_NoCapture(Attr_ReadOnly, 1, llvm::Attribute::NoCapture),
      Attr_ReadOnly_1_3_NoCapture(Attr_ReadOnly_1_NoCapture, 3,
                                  llvm::Attribute::NoCapture),
      Attr_ReadOnly_NoUnwind_1_NoCapture(Attr_ReadOnly_1_NoCapture, ~0U,
                                         llvm::Attribute::NoUnwind),
      Attr_ReadNone(NoAttrs, ~0U, llvm::Attribute::ReadNone),
      Attr_1_NoCapture(NoAttrs, 1, llvm::Attribute::NoCapture),
      Attr_NoAlias_1_NoCapture(Attr_1_NoCapture, 0, llvm::Attribute::NoAlias),
      Attr_1_2_NoCapture(Attr_1_NoCapture, 2, llvm::Attribute::NoCapture),
      Attr_1_3_NoCapture(Attr_1_NoCapture, 3, llvm::Attribute::NoCapture),
      Attr_1_4_NoCapture(Attr_1_NoCapture, 4, llvm::Attribute::NoCapture);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // void _d_assert(string file, uint line)
  // void _d_arraybounds(string file, uint line)
  createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"},
                {stringTy, uintTy});

  // void _d_assert_msg(string msg, string file, uint line)
  createFwdDecl(LINKc, voidTy, {"_d_assert_msg"}, {stringTy, stringTy, uintTy});

  // void _d_assertm(immutable(ModuleInfo)* m, uint line)
  // void _d_array_bounds(immutable(ModuleInfo)* m, uint line)
  // void _d_switch_error(immutable(ModuleInfo)* m, uint line)
  createFwdDecl(LINKc, voidTy,
                {"_d_assertm", "_d_array_bounds", "_d_switch_error"},
                {moduleInfoPtrTy, uintTy}, {STCimmutable, 0});

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // void* _d_allocmemory(size_t sz)
  createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemory"}, {sizeTy}, {},
                Attr_NoAlias);

  // void* _d_allocmemoryT(TypeInfo ti)
  createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemoryT"}, {typeInfoTy}, {},
                Attr_NoAlias);

  // void[] _d_newarrayT (const TypeInfo ti, size_t length)
  // void[] _d_newarrayiT(const TypeInfo ti, size_t length)
  // void[] _d_newarrayU (const TypeInfo ti, size_t length)
  createFwdDecl(LINKc, voidArrayTy,
                {"_d_newarrayT", "_d_newarrayiT", "_d_newarrayU"},
                {typeInfoTy, sizeTy}, {STCconst, 0});

  // void[] _d_newarraymTX (const TypeInfo ti, size_t[] dims)
  // void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims)
  createFwdDecl(LINKc, voidArrayTy, {"_d_newarraymTX", "_d_newarraymiTX"},
                {typeInfoTy, sizeTy->arrayOf()}, {STCconst, 0});

  // void[] _d_arraysetlengthT (const TypeInfo ti, size_t newlength, void[]* p)
  // void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p)
  createFwdDecl(LINKc, voidArrayTy,
                {"_d_arraysetlengthT", "_d_arraysetlengthiT"},
                {typeInfoTy, sizeTy, voidArrayPtrTy}, {STCconst, 0, 0});

  // byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcTX"},
                {typeInfoTy, voidArrayTy, sizeTy}, {STCconst, STCref, 0});

  // void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendT"},
                {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, STCref, 0});

  // void[] _d_arrayappendcd(ref byte[] x, dchar c)
  // void[] _d_arrayappendwd(ref byte[] x, dchar c)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcd", "_d_arrayappendwd"},
                {voidArrayTy, dcharTy}, {STCref, 0});

  // byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatT"},
                {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0});

  // void[] _d_arraycatnTX(const TypeInfo ti, byte[][] arrs)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatnTX"},
                {typeInfoTy, voidArrayTy->arrayOf()}, {STCconst, 0});

  // Object _d_newclass(const ClassInfo ci)
  createFwdDecl(LINKc, objectTy, {"_d_newclass"}, {classInfoTy}, {STCconst},
                Attr_NoAlias);

  // void* _d_newitemT (TypeInfo ti)
  // void* _d_newitemiT(TypeInfo ti)
  createFwdDecl(LINKc, voidPtrTy, {"_d_newitemT", "_d_newitemiT"}, {typeInfoTy},
                {0}, Attr_NoAlias);

  // void _d_delarray_t(void[]* p, const TypeInfo_Struct ti)
  createFwdDecl(LINKc, voidTy, {"_d_delarray_t"},
                {voidArrayPtrTy, Type::typeinfostruct->type}, {0, STCconst});

  // void _d_delmemory(void** p)
  // void _d_delinterface(void** p)
  createFwdDecl(LINKc, voidTy, {"_d_delmemory", "_d_delinterface"},
                {voidPtrTy->pointerTo()});

  // void _d_callfinalizer(void* p)
  createFwdDecl(LINKc, voidTy, {"_d_callfinalizer"}, {voidPtrTy});

  // D2: void _d_delclass(Object* p)
  createFwdDecl(LINKc, voidTy, {"_d_delclass"}, {objectTy->pointerTo()});

  // void _d_delstruct(void** p, TypeInfo_Struct inf)
  createFwdDecl(LINKc, voidTy, {"_d_delstruct"},
                {voidPtrTy->pointerTo(), Type::typeinfostruct->type});

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // array slice copy when assertions are on!
  // void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t
  // srclen)
  createFwdDecl(LINKc, voidTy, {"_d_array_slice_copy"},
                {voidPtrTy, sizeTy, voidPtrTy, sizeTy}, {}, Attr_1_3_NoCapture);

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// int _aApplycd1(in char[] aa, dg_t dg)
// int _aApplyRcd1(in char[] aa, dg_t dg)
#define STR_APPLY1(TY, a, b)                                                   \
  {                                                                            \
    const std::string prefix = "_aApply";                                      \
    std::string fname1 = prefix + (a) + '1', fname2 = prefix + (b) + '1',      \
                fname3 = prefix + 'R' + (a) + '1',                             \
                fname4 = prefix + 'R' + (b) + '1';                             \
    createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4},             \
                  {TY, rt_dg1()});                                             \
  }
  STR_APPLY1(stringTy, "cw", "cd")
  STR_APPLY1(wstringTy, "wc", "wd")
  STR_APPLY1(dstringTy, "dc", "dw")
#undef STR_APPLY1

// int _aApplycd2(in char[] aa, dg2_t dg)
// int _aApplyRcd2(in char[] aa, dg2_t dg)
#define STR_APPLY2(TY, a, b)                                                   \
  {                                                                            \
    const std::string prefix = "_aApply";                                      \
    std::string fname1 = prefix + (a) + '2', fname2 = prefix + (b) + '2',      \
                fname3 = prefix + 'R' + (a) + '2',                             \
                fname4 = prefix + 'R' + (b) + '2';                             \
    createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4},             \
                  {TY, rt_dg2()});                                             \
  }
  STR_APPLY2(stringTy, "cw", "cd")
  STR_APPLY2(wstringTy, "wc", "wd")
  STR_APPLY2(dstringTy, "dc", "dw")
#undef STR_APPLY2

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // fixes the length for dynamic array casts
  // size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
  createFwdDecl(LINKc, sizeTy, {"_d_array_cast_len"}, {sizeTy, sizeTy, sizeTy},
                {}, Attr_ReadNone);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp)
  // void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arrayassign_l", "_d_arrayassign_r"},
                {typeInfoTy, voidArrayTy, voidArrayTy, voidPtrTy});

  // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
  createFwdDecl(LINKc, voidArrayTy, {"_d_arrayctor"},
                {typeInfoTy, voidArrayTy, voidArrayTy});

  // void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
  // void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
  createFwdDecl(LINKc, voidPtrTy, {"_d_arraysetassign", "_d_arraysetctor"},
                {voidPtrTy, voidPtrTy, intTy, typeInfoTy}, {}, Attr_NoAlias);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // cast interface
  // void* _d_interface_cast(void* p, ClassInfo c)
  createFwdDecl(LINKc, voidPtrTy, {"_d_interface_cast"},
                {voidPtrTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind);

  // dynamic cast
  // void* _d_dynamic_cast(Object o, ClassInfo c)
  createFwdDecl(LINKc, voidPtrTy, {"_d_dynamic_cast"}, {objectTy, classInfoTy},
                {}, Attr_ReadOnly_NoUnwind);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // char[] _adReverseChar(char[] a)
  // char[] _adSortChar(char[] a)
  createFwdDecl(LINKc, stringTy, {"_adReverseChar", "_adSortChar"}, {stringTy});

  // wchar[] _adReverseWchar(wchar[] a)
  // wchar[] _adSortWchar(wchar[] a)
  createFwdDecl(LINKc, wstringTy, {"_adReverseWchar", "_adSortWchar"},
                {wstringTy});

  // void[] _adReverse(void[] a, size_t szelem)
  createFwdDecl(LINKc, wstringTy, {"_adReverse"}, {voidArrayTy, sizeTy}, {},
                Attr_NoUnwind);

  // int _adEq2(void[] a1, void[] a2, TypeInfo ti)
  // int _adCmp2(void[] a1, void[] a2, TypeInfo ti)
  createFwdDecl(LINKc, intTy, {"_adEq2", "_adCmp2"},
                {voidArrayTy, voidArrayTy, typeInfoTy}, {}, Attr_ReadOnly);

  // int _adCmpChar(void[] a1, void[] a2)
  createFwdDecl(LINKc, intTy, {"_adCmpChar"}, {voidArrayTy, voidArrayTy}, {},
                Attr_ReadOnly_NoUnwind);

  // void[] _adSort(void[] a, TypeInfo ti)
  createFwdDecl(LINKc, voidArrayTy, {"_adSort"}, {voidArrayTy, typeInfoTy});

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // size_t _aaLen(in AA aa)
  createFwdDecl(LINKc, sizeTy, {"_aaLen"}, {aaTy}, {STCin},
                Attr_ReadOnly_NoUnwind_1_NoCapture);

  // void* _aaGetY(AA* aa, const TypeInfo aati, in size_t valuesize,
  //               in void* pkey)
  createFwdDecl(LINKc, voidPtrTy, {"_aaGetY"},
                {aaTy->pointerTo(), aaTypeInfoTy, sizeTy, voidPtrTy},
                {0, STCconst, STCin, STCin}, Attr_1_4_NoCapture);

  // inout(void)* _aaInX(inout AA aa, in TypeInfo keyti, in void* pkey)
  // FIXME: "inout" storageclass is not applied to return type
  createFwdDecl(LINKc, voidPtrTy, {"_aaInX"}, {aaTy, typeInfoTy, voidPtrTy},
                {STCin | STCout, STCin, STCin}, Attr_ReadOnly_1_3_NoCapture);

  // bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey)
  createFwdDecl(LINKc, boolTy, {"_aaDelX"}, {aaTy, typeInfoTy, voidPtrTy},
                {0, STCin, STCin}, Attr_1_3_NoCapture);

  // inout(void[]) _aaValues(inout AA aa, in size_t keysize,
  //                         in size_t valuesize, const TypeInfo tiValueArray)
  createFwdDecl(
      LINKc, voidArrayTy, {"_aaValues"}, {aaTy, sizeTy, sizeTy, typeInfoTy},
      {STCin | STCout, STCin, STCin, STCconst}, Attr_ReadOnly_1_3_NoCapture);

  // void* _aaRehash(AA* paa, in TypeInfo keyti)
  createFwdDecl(LINKc, voidPtrTy, {"_aaRehash"},
                {aaTy->pointerTo(), typeInfoTy}, {0, STCin});

  // inout(void[]) _aaKeys(inout AA aa, in size_t keysize,
  //                       const TypeInfo tiKeyArray)
  createFwdDecl(LINKc, voidArrayTy, {"_aaKeys"}, {aaTy, sizeTy, typeInfoTy},
                {STCin | STCout, STCin, STCconst}, Attr_NoAlias_1_NoCapture);

  // int _aaApply(AA aa, in size_t keysize, dg_t dg)
  createFwdDecl(LINKc, intTy, {"_aaApply"}, {aaTy, sizeTy, rt_dg1()},
                {0, STCin, 0}, Attr_1_NoCapture);

  // int _aaApply2(AA aa, in size_t keysize, dg2_t dg)
  createFwdDecl(LINKc, intTy, {"_aaApply2"}, {aaTy, sizeTy, rt_dg2()},
                {0, STCin, 0}, Attr_1_NoCapture);

  // int _aaEqual(in TypeInfo tiRaw, in AA e1, in AA e2)
  createFwdDecl(LINKc, intTy, {"_aaEqual"}, {typeInfoTy, aaTy, aaTy},
                {STCin, STCin, STCin}, Attr_1_2_NoCapture);

  // AA _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti,
  //                           void[] keys, void[] values)
  createFwdDecl(LINKc, aaTy, {"_d_assocarrayliteralTX"},
                {aaTypeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0});

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // void _moduleCtor()
  // void _moduleDtor()
  createFwdDecl(LINKc, voidTy, {"_moduleCtor", "_moduleDtor"}, {});

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // void _d_throw_exception(Object e)
  createFwdDecl(LINKc, voidTy, {"_d_throw_exception"}, {objectTy});

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // int _d_switch_string(char[][] table, char[] ca)
  createFwdDecl(LINKc, intTy, {"_d_switch_string"},
                {stringTy->arrayOf(), stringTy}, {}, Attr_ReadOnly);

  // int _d_switch_ustring(wchar[][] table, wchar[] ca)
  createFwdDecl(LINKc, intTy, {"_d_switch_ustring"},
                {wstringTy->arrayOf(), wstringTy}, {}, Attr_ReadOnly);

  // int _d_switch_dstring(dchar[][] table, dchar[] ca)
  createFwdDecl(LINKc, intTy, {"_d_switch_dstring"},
                {dstringTy->arrayOf(), dstringTy}, {}, Attr_ReadOnly);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // int _d_eh_personality(...)
  {
    if (global.params.targetTriple.isWindowsMSVCEnvironment()) {
      // (ptr ExceptionRecord, ptr EstablisherFrame, ptr ContextRecord,
      //  ptr DispatcherContext)
      createFwdDecl(LINKc, intTy, {"_d_eh_personality"},
                    {voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy});
    } else if (global.params.targetTriple.getArch() == llvm::Triple::arm) {
      // (int state, ptr ucb, ptr context)
      createFwdDecl(LINKc, intTy, {"_d_eh_personality"},
                    {intTy, voidPtrTy, voidPtrTy});
    } else {
      // (int ver, int actions, ulong eh_class, ptr eh_info, ptr context)
      createFwdDecl(LINKc, intTy, {"_d_eh_personality"},
                    {intTy, intTy, ulongTy, voidPtrTy, voidPtrTy});
    }
  }

  // void _d_eh_resume_unwind(ptr)
  createFwdDecl(LINKc, voidTy, {"_d_eh_resume_unwind"}, {voidPtrTy});

  // Object _d_eh_enter_catch(ptr)
  createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy}, {},
                Attr_NoUnwind);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // void invariant._d_invariant(Object o)
  createFwdDecl(
      LINKd, voidTy,
      {gABI->mangleForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)},
      {objectTy});

  // void _d_dso_registry(CompilerDSOData* data)
  llvm::StringRef fname("_d_dso_registry");

  LLType *LLvoidTy = LLType::getVoidTy(gIR->context());
  LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy));
  LLType *moduleInfoPtrPtrTy =
      getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type)));

  llvm::StructType *dsoDataTy =
      llvm::StructType::get(DtoSize_t(),        // version
                            LLvoidPtrPtrTy,     // slot
                            moduleInfoPtrPtrTy, // _minfo_beg
                            moduleInfoPtrPtrTy, // _minfo_end
                            NULL);

  llvm::Type *types[] = {getPtrToType(dsoDataTy)};
  llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false);
  llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);

  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////

  // extern (C) void _d_cover_register2(string filename, size_t[] valid,
  //                                    uint[] data, ubyte minPercent)
  if (global.params.cov) {
    createFwdDecl(LINKc, voidTy, {"_d_cover_register2"},
                  {stringTy, sizeTy->arrayOf(), uintTy->arrayOf(), ubyteTy});
  }
}
Пример #29
0
DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
{
    // D1:
    // call:
    // extern(C) void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey)
    // or
    // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey)

    // D2:
    // call:
    // extern(C) void* _aaGetX(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey)
    // or
    // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)

    // first get the runtime function
    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGetX":"_aaInX");
    LLFunctionType* funcTy = func->getFunctionType();

    // aa param
    LLValue* aaval = lvalue ? aa->getLVal() : aa->getRVal();
    aaval = DtoBitCast(aaval, funcTy->getParamType(0));

    // keyti param
    LLValue* keyti = to_keyti(aa);
    keyti = DtoBitCast(keyti, funcTy->getParamType(1));

    // pkey param
    LLValue* pkey = makeLValue(loc, key);
    pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2));

    // call runtime
    LLValue* ret;
    if (lvalue) {
        // valuesize param
        LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));

        ret = gIR->CreateCallOrInvoke4(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction();
    } else {
        ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.index").getInstruction();
    }

    // cast return value
    LLType* targettype = getPtrToType(DtoType(type));
    if (ret->getType() != targettype)
        ret = DtoBitCast(ret, targettype);

    // Only check bounds for rvalues ('aa[key]').
    // Lvalue use ('aa[key] = value') auto-adds an element.
    if (!lvalue && global.params.useArrayBounds) {
        llvm::BasicBlock* oldend = gIR->scopeend();
        llvm::BasicBlock* failbb = llvm::BasicBlock::Create(gIR->context(), "aaboundscheckfail", gIR->topfunc(), oldend);
        llvm::BasicBlock* okbb = llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc(), oldend);

        LLValue* nullaa = LLConstant::getNullValue(ret->getType());
        LLValue* cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck");
        gIR->ir->CreateCondBr(cond, okbb, failbb);

        // set up failbb to call the array bounds error runtime function

        gIR->scope() = IRScope(failbb, okbb);

        std::vector<LLValue*> args;

        // module param
        LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol();
        LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
        args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType)));

        // line param
        LLConstant* c = DtoConstUint(loc.linnum);
        args.push_back(c);

        // call
        llvm::Function* errorfn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_array_bounds");
        gIR->CreateCallOrInvoke(errorfn, args);

        // the function does not return
        gIR->ir->CreateUnreachable();

        // if ok, proceed in okbb
        gIR->scope() = IRScope(okbb, oldend);
    }
    return new DVarValue(type, ret);
}
Пример #30
0
bool X86_64TargetABI::passByVal(Type* t) {
    t = t->toBasetype();
    if (linkage() == LINKd) {
        return t->toBasetype()->ty == Tstruct;
    } else {
        // This implements the C calling convention for x86-64.
        // It might not be correct for other calling conventions.
        Classification cl = classify(t);
        if (cl.isMemory)
            return true;
        
        // Figure out how many registers we want for this arg:
        RegCount wanted = { 0, 0 };
        for (int i = 0 ; i < 2; i++) {
            if (cl.classes[i] == Integer)
                wanted.int_regs++;
            else if (cl.classes[i] == Sse)
                wanted.sse_regs++;
        }
        
        // See if they're available:
        RegCount& state = this->state();
        if (wanted.int_regs <= state.int_regs && wanted.sse_regs <= state.sse_regs) {
            state.int_regs -= wanted.int_regs;
            state.sse_regs -= wanted.sse_regs;
        } else {
            if (keepUnchanged(t)) {
                // Not enough registers available, but this is passed as if it's
                // multiple arguments. Just use the registers there are,
                // automatically spilling the rest to memory.
                if (wanted.int_regs > state.int_regs)
                    state.int_regs = 0;
                else
                    state.int_regs -= wanted.int_regs;
                
                if (wanted.sse_regs > state.sse_regs)
                    state.sse_regs = 0;
                else
                    state.sse_regs -= wanted.sse_regs;
            } else if (t->iscomplex() || t->ty == Tstruct) {
                // Spill entirely to memory, even if some of the registers are
                // available.
                
                // FIXME: Don't do this if *none* of the wanted registers are available,
                //        (i.e. only when absolutely necessary for abi-compliance)
                //        so it gets alloca'd by the callee and -scalarrepl can
                //        more easily break it up?
                // Note: this won't be necessary if the following LLVM bug gets fixed:
                //       http://llvm.org/bugs/show_bug.cgi?id=3741
                return true;
            } else {
                assert(t == Type::tfloat80 || t == Type::timaginary80 || t->ty == Tsarray || t->size() <= 8
                    && "What other big types are there?");
                // In any case, they shouldn't be represented as structs in LLVM:
                assert(!isaStruct(DtoType(t)));
            }
        }
        // Everything else that's passed in memory is handled by LLVM.
        return false;
    }
}