示例#1
0
文件: glue.c 项目: Rayerd/dmd
void FuncDeclaration::toObjFile(int multiobj)
{
    FuncDeclaration *func = this;
    ClassDeclaration *cd = func->parent->isClassDeclaration();
    int reverse;
    int has_arguments;

    //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars());
    //if (type) printf("type = %s\n", func->type->toChars());
#if 0
    //printf("line = %d\n",func->getWhere() / LINEINC);
    EEcontext *ee = env->getEEcontext();
    if (ee->EEcompile == 2)
    {
        if (ee->EElinnum < (func->getWhere() / LINEINC) ||
            ee->EElinnum > (func->endwhere / LINEINC)
           )
            return;             // don't compile this function
        ee->EEfunc = func->toSymbol();
    }
#endif

    if (semanticRun >= PASSobj) // if toObjFile() already run
        return;

    // If errors occurred compiling it, such as bugzilla 6118
    if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror)
        return;

    if (!func->fbody)
    {
        return;
    }
    if (func->isUnitTestDeclaration() && !global.params.useUnitTests)
        return;

    if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration())
    {   obj_append(this);
        return;
    }

    assert(semanticRun == PASSsemantic3done);
    semanticRun = PASSobj;

    if (global.params.verbose)
        printf("function  %s\n",func->toChars());

    Symbol *s = func->toSymbol();
    func_t *f = s->Sfunc;

#if TARGET_WINDOS
    /* This is done so that the 'this' pointer on the stack is the same
     * distance away from the function parameters, so that an overriding
     * function can call the nested fdensure or fdrequire of its overridden function
     * and the stack offsets are the same.
     */
    if (isVirtual() && (fensure || frequire))
        f->Fflags3 |= Ffakeeh;
#endif

#if TARGET_OSX
    s->Sclass = SCcomdat;
#else
    s->Sclass = SCglobal;
#endif
    for (Dsymbol *p = parent; p; p = p->parent)
    {
        if (p->isTemplateInstance())
        {
            s->Sclass = SCcomdat;
            break;
        }
    }

    /* Vector operations should be comdat's
     */
    if (isArrayOp)
        s->Sclass = SCcomdat;

    if (isNested())
    {
//      if (!(config.flags3 & CFG3pic))
//          s->Sclass = SCstatic;
        f->Fflags3 |= Fnested;
    }
    else
    {
        const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;

        // Pull in RTL startup code
        if (func->isMain())
        {   objextdef("_main");
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
            obj_ehsections();   // initialize exception handling sections
#endif
#if TARGET_WINDOS
            objextdef("__acrtused_con");
#endif
            obj_includelib(libname);
            s->Sclass = SCglobal;
        }
        else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc)
        {
#if TARGET_WINDOS
            objextdef("__acrtused_con");        // bring in C startup code
            obj_includelib("snn.lib");          // bring in C runtime library
#endif
            s->Sclass = SCglobal;
        }
        else if (func->isWinMain())
        {
            objextdef("__acrtused");
            obj_includelib(libname);
            s->Sclass = SCglobal;
        }

        // Pull in RTL startup code
        else if (func->isDllMain())
        {
            objextdef("__acrtused_dll");
            obj_includelib(libname);
            s->Sclass = SCglobal;
        }
    }

    cstate.CSpsymtab = &f->Flocsym;

    // Find module m for this function
    Module *m = NULL;
    for (Dsymbol *p = parent; p; p = p->parent)
    {
        m = p->isModule();
        if (m)
            break;
    }

    IRState irs(m, func);
    Dsymbols deferToObj;                   // write these to OBJ file later
    irs.deferToObj = &deferToObj;

    TypeFunction *tf;
    enum RET retmethod;
    symbol *shidden = NULL;
    Symbol *sthis = NULL;
    tym_t tyf;

    tyf = tybasic(s->Stype->Tty);
    //printf("linkage = %d, tyf = x%x\n", linkage, tyf);
    reverse = tyrevfunc(s->Stype->Tty);

    assert(func->type->ty == Tfunction);
    tf = (TypeFunction *)(func->type);
    has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1);
    retmethod = tf->retStyle();
    if (retmethod == RETstack)
    {
        // If function returns a struct, put a pointer to that
        // as the first argument
        ::type *thidden = tf->next->pointerTo()->toCtype();
        char hiddenparam[5+4+1];
        static int hiddenparami;    // how many we've generated so far

        sprintf(hiddenparam,"__HID%d",++hiddenparami);
        shidden = symbol_name(hiddenparam,SCparameter,thidden);
        shidden->Sflags |= SFLtrue | SFLfree;
#if DMDV1
        if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref)
