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 )