/* NOTE: the same name space as C labels is used to avoid using too much memory when storing labels in TokenStrings */ static void asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value) { Sym *sym; sym = label_find(label); if (sym) { if (sym->r) { /* the label is already defined */ if (!is_local) { tcc_error("assembler label '%s' already defined", get_tok_str(label, NULL)); } else { /* redefinition of local labels is possible */ goto new_label; } } } else { new_label: sym = label_push(&s1->asm_labels, label, 0); sym->type.t = VT_STATIC | VT_VOID; } sym->r = sh_num; sym->jnext = value; }
char* get_sym_str(Sym* sym) { static char name[256]; char* symname; symname = get_tok_str(sym->v, NULL); name[0] = 0; /* if static, add prefix */ #if 0 if(sym->type.t & VT_STATICLOCAL) { strcpy(name, "__local_"); } else #endif if(sym->type.t & VT_STATIC) { //fprintf(stderr,"sym %s type 0x%x current_fn %s token %d\n",symname,sym->type.t,current_fn,sym->v); if((sym->type.t & VT_STATICLOCAL) && current_fn[0] != 0 && !((sym->type.t & VT_BTYPE) == VT_FUNC)) sprintf(name, "%s_FUNC_%s_", static_prefix, current_fn); else strcpy(name, static_prefix); #if 0 for(int i = 0; i < labels; i++) { if(strcmp(label[i].name, symname) == 0) strcpy(name, "__local_"); } #endif } /* add symbol name */ strcat(name, symname); //fprintf(stderr,"symbol %s type 0x%x\n", name, sym->type.t); return name; }
static void asm_expr_unary(TCCState *s1, ExprValue *pe) { Sym *sym; int op, n, label; const char *p; switch(tok) { case TOK_PPNUM: p = tokc.cstr->data; n = strtoul(p, (char **)&p, 0); if (*p == 'b' || *p == 'f') { /* backward or forward label */ label = asm_get_local_label_name(s1, n); sym = label_find(label); if (*p == 'b') { /* backward : find the last corresponding defined label */ if (sym && sym->r == 0) sym = sym->prev_tok; if (!sym) tcc_error("local label '%d' not found backward", n); } else { /* forward */ if (!sym || sym->r) { /* if the last label is defined, then define a new one */ sym = label_push(&s1->asm_labels, label, 0); sym->type.t = VT_STATIC | VT_VOID; } } pe->v = 0; pe->sym = sym; } else if (*p == '\0') { pe->v = n; pe->sym = NULL; } else { tcc_error("invalid number syntax"); } next(); break; case '+': next(); asm_expr_unary(s1, pe); break; case '-': case '~': op = tok; next(); asm_expr_unary(s1, pe); if (pe->sym) tcc_error("invalid operation with label"); if (op == '-') pe->v = -pe->v; else pe->v = ~pe->v; break; case TOK_CCHAR: case TOK_LCHAR: pe->v = tokc.i; pe->sym = NULL; next(); break; case '(': next(); asm_expr(s1, pe); skip(')'); break; default: if (tok >= TOK_IDENT) { /* label case : if the label was not found, add one */ sym = label_find(tok); if (!sym) { sym = label_push(&s1->asm_labels, tok, 0); /* NOTE: by default, the symbol is global */ sym->type.t = VT_VOID; } if (sym->r == SHN_ABS) { /* if absolute symbol, no need to put a symbol value */ pe->v = sym->jnext; pe->sym = NULL; } else { pe->v = 0; pe->sym = sym; } next(); } else { tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); } break; } }
void gcode(void) { int i, n, t, r, stacksize, addr, pc, disp, rel, errs, more, func_start; Branch *b, *bn; // Generate function prolog func_start = cur_text_section->data_offset; if (!func_naked) { // Align local size to word stacksize = (-loc + 3) & -4; if (stacksize >= 4096) { // Generate stack guard since parameters can cross page boundary Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); gen(0xb8); // mov stacksize, %eax genword(stacksize); gen(0xe8); // call __chkstk, (does the stackframe too) put_reloc(cur_text_section, sym, cur_text_section->data_offset, R_386_PC32); genword(-4); } else { if (do_debug || loc || !func_noargs) { gen(0x55); // push %ebp gen(0x89); // mov %esp, %ebp gen(0xe5); } if (stacksize > 0) { if (stacksize == (char) stacksize) { gen(0x83); // sub esp, stacksize gen(0xec); gen(stacksize); } else { gen(0x81); // sub esp, stacksize gen(0xec); genword(stacksize); } } } // Save callee-saved registers used by function. for (r = 0; r < NB_REGS; ++r) { if ((reg_classes[r] & RC_SAVE) && (regs_used & (1 << r))) { gen(0x50 + r); // push r } } } // Optimize jumps more = 1; while (more) { more = 0; for (i = 0; i < br; ++i) { b = branch + i; if (b->type == CodeLabel) b->target = 0; if (b->type != CodeJump) continue; t = skip_nops(b->target, 1); if (branch[t].type == CodeJump && !branch[t].param && b->target != branch[t].target) { // Eliminate jump to jump b->target = branch[t].target; more = 1; continue; } // Find next non-nop n = i + 1; while (branch[n].type == CodeNop || branch[n].type == CodeLine) n++; bn = branch + n; if (b->ind != bn->ind) continue; if (!b->param && bn->type == CodeJump) { // Eliminate dead jump instruction bn->type = CodeNop; more = 1; continue; } if (b->target > i && b->target <= n) { // Eliminate jump to next instruction b->type = CodeNop; more = 1; continue; } t = skip_nops(n + 1, 0); if (bn->type == CodeJump && !bn->param && b->target == t && bn->ind == branch[t].ind) { // Optimize inverted jump if (b->param) b->param ^= 1; b->target = bn->target; bn->type = CodeNop; more = 1; continue; } } // Eliminate unused labels for (i = 0; i < br; ++i) { b = branch + i; if (b->type == CodeJump) branch[b->target].target++; } for (i = 0; i < br; ++i) { b = branch + i; if (b->type == CodeLabel && !b->target && !b->sym) { // Remove label with no references b->type = CodeNop; more = 1; } } } // Assign addresses to branch points, assuming only long jumps addr = cur_text_section->data_offset; pc = 0; for (i = 0; i < br; ++i) { b = branch + i; addr += b->ind - pc; b->addr = addr; switch (b->type) { case CodeJump: addr += 5; if (b->param != 0) addr++; break; case CodeAlign: // Use convervative estimate for short/long jump estimation addr += b->param - 1; break; } pc = b->ind; } // Find jumps which can be encoded as short jumps for (i = 0; i < br; ++i) { b = branch + i; if (b->type == CodeJump) { disp = branch[b->target].addr - b->addr - 2; if (b->param) disp--; if (disp == (char) disp) b->type = CodeShortJump; } } // Assign final addresses to branch points addr = cur_text_section->data_offset; pc = 0; for (i = 0; i < br; ++i) { b = branch + i; addr += b->ind - pc; b->addr = addr; switch (b->type) { case CodeJump: addr += 5; if (b->param) addr++; break; case CodeShortJump: addr += 2; break; case CodeAlign: addr = (addr + b->param - 1) & -b->param; break; } pc = b->ind; } // Generate code blocks pc = 0; errs = 0; for (i = 0; i < br; ++i) { b = branch + i; // Output code block before branch point if (b->ind != pc) { genblk(code + pc, b->ind - pc); pc = b->ind; } switch (b->type) { case CodeLabel: // Export label if symbol defined if (b->sym) { put_extern_sym_ex(b->sym, cur_text_section, b->addr, 0, 0); sym_free(b->sym); } break; case CodeJump: // Generate long jump instruction if (branch[b->target].type != CodeLabel) { printf("internal error: jump %d to non-label %d\n", i, b->target); errs++; } if (b->param > 0xff) error("invalid displacement"); if (b->param == 0) { gen(0xe9); genword(branch[b->target].addr - (b->addr + 5)); } else { gen(0x0f); gen(b->param - 0x10); genword(branch[b->target].addr - (b->addr + 6)); } break; case CodeShortJump: // Generate short jump instruction if (branch[b->target].type != CodeLabel) { printf("internal error: jump %d to non-label %d\n", i, b->target); errs++; } if (b->param == 0) { gen(0xeb); } else { gen(b->param - 0x20); } gen(branch[b->target].addr - (b->addr + 2)); break; case CodeReloc: if (b->param) { rel = R_386_PC32; } else { rel = R_386_32; } put_elf_reloc(symtab_section, cur_text_section, b->addr, rel, b->target); break; case CodeAlign: i = addr; while (i & (b->param - 1)) { gen(b->target); i++; } break; case CodeLine: put_stabn(N_SLINE, 0, b->target, b->addr - func_start); break; } } // Generate function epilog if (!func_naked) { // Restore callee-saved registers used by function. for (r = NB_REGS; r >= 0; --r) { if ((reg_classes[r] & RC_SAVE) && (regs_used & (1 << r))) { gen(0x58 + r); // pop r } } if (do_debug || loc || !func_noargs) gen(0xc9); // leave // Generate return if (func_ret_sub == 0) { gen(0xc3); // ret } else { gen(0xc2); // ret n gen(func_ret_sub); gen(func_ret_sub >> 8); } } #ifdef DEBUG_BRANCH printf("\nbranch table for %s\n", func_name); printf(" # t targ parm ind addr\n"); printf("---- - ---- ----- -------- --------\n"); for (i = 0; i < br; ++i) { b = branch + i; printf("%04d %c %04d %04x %08x %08x", i, "SLJjRANlE"[b->type], b->target, b->param, b->ind, b->addr); if (branch[i].sym) { printf(" sym=%s", get_tok_str(b->sym->v, NULL)); } printf("\n"); } printf("\n"); #endif if (errs) error("internal error: code generation"); }
double float_eval(exp_tree_t *t, double val) { int i; double result = 0.0; double (*fp)(double); int v; hashtab_t *function_dispatch_table = new_hashtab(); struct fts { char *key; double (*val)(double); } function_table[] = { { "arccos", &acos }, { "arcsin", &asin }, { "arctan", &atan }, /* XXX: arccsc, arcsec, arccot */ { "cos", &cos}, { "cot", &my_cot }, { "csc", &my_csc }, { "ln", &log }, /* n.b. this is by design; base-10 logarithms = shit */ { "log", &log }, { "sin", &sin }, { "sqrt", &sqrt }, { "tan", &tan }, { "sec", &my_sec }, { "D", &give_a_nan } }; /* * Register functions */ for (i = 0; i < sizeof(function_table) / sizeof(struct fts); ++i) { hashtab_insert(function_dispatch_table, function_table[i].key, (void *)function_table[i].val); } #define children_reduce_infix(operator) \ for (i = 1, result = float_eval(t->child[0], val); i < t->child_count; ++i) \ result = result operator float_eval(t->child[i], val); #define children_reduce_prefix(operator) \ for (i = 1, result = float_eval(t->child[0], val); i < t->child_count; ++i) \ result = operator ( result , float_eval(t->child[i], val) ); switch (t->head_type) { case NEGATIVE: return -float_eval(t->child[0], val); case ADD: children_reduce_infix(+); break; case SUB: children_reduce_infix(-); break; case MULT: children_reduce_infix(*); break; case DIV: children_reduce_infix(/); break; case EXP: children_reduce_prefix(powf); break; case FUNC: { fp = hashtab_lookup(function_dispatch_table, get_tok_str(*(t->tok))); if (!fp) { fprintf(stderr, "error: FLOATEVAL: uncoded function: %s\n", get_tok_str(*(t->tok))); exit(1); } result = fp(float_eval(t->child[0], val)); } break; case VARIABLE: { if (!strcmp(get_tok_str(*(t->tok)), "e")) result = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035; else /* * Provided value + some variation based * on the first letter of the variable */ result = val + (float)(1.0 * (*get_tok_str(*(t->tok)) % 5)); } break; case NUMBER: { sscanf(get_tok_str(*(t->tok)), "%d", &v); result = (double)v; } break; } return result; }