#else
        if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim)
#endif
            type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile);
        irs.shidden = shidden;
        this->shidden = shidden;
    }

    if (vthis)
    {
        assert(!vthis->csym);
        sthis = vthis->toSymbol();
        irs.sthis = sthis;
        if (!(f->Fflags3 & Fnested))
            f->Fflags3 |= Fmember;
    }

    Symbol **params;
    unsigned pi;

    // Estimate number of parameters, pi
    pi = (v_arguments != NULL);
    if (parameters)
        pi += parameters->dim;
    // Allow extra 2 for sthis and shidden
    params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *));

    // Get the actual number of parameters, pi, and fill in the params[]
    pi = 0;
    if (v_arguments)
    {
        params[pi] = v_arguments->toSymbol();
        pi += 1;
    }
    if (parameters)
    {
        for (size_t i = 0; i < parameters->dim; i++)
        {   VarDeclaration *v = parameters->tdata()[i];
            if (v->csym)
            {
                error("compiler error, parameter '%s', bugzilla 2962?", v->toChars());
                assert(0);
            }
            params[pi + i] = v->toSymbol();
        }
        pi += parameters->dim;
    }

    if (reverse)
    {   // Reverse params[] entries
        for (size_t i = 0; i < pi/2; i++)
        {
            Symbol *sptmp = params[i];
            params[i] = params[pi - 1 - i];
            params[pi - 1 - i] = sptmp;
        }
    }

    if (shidden)
    {
#if 0
        // shidden becomes last parameter
        params[pi] = shidden;
#else
        // shidden becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = shidden;
#endif
        pi++;
    }


    if (sthis)
    {
#if 0
        // sthis becomes last parameter
        params[pi] = sthis;
#else
        // sthis becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = sthis;
#endif
        pi++;
    }

    if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
         linkage != LINKd && shidden && sthis)
    {
        /* swap shidden and sthis
         */
        Symbol *sp = params[0];
        params[0] = params[1];
        params[1] = sp;
    }

    for (size_t i = 0; i < pi; i++)
    {   Symbol *sp = params[i];
        sp->Sclass = SCparameter;
        sp->Sflags &= ~SFLspill;
        sp->Sfl = FLpara;
        symbol_add(sp);
    }

    // Determine register assignments
    if (pi)
    {
        if (global.params.is64bit)
        {
            // Order of assignment of pointer or integer parameters
            static const unsigned char argregs[6] = { DI,SI,DX,CX,R8,R9 };
            int r = 0;
            int xmmcnt = XMM0;

            for (size_t i = 0; i < pi; i++)
            {   Symbol *sp = params[i];
                tym_t ty = tybasic(sp->Stype->Tty);
                // BUG: doesn't work for structs
                if (r < sizeof(argregs)/sizeof(argregs[0]))
                {
                    if (type_jparam(sp->Stype))
                    {
                        sp->Sclass = SCfastpar;
                        sp->Spreg = argregs[r];
                        sp->Sfl = FLauto;
                        ++r;
                    }
                }
                if (xmmcnt <= XMM7)
                {
                    if (tyfloating(ty) && tysize(ty) <= 8)
                    {
                        sp->Sclass = SCfastpar;
                        sp->Spreg = xmmcnt;
                        sp->Sfl = FLauto;
                        ++xmmcnt;
                    }
                }
            }
        }
        else
        {
            // First parameter goes in register
            Symbol *sp = params[0];
            if ((tyf == TYjfunc || tyf == TYmfunc) &&
                type_jparam(sp->Stype))
            {   sp->Sclass = SCfastpar;
                sp->Spreg = (tyf == TYjfunc) ? AX : CX;
                sp->Sfl = FLauto;
                //printf("'%s' is SCfastpar\n",sp->Sident);
            }
        }
    }

    if (func->fbody)
    {   block *b;
        Blockx bx;
        Statement *sbody;

        localgot = NULL;

        sbody = func->fbody;
        memset(&bx,0,sizeof(bx));
        bx.startblock = block_calloc();
        bx.curblock = bx.startblock;
        bx.funcsym = s;
        bx.scope_index = -1;
        bx.classdec = cd;
        bx.member = func;
        bx.module = getModule();
        irs.blx = &bx;
#if DMDV2
        buildClosure(&irs);
#endif

#if 0
        if (func->isSynchronized())
        {
            if (cd)
            {   elem *esync;
                if (func->isStatic())
                {   // monitor is in ClassInfo
                    esync = el_ptr(cd->toSymbol());
                }
                else
                {   // 'this' is the monitor
                    esync = el_var(sthis);
                }

                if (func->isStatic() || sbody->usesEH() ||
                    !(config.flags2 & CFG2seh))
                {   // BUG: what if frequire or fensure uses EH?

                    sbody = new SynchronizedStatement(func->loc, esync, sbody);
                }
                else
                {
#if TARGET_WINDOS
                    if (config.flags2 & CFG2seh)
                    {
                        /* The "jmonitor" uses an optimized exception handling frame
                         * which is a little shorter than the more general EH frame.
                         * It isn't strictly necessary.
                         */
                        s->Sfunc->Fflags3 |= Fjmonitor;
                    }
#endif
                    el_free(esync);
                }
            }
            else
            {
                error("synchronized function %s must be a member of a class", func->toChars());
            }
        }
#elif TARGET_WINDOS
        if (func->isSynchronized() && cd && config.flags2 & CFG2seh &&
            !func->isStatic() && !sbody->usesEH())
        {
            /* The "jmonitor" hack uses an optimized exception handling frame
             * which is a little shorter than the more general EH frame.
             */
            s->Sfunc->Fflags3 |= Fjmonitor;
        }
#endif

        sbody->toIR(&irs);
        bx.curblock->BC = BCret;

        f->Fstartblock = bx.startblock;
//      einit = el_combine(einit,bx.init);

        if (isCtorDeclaration())
        {
            assert(sthis);
            for (b = f->Fstartblock; b; b = b->Bnext)
            {
                if (b->BC == BCret)
                {
                    b->BC = BCretexp;
                    b->Belem = el_combine(b->Belem, el_var(sthis));
                }
            }
        }
    }

    // If static constructor
