Alien-TinyCCx

 view release on metacpan or  search on metacpan

src/tccgen.c  view on Meta::CPAN

#endif
    s->c = c;
    s->next = NULL;
    /* add in stack */
    s->prev = *ps;
    *ps = s;
    return s;
}

/* find a symbol and return its associated structure. 's' is the top
   of the symbol stack */
ST_FUNC Sym *sym_find2(Sym *s, int v)
{
/* #ifdef CONFIG_TCC_EXSYMTAB */
    v &= ~SYM_EXTENDED;
/* #endif */
    while (s) {
/* #ifdef CONFIG_TCC_EXSYMTAB */
        if ((s->v & ~SYM_EXTENDED) == v)
/* #else
        if (s->v == v)
#endif */
            return s;
        else if (s->v == -1)
            return NULL;
        s = s->prev;
    }
    return NULL;
}

/* structure lookup */
ST_INLN Sym *struct_find(int v)
{
/* #ifdef CONFIG_TCC_EXSYMTAB */
    v &= ~SYM_EXTENDED;
/* #endif */
    v -= TOK_IDENT;
    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
        return NULL;
    return table_ident[v]->sym_struct;
}

/* find an identifier */
ST_INLN Sym *sym_find(int v)
{
/* #ifdef CONFIG_TCC_EXSYMTAB */
    int is_extended = v & SYM_EXTENDED;
    v &= ~SYM_EXTENDED;
/* #endif */
    v -= TOK_IDENT;

    /* Does not exist in our table! The best we can do is return null. XXX Maybe
     * should warn if this happens with an extended symbol, since that would be
     * a sign of an inconsistent internal state. */
    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
        return NULL;

/* #ifdef CONFIG_TCC_EXSYMTAB */
    /* If this is an extended symbol table reference, then we need to make sure
     * that the extended symbol reference callback gets fired, but only once.
     * We'll modify the TokenSym's tok field and remove the flag if the callback
     * has been fired, so check if the TokenSym's tok field has the flag.
     */
    if (is_extended && (table_ident[v]->tok & SYM_EXTENDED)) {
        TokenSym *ts = table_ident[v];

        /* Clear the extended symbol flag in the TokenSym. */
        ts->tok &= ~SYM_EXTENDED;

        /* XXX If we don't have the callback function... throw error? */
        if ((ts->sym_identifier != NULL)
            && (ts->sym_identifier->type.t & VT_EXTERN) 
            && (tcc_state->symtab_sym_used_callback != NULL))
        {
            /* Call the function, passing the symbol name. */
            tcc_state->symtab_sym_used_callback(ts->str, ts->len,
                tcc_state->symtab_callback_data);
        }
    }
/* #endif */

    return table_ident[v]->sym_identifier;
}

/* push a given symbol on the symbol stack */
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
{
    Sym *s, **ps;
    TokenSym *ts;

    if (local_stack)
        ps = &local_stack;
    else {
/* #ifdef CONFIG_TCC_EXSYMTAB */
        /* Global symbol stack. This is OK for the local symbol stack, but don't allow
         * this for symbols that are in the extended symbol stack. There seem to be
         * some issues associated with copying *all* TokenSyms, so this needs to be
         * ironed out. For now, I'm removing the check. */
         //
         // if (v & SYM_EXTENDED) {
         //     tcc_error("Cannot use name '%s' as a global variable, it is already in the "
         //               "extended symbol table.", get_tok_str(v, 0));
         // }
/* #endif */
        ps = &global_stack;
    }
/* #ifdef CONFIG_TCC_EXSYMTAB */
    v &= ~SYM_EXTENDED;
/* #endif */
    s = sym_push2(ps, v, type->t, c);
    s->type.ref = type->ref;
    s->r = r;
    /* don't record fields or anonymous symbols */
    /* XXX: simplify */
    if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
        /* record symbol in token array */
        ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
        if (v & SYM_STRUCT)
            ps = &ts->sym_struct;
        else
            ps = &ts->sym_identifier;
        s->prev_tok = *ps;
        *ps = s;
        s->scope = local_scope;
        if (s->prev_tok && s->prev_tok->scope == s->scope)
            tcc_error("redeclaration of '%s'",
                get_tok_str(v & ~SYM_STRUCT, NULL));

src/tccgen.c  view on Meta::CPAN

                ps = &ts->sym_identifier;
            *ps = s->prev_tok;
        }
        sym_free(s);
        s = ss;
    }
    *ptop = b;
}

