Beispiel #1
0
    void visit(ForStatement *s)
    {
        //printf("visit(ForStatement)) %u..%u\n", s->loc.linnum, s->endloc.linnum);
        Blockx *blx = irs->blx;

        IRState mystate(irs,s);
        mystate.breakBlock = block_calloc(blx);
        mystate.contBlock = block_calloc(blx);

        if (s->_init)
            Statement_toIR(s->_init, &mystate);
        block *bpre = blx->curblock;
        block_next(blx,BCgoto,NULL);
        block *bcond = blx->curblock;
        bpre->appendSucc(bcond);
        mystate.contBlock->appendSucc(bcond);
        if (s->condition)
        {
            incUsage(irs, s->condition->loc);
            block_appendexp(bcond, toElemDtor(s->condition, &mystate));
            block_next(blx,BCiftrue,NULL);
            bcond->appendSucc(blx->curblock);
            bcond->appendSucc(mystate.breakBlock);
        }
        else
        {   /* No conditional, it's a straight goto
             */
            block_next(blx,BCgoto,NULL);
            bcond->appendSucc(blx->curblock);
        }

        if (s->_body)
            Statement_toIR(s->_body, &mystate);
        /* End of the body goes to the continue block
         */
        blx->curblock->appendSucc(mystate.contBlock);
        block_setLoc(blx->curblock, s->endloc);
        block_next(blx, BCgoto, mystate.contBlock);

        if (s->increment)
        {
            incUsage(irs, s->increment->loc);
            block_appendexp(mystate.contBlock, toElemDtor(s->increment, &mystate));
        }

        /* The 'break' block follows the for statement.
         */
        block_next(blx,BCgoto, mystate.breakBlock);
    }
Beispiel #2
0
    void visit(WithStatement *s)
    {
        Symbol *sp;
        elem *e;
        elem *ei;
        ExpInitializer *ie;
        Blockx *blx = irs->blx;

        //printf("WithStatement::toIR()\n");
        if (s->exp->op == TOKimport || s->exp->op == TOKtype)
        {
        }
        else
        {
            // Declare with handle
            sp = toSymbol(s->wthis);
            symbol_add(sp);

            // Perform initialization of with handle
            ie = s->wthis->_init->isExpInitializer();
            assert(ie);
            ei = toElemDtor(ie->exp, irs);
            e = el_var(sp);
            e = el_bin(OPeq,e->Ety, e, ei);
            elem_setLoc(e, s->loc);
            incUsage(irs, s->loc);
            block_appendexp(blx->curblock,e);
        }
        // Execute with block
        if (s->_body)
            Statement_toIR(s->_body, irs);
    }
Beispiel #3
0
    void visit(DoStatement *s)
    {
        Blockx *blx = irs->blx;

        IRState mystate(irs,s);
        mystate.breakBlock = block_calloc(blx);
        mystate.contBlock = block_calloc(blx);

        block *bpre = blx->curblock;
        block_next(blx, BCgoto, NULL);
        bpre->appendSucc(blx->curblock);

        mystate.contBlock->appendSucc(blx->curblock);
        mystate.contBlock->appendSucc(mystate.breakBlock);

        if (s->_body)
            Statement_toIR(s->_body, &mystate);
        blx->curblock->appendSucc(mystate.contBlock);

        block_next(blx, BCgoto, mystate.contBlock);
        incUsage(irs, s->condition->loc);
        block_appendexp(mystate.contBlock, toElemDtor(s->condition, &mystate));
        block_next(blx, BCiftrue, mystate.breakBlock);

    }
Beispiel #4
0
    void visit(ExpStatement *s)
    {
        Blockx *blx = irs->blx;

        //printf("ExpStatement::toIR(), exp = %s\n", exp ? exp->toChars() : "");
        incUsage(irs, s->loc);
        if (s->exp)
            block_appendexp(blx->curblock,toElemDtor(s->exp, irs));
    }
