void gen_expr_if(expr *e, symtable *stab) { char *lblfin, *lblelse; lblfin = asm_label_code("ifexpa"); gen_expr(e->expr, stab); if(e->lhs){ lblelse = asm_label_code("ifexpb"); asm_temp(1, "pop rax"); asm_temp(1, "test rax, rax"); asm_temp(1, "jz %s", lblelse); gen_expr(e->lhs, stab); asm_temp(1, "jmp %s", lblfin); asm_label(lblelse); }else{ asm_temp(1, "mov rax, [rsp] ; save for ?:"); asm_temp(1, "test rax, rax"); asm_temp(1, "jnz %s", lblfin); asm_temp(1, "pop rax ; discard lhs"); } gen_expr(e->rhs, stab); asm_label(lblfin); if(e->lhs) free(lblelse); free(lblfin); }
void gen_expr_sizeof(expr *e, symtable *stab) { decl *d = e->expr->tree_type; (void)stab; asm_temp(1, "push %d ; sizeof %s%s", decl_size(d), e->expr->expr_is_sizeof ? "type " : "", decl_to_str(d)); }
void gen_stmt_do(stmt *s) { char *begin = asm_label_flow("do_start"); asm_label(begin); gen_stmt(s->lhs); asm_label(s->lbl_continue); gen_expr(s->expr, s->symtab); asm_temp(1, "pop rax"); asm_temp(1, "test rax, rax"); asm_temp(1, "jnz %s", begin); asm_label(s->lbl_break); free(begin); }
void gen_expr_funcall(expr *e, symtable *stab) { const char *const fname = e->expr->spel; expr **iter; int nargs = 0; if(fopt_mode & FOPT_ENABLE_ASM && fname && !strcmp(fname, ASM_INLINE_FNAME)){ const char *str; expr *arg1; int i; if(!e->funcargs || e->funcargs[1] || !expr_kind(e->funcargs[0], addr)) die_at(&e->where, "invalid __asm__ arguments"); arg1 = e->funcargs[0]; str = arg1->array_store->data.str; for(i = 0; i < arg1->array_store->len - 1; i++){ char ch = str[i]; if(!isprint(ch) && !isspace(ch)) invalid: die_at(&arg1->where, "invalid __asm__ string (character %d)", ch); } if(str[i]) goto invalid; asm_temp(0, "; start manual __asm__"); fprintf(cc_out[SECTION_TEXT], "%s\n", arg1->array_store->data.str); asm_temp(0, "; end manual __asm__"); }else{ /* continue with normal funcall */ if(e->funcargs){ /* need to push on in reverse order */ for(iter = e->funcargs; *iter; iter++); for(iter--; iter >= e->funcargs; iter--){ gen_expr(*iter, stab); nargs++; } } if(e->sym && !e->sym->decl->decl_ptr && e->sym->decl->spel){ /* simple */ asm_temp(1, "call %s", e->sym->decl->spel); }else{ gen_expr(e->expr, stab); asm_temp(1, "pop rax ; function address"); asm_temp(1, "call rax ; duh"); } if(nargs) asm_temp(1, "add rsp, %d ; %d arg%s", nargs * platform_word_size(), nargs, nargs == 1 ? "" : "s"); asm_temp(1, "push rax ; ret"); } }
void gen_expr_val(expr *e, symtable *stab) { (void)stab; fputs("\tmov rax, ", cc_out[SECTION_TEXT]); e->f_gen_1(e, cc_out[SECTION_TEXT]); fputc('\n', cc_out[SECTION_TEXT]); asm_temp(1, "push rax"); }
void gen_stmt_if(stmt *s) { char *lbl_else = asm_label_code("else"); char *lbl_fi = asm_label_code("fi"); gen_expr(s->expr, s->symtab); asm_temp(1, "pop rax"); asm_temp(1, "test rax, rax"); asm_temp(1, "jz %s", lbl_else); gen_stmt(s->lhs); asm_temp(1, "jmp %s", lbl_fi); asm_label(lbl_else); if(s->rhs) gen_stmt(s->rhs); asm_label(lbl_fi); free(lbl_else); free(lbl_fi); }
void gen_stmt_for(stmt *s) { char *lbl_test = asm_label_flow("for_test"); /* don't else-if, possible to have both (comma-exp for init) */ if(s->flow->for_init){ gen_expr(s->flow->for_init, s->flow->for_init_symtab); asm_temp(1, "pop rax ; unused for init"); } asm_label(lbl_test); if(s->flow->for_while){ gen_expr(s->flow->for_while, s->flow->for_init_symtab); asm_temp(1, "pop rax"); asm_temp(1, "test rax, rax"); asm_temp(1, "jz %s", s->lbl_break); } gen_stmt(s->lhs); asm_label(s->lbl_continue); if(s->flow->for_inc){ gen_expr(s->flow->for_inc, s->flow->for_init_symtab); asm_temp(1, "pop rax ; unused for inc"); } asm_temp(1, "jmp %s", lbl_test); asm_label(s->lbl_break); free(lbl_test); }
void asm_sym(enum asm_sym_type t, sym *s, const char *reg) { const int is_global = s->type == sym_global || (s->decl->type->spec & (spec_extern | spec_static)); char *const dsp = s->decl->spel; int is_auto = s->type == sym_local; char stackbrackets[16]; char *brackets; if(is_global){ const int bracket_len = strlen(dsp) + 16; brackets = umalloc(bracket_len + 1); if(t == ASM_LEA || s->decl->func_code){ snprintf(brackets, bracket_len, "%s", dsp); /* int (*p)() = printf; for example */ /* * either: * we want lea rax, [a] * and convert this to mov rax, a // this is because Macho-64 is an awful binary format * force a mov for funcs (i.e. &func == func) */ t = ASM_LOAD; }else{ const char *type_s = ""; if(asm_type_size(s->decl) == ASM_SIZE_WORD) type_s = "qword "; /* get warnings for "lea rax, [qword tim]", just do "lea rax, [tim]" */ snprintf(brackets, bracket_len, "[%s%s]", t == ASM_LEA ? "" : type_s, dsp); } }else{ brackets = stackbrackets; snprintf(brackets, sizeof stackbrackets, "[rbp %c %d]", is_auto ? '-' : '+', ((is_auto ? 1 : 2) * platform_word_size()) + s->offset); } asm_temp(1, "%s %s, %s ; %s%s", t == ASM_LEA ? "lea" : "mov", t == ASM_SET ? brackets : reg, t == ASM_SET ? reg : brackets, t == ASM_LEA ? "&" : "", dsp ); if(brackets != stackbrackets) free(brackets); }
void asm_new(enum asm_type t, void *p) { switch(t){ case asm_assign: asm_temp(1, "pop rax"); break; case asm_call: asm_temp(1, "call %s", (const char *)p); break; case asm_load_ident: asm_temp(1, "load %s", (const char *)p); break; case asm_load_val: asm_temp(1, "load val %d", *(int *)p); break; case asm_op: asm_temp(1, "%s", op_to_str(*(enum op_type *)p)); break; case asm_pop: asm_temp(1, "pop"); break; case asm_push: asm_temp(1, "push"); break; case asm_addrof: fprintf(stderr, "BUH?? (addrof)\n"); break; } }
void asm_label(const char *lbl) { asm_temp(0, "%s:", lbl); }
void gen_stmt_noop(stmt *s) { (void)s; asm_temp(1, "; noop"); }