static void weaken_symbol(Sym *sym)
{
    sym->type.t |= VT_WEAK;
    if (sym->c > 0) {
        int esym_type;
        ElfW(Sym) *esym;
        
        esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
        esym_type = ELFW(ST_TYPE)(esym->st_info);
        esym->st_info = ELFW(ST_INFO)(STB_WEAK, esym_type);
    }
}

static void apply_visibility(Sym *sym, CType *type)
{
    int vis = sym->type.t & VT_VIS_MASK;
    int vis2 = type->t & VT_VIS_MASK;
    if (vis == (STV_DEFAULT << VT_VIS_SHIFT))
        vis = vis2;
    else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT))
        ;
    else
        vis = (vis < vis2) ? vis : vis2;
    sym->type.t &= ~VT_VIS_MASK;
    sym->type.t |= vis;

    if (sym->c > 0) {
        ElfW(Sym) *esym;
        
        esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
	vis >>= VT_VIS_SHIFT;
        esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis;
    }
}

/* ------------------------------------------------------------------------- */

ST_FUNC void swap(int *p, int *q)
{
    int t;
    t = *p;
    *p = *q;
    *q = t;
}

static void vsetc(CType *type, int r, CValue *vc)
{
    int v;

    if (vtop >= vstack + (VSTACK_SIZE - 1))
        tcc_error("memory full (vstack)");
    /* cannot let cpu flags if other instruction are generated. Also
       avoid leaving VT_JMP anywhere except on the top of the stack
       because it would complicate the code generator. */
    if (vtop >= vstack) {
        v = vtop->r & VT_VALMASK;
        if (v == VT_CMP || (v & ~1) == VT_JMP)
            gv(RC_INT);
    }
    vtop++;
    vtop->type = *type;
    vtop->r = r;
    vtop->r2 = VT_CONST;
    vtop->c = *vc;
}

/* push constant of type "type" with useless value */
ST_FUNC void vpush(CType *type)
{
    CValue cval;
    vsetc(type, VT_CONST, &cval);
}

/* push integer constant */
ST_FUNC void vpushi(int v)
{
    CValue cval;
    cval.i = v;
    vsetc(&int_type, VT_CONST, &cval);
}

/* push a pointer sized constant */
static void vpushs(addr_t v)
{
  CValue cval;
  cval.i = v;
  vsetc(&size_type, VT_CONST, &cval);
}

/* push arbitrary 64bit constant */
ST_FUNC void vpush64(int ty, unsigned long long v)
{
    CValue cval;
    CType ctype;
    ctype.t = ty;
    ctype.ref = NULL;
    cval.i = v;
    vsetc(&ctype, VT_CONST, &cval);
}

/* push long long constant */
static inline void vpushll(long long v)
{
    vpush64(VT_LLONG, v);
}

/* push a symbol value of TYPE */
static inline void vpushsym(CType *type, Sym *sym)
{
    CValue cval;
    cval.i = 0;
    vsetc(type, VT_CONST | VT_SYM, &cval);

src/tccgen.c  view on Meta::CPAN

        s = global_identifier_push(v, type->t | VT_EXTERN, 0);
        s->type.ref = type->ref;
        s->r = r | VT_CONST | VT_SYM;
    }
    return s;
}

/* define a new external reference to a symbol 'v' */
static Sym *external_sym(int v, CType *type, int r)
{
    Sym *s;

    s = sym_find(v);
    if (!s) {
        /* push forward reference */
        s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
        s->type.t |= VT_EXTERN;
    } else if (s->type.ref == func_old_type.ref) {
        s->type.ref = type->ref;
        s->r = r | VT_CONST | VT_SYM;
        s->type.t |= VT_EXTERN;
    } else if (!is_compatible_types(&s->type, type)) {
        tcc_error("incompatible types for redefinition of '%s'", 
              get_tok_str(v, NULL));
    }
    /* Merge some storage attributes.  */
    if (type->t & VT_WEAK)
        weaken_symbol(s);

    if (type->t & VT_VIS_MASK)
        apply_visibility(s, type);

    return s;
}

/* push a reference to global symbol v */
ST_FUNC void vpush_global_sym(CType *type, int v)
{
    vpushsym(type, external_global_sym(v, type, 0));
}

ST_FUNC void vset(CType *type, int r, int v)
{
    CValue cval;

    cval.i = v;
    vsetc(type, r, &cval);
}

static void vseti(int r, int v)
{
    CType type;
    type.t = VT_INT;
    type.ref = 0;
    vset(&type, r, v);
}