Beispiel #5
0
    void visit(ThrowStatement *s)
    {
        // throw(exp)

        Blockx *blx = irs->blx;

        incUsage(irs, s->loc);
        elem *e = toElemDtor(s->exp, irs);
        e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_THROWC)),e);
        block_appendexp(blx->curblock, e);
    }
Beispiel #6
0
    void visit(IfStatement *s)
    {
        elem *e;
        Blockx *blx = irs->blx;

        //printf("IfStatement::toIR('%s')\n", s->condition->toChars());

        IRState mystate(irs, s);

        // bexit is the block that gets control after this IfStatement is done
        block *bexit = mystate.breakBlock ? mystate.breakBlock : block_calloc();

        incUsage(irs, s->loc);
        e = toElemDtor(s->condition, &mystate);
        block_appendexp(blx->curblock, e);
        block *bcond = blx->curblock;
        block_next(blx, BCiftrue, NULL);

        bcond->appendSucc(blx->curblock);
        if (s->ifbody)
            Statement_toIR(s->ifbody, &mystate);
        blx->curblock->appendSucc(bexit);

        if (s->elsebody)
        {
            block_next(blx, BCgoto, NULL);
            bcond->appendSucc(blx->curblock);
            Statement_toIR(s->elsebody, &mystate);
            blx->curblock->appendSucc(bexit);
        }
        else
            bcond->appendSucc(bexit);

        block_next(blx, BCgoto, bexit);

    }
Beispiel #7
0
    void visit(ReturnStatement *s)
    {
        Blockx *blx = irs->blx;
        enum BC bc;

        incUsage(irs, s->loc);
        if (s->exp)
        {
            elem *e;

            FuncDeclaration *func = irs->getFunc();
            assert(func);
            assert(func->type->ty == Tfunction);
            TypeFunction *tf = (TypeFunction *)(func->type);

            RET retmethod = retStyle(tf);
            if (retmethod == RETstack)
            {
                elem *es;

                /* If returning struct literal, write result
                 * directly into return value
                 */
                if (s->exp->op == TOKstructliteral)
                {
                    StructLiteralExp *se = (StructLiteralExp *)s->exp;
                    char save[sizeof(StructLiteralExp)];
                    memcpy(save, (void*)se, sizeof(StructLiteralExp));
                    se->sym = irs->shidden;
                    se->soffset = 0;
                    se->fillHoles = 1;
                    e = toElemDtor(s->exp, irs);
                    memcpy((void*)se, save, sizeof(StructLiteralExp));
                }
                else
                    e = toElemDtor(s->exp, irs);
                assert(e);

                if (s->exp->op == TOKstructliteral ||
                    (func->nrvo_can && func->nrvo_var))
                {
                    // Return value via hidden pointer passed as parameter
                    // Write exp; return shidden;
                    es = e;
                }
                else
                {
                    // Return value via hidden pointer passed as parameter
                    // Write *shidden=exp; return shidden;
                    int op;
                    tym_t ety;

                    ety = e->Ety;
                    es = el_una(OPind,ety,el_var(irs->shidden));
                    op = (tybasic(ety) == TYstruct) ? OPstreq : OPeq;
                    es = el_bin(op, ety, es, e);
                    if (op == OPstreq)
                        es->ET = Type_toCtype(s->exp->type);
                }
                e = el_var(irs->shidden);
                e = el_bin(OPcomma, e->Ety, es, e);
            }
            else if (tf->isref)
            {
                // Reference return, so convert to a pointer
                e = toElemDtor(s->exp, irs);
                e = addressElem(e, s->exp->type->pointerTo());
            }
            else
            {
                e = toElemDtor(s->exp, irs);
                assert(e);
            }
            elem_setLoc(e, s->loc);
            block_appendexp(blx->curblock, e);
            bc = BCretexp;
        }
        else
            bc = BCret;

        if (block *finallyBlock = irs->getFinallyBlock())
        {
            assert(finallyBlock->BC == BC_finally);
            blx->curblock->appendSucc(finallyBlock);
        }

        block_next(blx, bc, NULL);
    }