#if DMDV2
    if (isSharedStaticCtorDeclaration())        // must come first because it derives from StaticCtorDeclaration
    {
        elem *e = el_una(OPucall, TYvoid, el_var(s));
        esharedctor = el_combine(esharedctor, e);
    }
    else
#endif
    if (isStaticCtorDeclaration())
    {
        elem *e = el_una(OPucall, TYvoid, el_var(s));
        ector = el_combine(ector, e);
    }

    // If static destructor
#if DMDV2
    if (isSharedStaticDtorDeclaration())        // must come first because it derives from StaticDtorDeclaration
    {
        elem *e;

#if STATICCTOR
        e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_FATEXIT]), el_ptr(s));
        esharedctor = el_combine(esharedctor, e);
        shareddtorcount++;
#else
        SharedStaticDtorDeclaration *f = isSharedStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {   /* Increment destructor's vgate at construction time
             */
            esharedctorgates.push(f);
        }

        e = el_una(OPucall, TYvoid, el_var(s));
        eshareddtor = el_combine(e, eshareddtor);
#endif
    }
    else
#endif
    if (isStaticDtorDeclaration())
    {
        elem *e;

#if STATICCTOR
        e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_FATEXIT]), el_ptr(s));
        ector = el_combine(ector, e);
        dtorcount++;
#else
        StaticDtorDeclaration *f = isStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {   /* Increment destructor's vgate at construction time
             */
            ectorgates.push(f);
        }

        e = el_una(OPucall, TYvoid, el_var(s));
        edtor = el_combine(e, edtor);
