Example #1
0
DValue* DtoArgument(Parameter* fnarg, Expression* argexp)
{
    IF_LOG Logger::println("DtoArgument");
    LOG_SCOPE;

    DValue* arg = toElem(argexp);

    // ref/out arg
    if (fnarg && (fnarg->storageClass & (STCref | STCout)))
    {
        Loc loc;
        arg = new DImValue(argexp->type, makeLValue(loc, arg));
    }
    // lazy arg
    else if (fnarg && (fnarg->storageClass & STClazy))
    {
        assert(argexp->type->toBasetype()->ty == Tdelegate);
        assert(!arg->isLVal());
        return arg;
    }
    // byval arg, but expr has no storage yet
    else if (DtoIsPassedByRef(argexp->type) && (arg->isSlice() || arg->isNull()))
    {
        LLValue* alloc = DtoAlloca(argexp->type, ".tmp_arg");
        DVarValue* vv = new DVarValue(argexp->type, alloc);
        DtoAssign(argexp->loc, vv, arg);
        arg = vv;
    }

    return arg;
}
Example #2
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);
}
Example #3
0
void AsmStatement_toIR(AsmStatement *stmt, IRState * irs)
{
    IF_LOG Logger::println("AsmStatement::toIR(): %s", stmt->loc.toChars());
    LOG_SCOPE;

    // sanity check
    assert(irs->func()->decl->hasReturnExp & 8);

    // get asm block
    IRAsmBlock* asmblock = irs->asmBlock;
    assert(asmblock);

    // debug info
    gIR->DBuilder.EmitStopPoint(stmt->loc.linnum);

    if (!stmt->asmcode)
        return;

    static std::string i_cns = "i";
    static std::string p_cns = "i";
    static std::string m_cns = "*m";
    static std::string mw_cns = "=*m";
    static std::string mrw_cns = "+*m";
    static std::string memory_name = "memory";

    AsmCode *code = static_cast<AsmCode *>(stmt->asmcode);
    std::vector<LLValue*> input_values;
    std::vector<std::string> input_constraints;
    std::vector<LLValue*> output_values;
    std::vector<std::string> output_constraints;
    std::vector<std::string> clobbers;

// FIXME
    //#define HOST_WIDE_INT long
    //HOST_WIDE_INT var_frame_offset; // "frame_offset" is a macro
    bool clobbers_mem = code->clobbersMemory;
    int input_idx = 0;
    int n_outputs = 0;
    int arg_map[10];

    assert(code->args.size() <= 10);

    std::vector<AsmArg>::iterator arg = code->args.begin();
    for (unsigned i = 0; i < code->args.size(); i++, ++arg) {
        bool is_input = true;
        LLValue* arg_val = 0;
        std::string cns;

        switch (arg->type) {
        case Arg_Integer:
            arg_val = toElem(arg->expr)->getRVal();
        do_integer:
            cns = i_cns;
            break;
        case Arg_Pointer:
            assert(arg->expr->op == TOKvar);
            arg_val = toElem(arg->expr)->getRVal();
            cns = p_cns;

            break;
        case Arg_Memory:
            arg_val = toElem(arg->expr)->getRVal();

            switch (arg->mode) {
            case Mode_Input:  cns = m_cns; break;
            case Mode_Output: cns = mw_cns;  is_input = false; break;
            case Mode_Update: cns = mrw_cns; is_input = false; break;
            default: llvm_unreachable("Unknown inline asm reference mode."); break;
            }
            break;
        case Arg_FrameRelative:
            // FIXME
            llvm_unreachable("Arg_FrameRelative not supported.");
/*          if (arg->expr->op == TOKvar)
                arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
            else
                assert(0);
            if ( getFrameRelativeValue(arg_val, & var_frame_offset) ) {
//              arg_val = irs->integerConstant(var_frame_offset);
                cns = i_cns;
            } else {
                this->error("%s", "argument not frame relative");
                return;
            }
            if (arg->mode != Mode_Input)
                clobbers_mem = true;
            break;*/
        case Arg_LocalSize:
            // FIXME
            llvm_unreachable("Arg_LocalSize not supported.");
/*          var_frame_offset = cfun->x_frame_offset;
            if (var_frame_offset < 0)
                var_frame_offset = - var_frame_offset;
            arg_val = irs->integerConstant( var_frame_offset );*/
            goto do_integer;
        default:
            llvm_unreachable("Unknown inline asm reference type.");
        }

        if (is_input) {
            arg_map[i] = --input_idx;
            input_values.push_back(arg_val);
            input_constraints.push_back(cns);
        } else {
            arg_map[i] = n_outputs++;
            output_values.push_back(arg_val);
            output_constraints.push_back(cns);
        }
    }

    // Telling GCC that callee-saved registers are clobbered makes it preserve
    // those registers.   This changes the stack from what a naked function
    // expects.

// FIXME
//    if (! irs->func->naked) {
        assert(asmparser);
        for (size_t i = 0; i < code->regs.size(); i++) {
            if (code->regs[i]) {
                clobbers.push_back(asmparser->getRegName(i));
            }
        }
        if (clobbers_mem)
            clobbers.push_back(memory_name);
//    }

    // Remap argument numbers
    for (unsigned i = 0; i < code->args.size(); i++) {
        if (arg_map[i] < 0)
            arg_map[i] = -arg_map[i] - 1 + n_outputs;
    }

    bool pct = false;
    std::string::iterator
        p = code->insnTemplate.begin(),
        q = code->insnTemplate.end();
    //printf("start: %.*s\n", code->insnTemplateLen, code->insnTemplate);
    while (p < q) {
        if (pct) {
            if (*p >= '0' && *p <= '9') {
                // %% doesn't check against nargs
                *p = '0' + arg_map[*p - '0'];
                pct = false;
            } else if (*p == '$') {
                pct = false;
            }
            //assert(*p == '%');// could be 'a', etc. so forget it..
        } else if (*p == '$')
            pct = true;
        ++p;
    }

    typedef std::vector<std::string>::iterator It;
    IF_LOG {
        Logger::cout() << "final asm: " << code->insnTemplate << '\n';
        std::ostringstream ss;

        ss << "GCC-style output constraints: {";
        for (It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i) {
            ss << " " << *i;
        }
        ss << " }";
        Logger::println("%s", ss.str().c_str());

        ss.str("");
        ss << "GCC-style input constraints: {";
        for (It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
            ss << " " << *i;
        }
        ss << " }";
        Logger::println("%s", ss.str().c_str());

        ss.str("");
        ss << "GCC-style clobbers: {";
        for (It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
            ss << " " << *i;
        }
        ss << " }";
        Logger::println("%s", ss.str().c_str());
    }

    // rewrite GCC-style constraints to LLVM-style constraints
    std::string llvmOutConstraints;
    std::string llvmInConstraints;
    int n = 0;
    for(It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) {
        // rewrite update constraint to in and out constraints
        if((*i)[0] == '+') {
            assert(*i == mrw_cns && "What else are we updating except memory?");
            /* LLVM doesn't support updating operands, so split into an input
             * and an output operand.
             */

            // Change update operand to pure output operand.
            *i = mw_cns;

            // Add input operand with same value, with original as "matching output".
            std::ostringstream ss;
            ss << '*' << (n + asmblock->outputcount);
            // Must be at the back; unused operands before used ones screw up numbering.
            input_constraints.push_back(ss.str());
            input_values.push_back(output_values[n]);
        }
        llvmOutConstraints += *i;
        llvmOutConstraints += ",";
    }
    asmblock->outputcount += n;

    for(It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
        llvmInConstraints += *i;
        llvmInConstraints += ",";
    }

    std::string clobstr;
    for(It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
        clobstr = "~{" + *i + "},";
        asmblock->clobs.insert(clobstr);
    }

    IF_LOG {
        typedef std::vector<LLValue*>::iterator It;
        {
            Logger::println("Output values:");
            LOG_SCOPE
            size_t i = 0;
            for (It I = output_values.begin(), E = output_values.end(); I != E; ++I) {
                Logger::cout() << "Out " << i++ << " = " << **I << '\n';
            }
        }
        {
            Logger::println("Input values:");
            LOG_SCOPE
            size_t i = 0;
            for (It I = input_values.begin(), E = input_values.end(); I != E; ++I) {
                Logger::cout() << "In  " << i++ << " = " << **I << '\n';
            }
        }
    }

    // excessive commas are removed later...

    replace_func_name(irs, code->insnTemplate);

    // push asm statement
    IRAsmStmt* asmStmt = new IRAsmStmt;
    asmStmt->code = code->insnTemplate;
    asmStmt->out_c = llvmOutConstraints;
    asmStmt->in_c = llvmInConstraints;
    asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(), output_values.end());
    asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(), input_values.end());
    asmStmt->isBranchToLabel = stmt->isBranchToLabel;
    asmblock->s.push_back(asmStmt);
}