Beispiel #8
0
    void visit(SwitchStatement *s)
    {
        int string;
        Blockx *blx = irs->blx;

        //printf("SwitchStatement::toIR()\n");
        IRState mystate(irs,s);

        mystate.switchBlock = blx->curblock;

        /* Block for where "break" goes to
         */
        mystate.breakBlock = block_calloc(blx);

        /* Block for where "default" goes to.
         * If there is a default statement, then that is where default goes.
         * If not, then do:
         *   default: break;
         * by making the default block the same as the break block.
         */
        mystate.defaultBlock = s->sdefault ? block_calloc(blx) : mystate.breakBlock;

        size_t numcases = 0;
        if (s->cases)
            numcases = s->cases->dim;

        incUsage(irs, s->loc);
        elem *econd = toElemDtor(s->condition, &mystate);
        if (s->hasVars)
        {   /* Generate a sequence of if-then-else blocks for the cases.
             */
            if (econd->Eoper != OPvar)
            {
                elem *e = exp2_copytotemp(econd);
                block_appendexp(mystate.switchBlock, e);
                econd = e->E2;
            }

            for (size_t i = 0; i < numcases; i++)
            {   CaseStatement *cs = (*s->cases)[i];

                elem *ecase = toElemDtor(cs->exp, &mystate);
                elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase);
                block *b = blx->curblock;
                block_appendexp(b, e);
                Label *clabel = getLabel(irs, blx, cs);
                block_next(blx, BCiftrue, NULL);
                b->appendSucc(clabel->lblock);
                b->appendSucc(blx->curblock);
            }

            /* The final 'else' clause goes to the default
             */
            block *b = blx->curblock;
            block_next(blx, BCgoto, NULL);
            b->appendSucc(mystate.defaultBlock);

            Statement_toIR(s->_body, &mystate);

            /* Have the end of the switch body fall through to the block
             * following the switch statement.
             */
            block_goto(blx, BCgoto, mystate.breakBlock);
            return;
        }

        if (s->condition->type->isString())
        {
            // Number the cases so we can unscramble things after the sort()
            for (size_t i = 0; i < numcases; i++)
            {   CaseStatement *cs = (*s->cases)[i];
                cs->index = i;
            }

            s->cases->sort();

            /* Create a sorted array of the case strings, and si
             * will be the symbol for it.
             */
            dt_t *dt = NULL;
            Symbol *si = symbol_generate(SCstatic,type_fake(TYdarray));
            dtsize_t(&dt, numcases);
            dtxoff(&dt, si, Target::ptrsize * 2, TYnptr);

            for (size_t i = 0; i < numcases; i++)
            {   CaseStatement *cs = (*s->cases)[i];

                if (cs->exp->op != TOKstring)
                {   s->error("case '%s' is not a string", cs->exp->toChars()); // BUG: this should be an assert
                }
                else
                {
                    StringExp *se = (StringExp *)(cs->exp);
                    Symbol *si = toStringSymbol((char *)se->string, se->len, se->sz);
                    dtsize_t(&dt, se->len);
                    dtxoff(&dt, si, 0);
                }
            }

            si->Sdt = dt;
            si->Sfl = FLdata;
            outdata(si);

            /* Call:
             *      _d_switch_string(string[] si, string econd)
             */
            if (config.exe == EX_WIN64)
                econd = addressElem(econd, s->condition->type, true);
            elem *eparam = el_param(econd, (config.exe == EX_WIN64) ? el_ptr(si) : el_var(si));
            switch (s->condition->type->nextOf()->ty)
            {
                case Tchar:
                    econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_STRING)), eparam);
                    break;
                case Twchar:
                    econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_USTRING)), eparam);
                    break;
                case Tdchar:        // BUG: implement
                    econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_DSTRING)), eparam);
                    break;
                default:
                    assert(0);
            }
            elem_setLoc(econd, s->loc);
            string = 1;
        }
        else
            string = 0;
        block_appendexp(mystate.switchBlock, econd);
        block_next(blx,BCswitch,NULL);

        // Corresponding free is in block_free
        targ_llong *pu = (targ_llong *) ::malloc(sizeof(*pu) * (numcases + 1));
        mystate.switchBlock->BS.Bswitch = pu;
        /* First pair is the number of cases, and the default block
         */
        *pu++ = numcases;
        mystate.switchBlock->appendSucc(mystate.defaultBlock);

        /* Fill in the first entry in each pair, which is the case value.
         * CaseStatement::toIR() will fill in
         * the second entry for each pair with the block.
         */
        for (size_t i = 0; i < numcases; i++)
        {
            CaseStatement *cs = (*s->cases)[i];
            if (string)
            {
                pu[cs->index] = i;
            }
            else
            {
                pu[i] = cs->exp->toInteger();
            }
        }

        Statement_toIR(s->_body, &mystate);

        /* Have the end of the switch body fall through to the block
         * following the switch statement.
         */
        block_goto(blx, BCgoto, mystate.breakBlock);
    }