#endif
    }

    // If unit test
    if (isUnitTestDeclaration())
    {
        elem *e = el_una(OPucall, TYvoid, el_var(s));
        etest = el_combine(etest, e);
    }

    if (global.errors)
        return;

    writefunc(s);
    if (isExport())
        obj_export(s, Poffset);

    for (size_t i = 0; i < irs.deferToObj->dim; i++)
    {
        Dsymbol *s = irs.deferToObj->tdata()[i];
        s->toObjFile(0);
    }

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
    // A hack to get a pointer to this function put in the .dtors segment
    if (ident && memcmp(ident->toChars(), "_STD", 4) == 0)
        obj_staticdtor(s);
#endif
#if DMDV2
    if (irs.startaddress)
    {
        printf("Setting start address\n");
        obj_startaddress(irs.startaddress);
    }
#endif
}
示例#2
0
文件: cgcs.c 项目: Abscissa/dmd
STATIC void ecom(elem **pe)
{ int i,op,hcstopsave;
  unsigned hash;
  elem *e,*ehash;
  tym_t tym;

  e = *pe;
  assert(e);
  elem_debug(e);
#ifdef DEBUG
  assert(e->Ecount == 0);
  //assert(e->Ecomsub == 0);
#endif
  tym = tybasic(e->Ety);
  op = e->Eoper;
  switch (op)
  {
    case OPconst:
    case OPvar:
    case OPrelconst:
        break;
    case OPstreq:
    case OPpostinc:
    case OPpostdec:
    case OPeq:
    case OPaddass:
    case OPminass:
    case OPmulass:
    case OPdivass:
    case OPmodass:
    case OPshrass:
    case OPashrass:
    case OPshlass:
    case OPandass:
    case OPxorass:
    case OPorass:
#if TX86
        /* Reverse order of evaluation for double op=. This is so that  */
        /* the pushing of the address of the second operand is easier.  */
        /* However, with the 8087 we don't need the kludge.             */
        if (op != OPeq && tym == TYdouble && !config.inline8087)
        {       if (EOP(e->E1))
                        ecom(&e->E1->E1);
                ecom(&e->E2);
        }
        else
#endif
        {
            /* Don't mark the increment of an i++ or i-- as a CSE, if it */
            /* can be done with an INC or DEC instruction.               */
            if (!(OTpost(op) && elemisone(e->E2)))
                ecom(&e->E2);           /* evaluate 2nd operand first   */
    case OPnegass:
            if (EOP(e->E1))             /* if lvalue is an operator     */
            {
#ifdef DEBUG
                if (e->E1->Eoper != OPind)
                    elem_print(e);
#endif
                assert(e->E1->Eoper == OPind);
                ecom(&(e->E1->E1));
            }
        }
        touchlvalue(e->E1);
        if (!OTpost(op))                /* lvalue of i++ or i-- is not a cse*/
        {
            hash = cs_comphash(e->E1);
            vec_setbit(hash % CSVECDIM,csvec);
            addhcstab(e->E1,hash);              // add lvalue to hcstab[]
        }
        return;

    case OPbtc:
    case OPbts:
    case OPbtr:
        ecom(&e->E1);
        ecom(&e->E2);
        touchfunc(0);                   // indirect assignment
        return;

    case OPandand:
    case OPoror:
        ecom(&e->E1);
        hcstopsave = hcstop;
        ecom(&e->E2);
        hcstop = hcstopsave;            /* no common subs by E2         */
        return;                         /* if comsub then logexp() will */
                                        /* break                        */
    case OPcond:
        ecom(&e->E1);
        hcstopsave = hcstop;
        ecom(&e->E2->E1);               /* left condition               */
        hcstop = hcstopsave;            /* no common subs by E2         */
        ecom(&e->E2->E2);               /* right condition              */
        hcstop = hcstopsave;            /* no common subs by E2         */
        return;                         /* can't be a common sub        */
    case OPcall:
    case OPcallns:
        ecom(&e->E2);                   /* eval right first             */
        /* FALL-THROUGH */
    case OPucall:
    case OPucallns:
        ecom(&e->E1);
        touchfunc(1);
        return;
    case OPstrpar:                      /* so we don't break logexp()   */
#if TX86
    case OPinp:                 /* never CSE the I/O instruction itself */
#endif
    case OPdctor:
        ecom(&e->E1);
        /* FALL-THROUGH */
    case OPasm:
    case OPstrthis:             // don't CSE these
    case OPframeptr:
    case OPgot:
    case OPctor:
    case OPdtor:
    case OPmark:
        return;

    case OPddtor:
        return;

    case OPparam:
#if TX86
    case OPoutp:
#endif
        ecom(&e->E1);
    case OPinfo:
        ecom(&e->E2);
        return;
    case OPcomma:
    case OPremquo:
        ecom(&e->E1);
        ecom(&e->E2);
        break;
#if TARGET_SEGMENTED
    case OPvp_fp:
    case OPcvp_fp:
        ecom(&e->E1);
        touchaccess(e);
        break;
#endif
    case OPind:
        ecom(&e->E1);
        /* Generally, CSEing a *(double *) results in worse code        */
        if (tyfloating(tym))
            return;
        break;
#if TX86
    case OPstrcpy:
    case OPstrcat:
    case OPmemcpy:
    case OPmemset:
        ecom(&e->E2);
    case OPsetjmp:
        ecom(&e->E1);
        touchfunc(0);
        return;
#endif
    default:                            /* other operators */
#if TX86
#ifdef DEBUG
        if (!EBIN(e)) WROP(e->Eoper);
#endif
        assert(EBIN(e));
    case OPadd:
    case OPmin:
    case OPmul:
    case OPdiv:
    case OPor:
    case OPxor:
    case OPand:
    case OPeqeq:
    case OPne:
    case OPscale:
    case OPyl2x:
    case OPyl2xp1:
        ecom(&e->E1);
        ecom(&e->E2);
        break;
#else
#ifdef DEBUG
        if (!EOP(e)) WROP(e->Eoper);
#endif
        assert(EOP(e));
        ecom(&e->E1);
        if (EBIN(e))
                ecom(&e->E2);           /* eval left first              */
        break;
#endif
    case OPstring:
    case OPaddr:
    case OPbit:
#ifdef DEBUG
        WROP(e->Eoper);
        elem_print(e);
#endif
        assert(0);              /* optelem() should have removed these  */
        /* NOTREACHED */

    // Explicitly list all the unary ops for speed
    case OPnot: case OPcom: case OPneg: case OPuadd:
    case OPabs: case OPsqrt: case OPrndtol: case OPsin: case OPcos: case OPrint:
    case OPpreinc: case OPpredec:
    case OPbool: case OPstrlen: case OPs16_32: case OPu16_32:
    case OPd_s32: case OPd_u32:
    case OPs32_d: case OPu32_d: case OPd_s16: case OPs16_d: case OP32_16:
    case OPd_f: case OPf_d:
    case OPd_ld: case OPld_d:
    case OPc_r: case OPc_i:
    case OPu8_16: case OPs8_16: case OP16_8:
    case OPu32_64: case OPs32_64: case OP64_32: case OPmsw:
    case OPu64_128: case OPs64_128: case OP128_64:
    case OPd_s64: case OPs64_d: case OPd_u64: case OPu64_d:
    case OPstrctor: case OPu16_d: case OPd_u16:
    case OParrow:
    case OPvoid: case OPnullcheck:
    case OPbsf: case OPbsr: case OPbswap:
    case OPld_u64:
#if TARGET_SEGMENTED
    case OPoffset: case OPnp_fp: case OPnp_f16p: case OPf16p_np:
#endif
        ecom(&e->E1);
        break;
    case OPhalt:
        return;
  }

  /* don't CSE structures or unions or volatile stuff   */
  if (tym == TYstruct ||
      tym == TYvoid ||
      e->Ety & mTYvolatile
#if TX86
    // don't CSE doubles if inline 8087 code (code generator can't handle it)
      || (tyfloating(tym) && config.inline8087)
#endif
     )
        return;

  hash = cs_comphash(e);                /* must be AFTER leaves are done */

  /* Search for a match in hcstab[].
   * Search backwards, as most likely matches will be towards the end
   * of the list.
   */

#ifdef DEBUG
  if (debugx) dbg_printf("elem: %p hash: %6d\n",e,hash);
#endif
  int csveci = hash % CSVECDIM;
  if (vec_testbit(csveci,csvec))
  {
    for (i = hcstop; i--;)
    {
#ifdef DEBUG
        if (debugx)
            dbg_printf("i: %2d Hhash: %6d Helem: %p\n",
                i,hcstab[i].Hhash,hcstab[i].Helem);
#endif
        if (hash == hcstab[i].Hhash && (ehash = hcstab[i].Helem) != NULL)
        {
            /* if elems are the same and we still have room for more    */
            if (el_match(e,ehash) && ehash->Ecount < 0xFF)
            {
                /* Make sure leaves are also common subexpressions
                 * to avoid false matches.
                 */
                if (!OTleaf(op))
                {
                    if (!e->E1->Ecount)
                        continue;
                    if (OTbinary(op) && !e->E2->Ecount)
                        continue;
                }
                ehash->Ecount++;
                *pe = ehash;
#ifdef DEBUG
                if (debugx)
                        dbg_printf("**MATCH** %p with %p\n",e,*pe);
#endif
                el_free(e);
                return;
            }
        }
    }
  }
  else
    vec_setbit(csveci,csvec);
  addhcstab(e,hash);                    // add this elem to hcstab[]
}
示例#3
0
static void sliceStructs_Gather(SymInfo *sia, elem *e)
{
    while (1)
    {
        switch (e->Eoper)
        {
            case OPvar:
            {
                SYMIDX si = e->EV.sp.Vsym->Ssymnum;
                if (si >= 0 && sia[si].canSlice)
                {
                    assert(si < globsym.top);
                    unsigned sz = tysize(e->Ety);
                    if (sz == 2 * REGSIZE)
                    {
                        // Rewrite as OPpair later
                        sia[si].usePair = true;

                        /* OPpair cannot handle XMM registers, cdpair() and fixresult()
                         */
                        if (tyfloating(sia[si].ty0) || tyfloating(sia[si].ty1))
                            sia[si].canSlice = false;
                    }
                    else if (sz == REGSIZE &&
                        (e->Eoffset == 0 || e->Eoffset == REGSIZE))
                    {
                        if (!sia[si].accessSlice)
                        {
                            sia[si].ty0 = TYnptr;
                            sia[si].ty1 = TYnptr;
                        }
                        sia[si].accessSlice = true;
                        if (e->Eoffset == 0)
                            sia[si].ty0 = tybasic(e->Ety);
                        else
                            sia[si].ty1 = tybasic(e->Ety);
                        // Cannot slice float fields if the symbol is also accessed using OPpair (see above)
                        if (sia[si].usePair && (tyfloating(sia[si].ty0) || tyfloating(sia[si].ty1)))
                            sia[si].canSlice = false;
                    }
                    else
                    {
                        sia[si].canSlice = false;
                    }
                }
                return;
            }

            default:
                if (OTassign(e->Eoper))
                {
                    if (OTbinary(e->Eoper))
                        sliceStructs_Gather(sia, e->E2);

                    // Assignment to a whole var will disallow SROA
                    if (e->E1->Eoper == OPvar)
                    {
                        elem *e1 = e->E1;
                        SYMIDX si = e1->EV.sp.Vsym->Ssymnum;
                        if (si >= 0 && sia[si].canSlice)
                        {
                            assert(si < globsym.top);
                            if (tysize(e1->Ety) != REGSIZE ||
                                (e1->Eoffset != 0 && e1->Eoffset != REGSIZE))
                            {
                                sia[si].canSlice = false;
                            }
                        }
                        return;
                    }
                    e = e->E1;
                    break;
                }
                if (OTunary(e->Eoper))
                {
                    e = e->E1;
                    break;
                }
                if (OTbinary(e->Eoper))
                {
                    sliceStructs_Gather(sia, e->E2);
                    e = e->E1;
                    break;
                }
                return;
        }
    }
}