ST_FUNC void vswap(void)
{
    SValue tmp;
    /* cannot let cpu flags if other instruction are generated. Also
       avoid leaving VT_JMP anywhere except on the top of the stack
       because it would complicate the code generator. */
    if (vtop >= vstack) {
        int v = vtop->r & VT_VALMASK;
        if (v == VT_CMP || (v & ~1) == VT_JMP)
            gv(RC_INT);
    }
    tmp = vtop[0];
    vtop[0] = vtop[-1];
    vtop[-1] = tmp;

/* XXX: +2% overall speed possible with optimized memswap
 *
 *  memswap(&vtop[0], &vtop[1], sizeof *vtop);
 */
}

ST_FUNC void vpushv(SValue *v)
{
    if (vtop >= vstack + (VSTACK_SIZE - 1))
        tcc_error("memory full (vstack)");
    vtop++;
    *vtop = *v;
}

static void vdup(void)
{
    vpushv(vtop);
}

/* save registers up to (vtop - n) stack entry */
ST_FUNC void save_regs(int n)
{
    SValue *p, *p1;
    for(p = vstack, p1 = vtop - n; p <= p1; p++)
        save_reg(p->r);
}

/* save r to the memory stack, and mark it as being free */
ST_FUNC void save_reg(int r)
{
    save_reg_upstack(r, 0);
}

/* save r to the memory stack, and mark it as being free,
   if seen up to (vtop - n) stack entry */
ST_FUNC void save_reg_upstack(int r, int n)
{
    int l, saved, size, align;
    SValue *p, *p1, sv;
    CType *type;

    if ((r &= VT_VALMASK) >= VT_CONST)
        return;

    /* modify all stack values */
    saved = 0;
    l = 0;
    for(p = vstack, p1 = vtop - n; p <= p1; p++) {
        if ((p->r & VT_VALMASK) == r ||
            ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) {
            /* must save value on stack if not already done */
            if (!saved) {
                /* NOTE: must reload 'r' because r might be equal to r2 */
                r = p->r & VT_VALMASK;
                /* store register in the stack */
                type = &p->type;
                if ((p->r & VT_LVAL) ||
                    (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
                    type = &char_pointer_type;
#else
                    type = &int_type;
#endif
                size = type_size(type, &align);
                loc = (loc - size) & -align;
                sv.type.t = type->t;
                sv.r = VT_LOCAL | VT_LVAL;
                sv.c.i = loc;
                store(r, &sv);
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
                /* x86 specific: need to pop fp register ST0 if saved */
                if (r == TREG_ST0) {
                    o(0xd8dd); /* fstp %st(0) */
                }
#endif
#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
                /* special long long case */
                if ((type->t & VT_BTYPE) == VT_LLONG) {
                    sv.c.i += 4;
                    store(p->r2, &sv);
                }
#endif
                l = loc;
                saved = 1;
            }
            /* mark that stack entry as being saved on the stack */
            if (p->r & VT_LVAL) {
                /* also clear the bounded flag because the
                   relocation address of the function was stored in
                   p->c.i */
                p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
            } else {
                p->r = lvalue_type(p->type.t) | VT_LOCAL;
            }
            p->r2 = VT_CONST;
            p->c.i = l;
        }
    }
}

#ifdef TCC_TARGET_ARM
/* find a register of class 'rc2' with at most one reference on stack.
 * If none, call get_reg(rc) */
ST_FUNC int get_reg_ex(int rc, int rc2)
{
    int r;
    SValue *p;
    
    for(r=0;r<NB_REGS;r++) {
        if (reg_classes[r] & rc2) {
            int n;
            n=0;
            for(p = vstack; p <= vtop; p++) {
                if ((p->r & VT_VALMASK) == r ||
                    (p->r2 & VT_VALMASK) == r)
                    n++;
            }
            if (n <= 1)
                return r;
        }
    }
    return get_reg(rc);
}
#endif

/* find a free register of class 'rc'. If none, save one register */
ST_FUNC int get_reg(int rc)
{
    int r;
    SValue *p;

    /* find a free register */
    for(r=0;r<NB_REGS;r++) {
        if (reg_classes[r] & rc) {
            for(p=vstack;p<=vtop;p++) {
                if ((p->r & VT_VALMASK) == r ||
                    (p->r2 & VT_VALMASK) == r)
                    goto notfound;
            }
            return r;
        }
    notfound: ;
    }
    
    /* no register left : free the first one on the stack (VERY
       IMPORTANT to start from the bottom to ensure that we don't
       spill registers used in gen_opi()) */
    for(p=vstack;p<=vtop;p++) {



( run in 1.486 second using v1.01-cache-2.11-cpan-5735350b133 )