Beispiel #9
0
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
  // resolve type
  DtoResolveClass(tc->sym);

  // allocate
  LLValue *mem;
  bool doInit = true;
  if (newexp->onstack) {
    unsigned alignment = tc->sym->alignsize;
    if (alignment == STRUCTALIGN_DEFAULT)
      alignment = 0;
    mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), alignment,
                       ".newclass_alloca");
  }
  // custom allocator
  else if (newexp->allocator) {
    DtoResolveFunction(newexp->allocator);
    DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator));
    DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs);
    mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom");
  }
  // default allocator
  else {
    const bool useEHAlloc = global.params.ehnogc && newexp->thrownew;
    llvm::Function *fn = getRuntimeFunction(
        loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass");
    LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
                                DtoType(getClassInfoType()));
    mem = gIR->CreateCallOrInvoke(fn, ci,
                                  useEHAlloc ? ".newthrowable_alloc"
                                             : ".newclass_gc_alloc")
              .getInstruction();
    mem = DtoBitCast(mem, DtoType(tc),
                     useEHAlloc ? ".newthrowable" : ".newclass_gc");
    doInit = !useEHAlloc;
  }

  // init
  if (doInit)
    DtoInitClass(tc, mem);

  // init inner-class outer reference
  if (newexp->thisexp) {
    Logger::println("Resolving outer class");
    LOG_SCOPE;
    unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
    LLValue *src = DtoRVal(newexp->thisexp);
    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) {
    // evaluate argprefix
    if (newexp->argprefix) {
      toElemDtor(newexp->argprefix);
    }

    Logger::println("Calling constructor");
    assert(newexp->arguments != NULL);
    DtoResolveFunction(newexp->member);
    DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem);
    // ignore ctor return value (C++ ctors on Posix may not return `this`)
    DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments);
    return new DImValue(tc, mem);
  }

  assert(newexp->argprefix == NULL);

  // return default constructed class
  return new DImValue(tc, mem);
}
Beispiel #10
0
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
  // resolve type
  DtoResolveClass(tc->sym);

  // allocate
  LLValue *mem;
  if (newexp->onstack) {
    mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), DtoAlignment(tc),
                       ".newclass_alloca");
  }
  // custom allocator
  else if (newexp->allocator) {
    DtoResolveFunction(newexp->allocator);
    DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator));
    DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs);
    mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom");
  }
  // default allocator
  else {
    llvm::Function *fn =
        getRuntimeFunction(loc, gIR->module, "_d_allocclass");
    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;
    unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
    LLValue *src = DtoRVal(newexp->thisexp);
    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) {
    // evaluate argprefix
    if (newexp->argprefix) {
      toElemDtor(newexp->argprefix);
    }

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

  assert(newexp->argprefix == NULL);

  // return default constructed class
  return new DImValue(tc, mem);
}