/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' and 'long long' cases. */ void gen_cvt_itof(int t) { gv(RC_ST0); if (t == VT_FLOAT) out_op(IL_OP_CONV_R4); else out_op(IL_OP_CONV_R8); }
/* convert from one floating point type to another */ void gen_cvt_ftof(int t) { gv(RC_ST0); if (t == VT_FLOAT) { out_op(IL_OP_CONV_R4); } else { out_op(IL_OP_CONV_R8); } }
static void gen_expr_struct_lea(expr *e) { ASSERT_NOT_DOT(); gen_expr(e->lhs); /* cast for void* arithmetic */ out_change_type(type_ptr_to(type_nav_btype(cc1_type_nav, type_void))); out_push_l(type_nav_btype(cc1_type_nav, type_intptr_t), struct_offset(e)); /* integral offset */ out_op(op_plus); if(fopt_mode & FOPT_VERBOSE_ASM) out_comment("struct member %s", e->bits.struct_mem.d->spel); { decl *d = e->bits.struct_mem.d; out_change_type(type_ptr_to(d->ref)); /* set if we're a bitfield - out_deref() and out_store() * i.e. read + write then handle this */ if(d->bits.var.field_width){ unsigned w = const_fold_val_i(d->bits.var.field_width); out_set_bitfield(d->bits.var.struct_offset_bitfield, w); out_comment("struct bitfield lea"); } } }
/* XXX: handle long long case */ void gen_cvt_ftoi(int t) { gv(RC_ST0); switch(t) { case VT_INT | VT_UNSIGNED: out_op(IL_OP_CONV_U4); break; case VT_LLONG: out_op(IL_OP_CONV_I8); break; case VT_LLONG | VT_UNSIGNED: out_op(IL_OP_CONV_U8); break; default: out_op(IL_OP_CONV_I4); break; } }
void v_stack_adj(out_ctx *octx, v_stackt amt, int sub) { out_flush_volatile( octx, out_op( octx, sub ? op_minus : op_plus, v_new_sp(octx, NULL), out_new_l( octx, type_nav_btype(cc1_type_nav, type_intptr_t), amt))); }
static void sanitize_assert_order( const out_val *test, enum op_type op, long limit, type *op_type, out_ctx *octx, const char *desc) { const out_val *vlimit = out_new_l( octx, op_type, limit); const out_val *lengthened_test = out_change_type( octx, out_val_retain(octx, test), op_type); const out_val *cmp = out_op(octx, op, lengthened_test, vlimit); sanitize_assert(cmp, octx, desc); }
const out_val *gen_expr_assign_compound(const expr *e, out_ctx *octx) { /* int += float * lea int, cast up to float, add, cast down to int, store */ const out_val *saved_post = NULL, *addr_lhs, *rhs, *lhs, *result; addr_lhs = gen_expr(e->lhs, octx); out_val_retain(octx, addr_lhs); /* 2 */ if(e->assign_is_post){ out_val_retain(octx, addr_lhs); /* 3 */ saved_post = out_deref(octx, addr_lhs); /* addr_lhs=2, saved_post=1 */ } /* delay the dereference until after generating rhs. * this is fine, += etc aren't sequence points */ rhs = gen_expr(e->rhs, octx); /* here's the delayed dereference */ lhs = out_deref(octx, addr_lhs); /* addr_lhs=1 */ if(e->bits.compoundop.upcast_ty) lhs = out_cast(octx, lhs, e->bits.compoundop.upcast_ty, /*normalise_bool:*/1); result = out_op(octx, e->bits.compoundop.op, lhs, rhs); gen_op_trapv(e->tree_type, &result, octx, e->bits.compoundop.op); if(e->bits.compoundop.upcast_ty) /* need to cast back down to store */ result = out_cast(octx, result, e->tree_type, /*normalise_bool:*/1); if(!saved_post) out_val_retain(octx, result); out_store(octx, addr_lhs, result); if(!saved_post) return result; return saved_post; }
/* store register 'r' in lvalue 'v' */ void store(int r, SValue *sv) { int v, fc, ft; v = sv->r & VT_VALMASK; fc = sv->c.i; ft = sv->t; if (v == VT_LOCAL) { if (fc >= ARG_BASE) { fc -= ARG_BASE; /* XXX: check IL arg store semantics */ if (fc <= 0xff) { out_opb(IL_OP_STARG_S, fc); } else { out_opi(IL_OP_STARG, fc); } } else { if (fc >= 0 && fc <= 4) { out_op(IL_OP_STLOC_0 + fc); } else if (fc <= 0xff) { out_opb(IL_OP_STLOC_S, fc); } else { out_opi(IL_OP_STLOC, fc); } } } else if (v == VT_CONST) { /* XXX: handle globals */ out_opi(IL_OP_STSFLD, 0); } else { if ((ft & VT_BTYPE) == VT_FLOAT) out_op(IL_OP_STIND_R4); else if ((ft & VT_BTYPE) == VT_DOUBLE) out_op(IL_OP_STIND_R8); else if ((ft & VT_BTYPE) == VT_LDOUBLE) out_op(IL_OP_STIND_R8); else if ((ft & VT_BTYPE) == VT_BYTE) out_op(IL_OP_STIND_I1); else if ((ft & VT_BTYPE) == VT_SHORT) out_op(IL_OP_STIND_I2); else out_op(IL_OP_STIND_I4); } }
void gen_expr_assign_compound(expr *e) { /* int += float * lea int, cast up to float, add, cast down to int, store */ lea_expr(e->bits.compound_upcast ? expr_cast_child(e->lhs) : e->lhs); if(e->assign_is_post){ out_dup(); out_deref(); out_flush_volatile(); out_swap(); out_comment("saved for compound op"); } out_dup(); /* delay the dereference until after generating rhs. * this is fine, += etc aren't sequence points */ gen_expr(e->rhs); /* here's the delayed dereference */ out_swap(); out_deref(); if(e->bits.compound_upcast) out_cast(e->lhs->tree_type, /*normalise_bool:*/1); out_swap(); out_op(e->op); if(e->bits.compound_upcast) /* need to cast back down to store */ out_cast(e->tree_type, /*normalise_bool:*/1); out_store(); if(e->assign_is_post) out_pop(); }
/** * 函数名:out_ic * 作者:ao * 功能:将中间代码打印至文件ir.txt */ int out_ic() { ics_now = intercodes; while(ics_now != NULL) { switch(ics_now->code->kind) { case 0: printf("FUNCTION %s\n",ics_now->code->u.func_d.name);break; case 1: { printf("PARAM "); out_op(ics_now->code->u.param.param); printf("\n"); break; } case 2: { out_op(ics_now->code->u.func_c.reop); printf(" := CALL %s\n",ics_now->code->u.func_c.name); } case 3: { printf("DEC "); out_op(ics_now->code->u.dec.var); printf(" %d\n",ics_now->code->u.dec.size); break; } case 4: { printf("ARG "); out_op(ics_now->code->u.arg.arg); printf("\n"); break; } case 5: { out_op(ics_now->code->u.assign.left); printf(" := "); out_op(ics_now->code->u.assign.right); printf("\n"); break; } case 6: { out_op(ics_now->code->u.relop.result); printf(" := "); out_op(ics_now->code->u.relop.left); printf(" %s ",ics_now->code->u.relop.r_kind); out_op(ics_now->code->u.relop.right); printf("\n"); break; } case 7: { out_op(ics_now->code->u.binop.result); printf(" := "); out_op(ics_now->code->u.binop.op1); printf(" %s ",ics_now->code->u.binop.o_kind); out_op(ics_now->code->u.binop.op2); printf("\n"); break; } case 8: { out_op(ics_now->code->u.notop.result); printf(" := !"); out_op(ics_now->code->u.notop.op); printf("\n"); break; } case 9: { printf("RETURN "); out_op(ics_now->code->u.retop.result); printf("\n"); break; } case 10: { printf("IF "); out_op(ics_now->code->u.ifop.relop); printf(" GOTO "); out_op(ics_now->code->u.ifop.label); printf("\n"); break; } case 11: { printf("LABEL "); out_op(ics_now->code->u.label.label); printf(" :\n"); break; } case 12: { printf("GOTO "); out_op(ics_now->code->u.gtop.gtop); printf("\n"); break; } } ics_now = ics_now->next; } return 1; }
const out_val *out_op( out_ctx *octx, enum op_type binop, const out_val *lhs, const out_val *rhs) { const out_val *div = NULL; const out_val *vconst = NULL, *vregp_or_lbl = NULL; const out_val *result; const out_val *decay_except[] = { lhs, rhs, NULL }; v_decay_flags_except(octx, decay_except); /* an op instruction may change cpu flags */ fill_if_type(lhs, &vconst, &vregp_or_lbl); fill_if_type(rhs, &vconst, &vregp_or_lbl); /* check for adding or subtracting to stack */ if(vconst && vregp_or_lbl){ result = try_mem_offset(octx, binop, vconst, vregp_or_lbl, rhs); if(result) return result; } if(vconst && const_is_noop(binop, vconst, vconst == lhs)) return consume_one(octx, vconst == lhs ? rhs : lhs, lhs, rhs); /* constant folding */ if(vconst && (fopt_mode & FOPT_CONST_FOLD)){ const out_val *oconst = (vconst == lhs ? rhs : lhs); if(oconst->type == V_CONST_I){ int step_l = calc_ptr_step(lhs->t); int step_r = calc_ptr_step(rhs->t); out_val *consted; /* currently we bail if something like (short *)0 + 2 * is attempted */ if(step_l == 1 && step_r == 1){ consted = try_const_fold(octx, binop, lhs, rhs); if(consted) return consted; } } } switch(binop){ case op_plus: case op_minus: apply_ptr_step(octx, &lhs, &rhs, &div); break; case op_multiply: case op_divide: if(vconst && (fopt_mode & FOPT_TRAPV) == 0) try_shift_conv(octx, &binop, &lhs, &rhs); break; default: break; } result = impl_op(octx, binop, lhs, rhs); if(div) result = out_op(octx, op_divide, result, div); return result; }
static void apply_ptr_step( out_ctx *octx, const out_val **lhs, const out_val **rhs, const out_val **div_out) { int l_ptr = !!type_is((*lhs)->t, type_ptr); int r_ptr = !!type_is((*rhs)->t, type_ptr); int ptr_step; if(!l_ptr && !r_ptr) return; ptr_step = calc_ptr_step((l_ptr ? *lhs : *rhs)->t); if(l_ptr ^ r_ptr){ /* ptr +/- int, adjust the non-ptr by sizeof *ptr */ const out_val **incdec = (l_ptr ? rhs : lhs); out_val *mut_incdec; *incdec = mut_incdec = v_dup_or_reuse(octx, *incdec, (*incdec)->t); switch(mut_incdec->type){ case V_CONST_I: if(ptr_step == -1){ *incdec = out_op(octx, op_multiply, *incdec, vla_size( type_next((l_ptr ? *lhs : *rhs)->t), octx)); mut_incdec = NULL; /* safety */ }else{ mut_incdec->bits.val_i *= ptr_step; } break; case V_CONST_F: assert(0 && "float pointer inc?"); case V_LBL: case V_FLAG: case V_REG_SPILT: assert(mut_incdec->retains == 1); *incdec = (out_val *)v_to_reg(octx, *incdec); case V_REG: { const out_val *n; if(ptr_step == -1){ n = vla_size( type_next((l_ptr ? *lhs : *rhs)->t), octx); }else{ n = out_new_l( octx, type_nav_btype(cc1_type_nav, type_intptr_t), ptr_step); } *incdec = (out_val *)out_op(octx, op_multiply, *incdec, n); break; } } }else if(l_ptr && r_ptr){ /* difference - divide afterwards */ if(ptr_step == -1){ *div_out = vla_size(type_next((*lhs)->t), octx); }else{ *div_out = out_new_l(octx, type_ptr_to(type_nav_btype(cc1_type_nav, type_void)), ptr_step); } } }
/* generate an integer binary operation */ void gen_opi(int op) { gv2(RC_ST1, RC_ST0); switch(op) { case '+': out_op(IL_OP_ADD); goto std_op; case '-': out_op(IL_OP_SUB); goto std_op; case '&': out_op(IL_OP_AND); goto std_op; case '^': out_op(IL_OP_XOR); goto std_op; case '|': out_op(IL_OP_OR); goto std_op; case '*': out_op(IL_OP_MUL); goto std_op; case TOK_SHL: out_op(IL_OP_SHL); goto std_op; case TOK_SHR: out_op(IL_OP_SHR_UN); goto std_op; case TOK_SAR: out_op(IL_OP_SHR); goto std_op; case '/': case TOK_PDIV: out_op(IL_OP_DIV); goto std_op; case TOK_UDIV: out_op(IL_OP_DIV_UN); goto std_op; case '%': out_op(IL_OP_REM); goto std_op; case TOK_UMOD: out_op(IL_OP_REM_UN); std_op: vtop--; vtop[0].r = REG_ST0; break; case TOK_EQ: case TOK_NE: case TOK_LT: case TOK_LE: case TOK_GT: case TOK_GE: case TOK_ULT: case TOK_ULE: case TOK_UGT: case TOK_UGE: vtop--; vtop[0].r = VT_CMP; vtop[0].c.i = op; break; } }
/* generate function epilog */ void gfunc_epilog(void) { out_op(IL_OP_RET); fprintf(il_outfile, "}\n\n"); }
/* load 'r' from value 'sv' */ void load(int r, SValue *sv) { int v, fc, ft; v = sv->r & VT_VALMASK; fc = sv->c.i; ft = sv->t; if (sv->r & VT_LVAL) { if (v == VT_LOCAL) { if (fc >= ARG_BASE) { fc -= ARG_BASE; if (fc >= 0 && fc <= 4) { out_op(IL_OP_LDARG_0 + fc); } else if (fc <= 0xff) { out_opb(IL_OP_LDARG_S, fc); } else { out_opi(IL_OP_LDARG, fc); } } else { if (fc >= 0 && fc <= 4) { out_op(IL_OP_LDLOC_0 + fc); } else if (fc <= 0xff) { out_opb(IL_OP_LDLOC_S, fc); } else { out_opi(IL_OP_LDLOC, fc); } } } else if (v == VT_CONST) { /* XXX: handle globals */ out_opi(IL_OP_LDSFLD, 0); } else { if ((ft & VT_BTYPE) == VT_FLOAT) { out_op(IL_OP_LDIND_R4); } else if ((ft & VT_BTYPE) == VT_DOUBLE) { out_op(IL_OP_LDIND_R8); } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { out_op(IL_OP_LDIND_R8); } else if ((ft & VT_TYPE) == VT_BYTE) out_op(IL_OP_LDIND_I1); else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) out_op(IL_OP_LDIND_U1); else if ((ft & VT_TYPE) == VT_SHORT) out_op(IL_OP_LDIND_I2); else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) out_op(IL_OP_LDIND_U2); else out_op(IL_OP_LDIND_I4); } } else { if (v == VT_CONST) { /* XXX: handle globals */ if (fc >= -1 && fc <= 8) { out_op(IL_OP_LDC_I4_M1 + fc + 1); } else { out_opi(IL_OP_LDC_I4, fc); } } else if (v == VT_LOCAL) { if (fc >= ARG_BASE) { fc -= ARG_BASE; if (fc <= 0xff) { out_opb(IL_OP_LDARGA_S, fc); } else { out_opi(IL_OP_LDARGA, fc); } } else { if (fc <= 0xff) { out_opb(IL_OP_LDLOCA_S, fc); } else { out_opi(IL_OP_LDLOCA, fc); } } } else { /* XXX: do it */ } } }
static void impl_overlay_mem_reg( out_ctx *octx, unsigned memsz, unsigned nregs, struct vreg regs[], int mem2reg, const out_val *ptr) { const unsigned pws = platform_word_size(); struct vreg *cur_reg = regs; unsigned reg_i = 0; if(memsz == 0){ out_val_release(octx, ptr); return; } UCC_ASSERT( nregs * pws >= memsz, "not enough registers for memory overlay"); out_comment(octx, "overlay, %s2%s(%u)", mem2reg ? "mem" : "reg", mem2reg ? "reg" : "mem", memsz); if(!mem2reg){ /* reserve all registers so we don't accidentally wipe before the spill */ for(reg_i = 0; reg_i < nregs; reg_i++) v_reserve_reg(octx, ®s[reg_i]); } for(;; cur_reg++, reg_i++){ /* read/write whatever size is required */ type *this_ty; unsigned this_sz; if(cur_reg->is_float){ UCC_ASSERT(memsz >= 4, "float for memsz %u?", memsz); this_ty = type_nav_btype( cc1_type_nav, memsz > 4 ? type_double : type_float); }else{ this_ty = type_nav_MAX_FOR(cc1_type_nav, memsz); } this_sz = type_size(this_ty, NULL); UCC_ASSERT(this_sz <= memsz, "reading/writing too much memory"); ptr = out_change_type(octx, ptr, type_ptr_to(this_ty)); out_val_retain(octx, ptr); if(mem2reg){ const out_val *fetched; /* can use impl_deref, as we have a register already, * and know that the memory is an lvalue and not a bitfield * * this means we can load straight into the desired register */ fetched = impl_deref(octx, ptr, cur_reg); UCC_ASSERT(reg_i < nregs, "reg oob"); if(fetched->type != V_REG || !vreg_eq(&fetched->bits.regoff.reg, cur_reg)){ /* move to register */ v_freeup_reg(octx, cur_reg); fetched = v_to_reg_given(octx, fetched, cur_reg); } out_flush_volatile(octx, fetched); v_reserve_reg(octx, cur_reg); /* prevent changes */ }else{ const out_val *vreg = v_new_reg(octx, NULL, this_ty, cur_reg); out_store(octx, ptr, vreg); } memsz -= this_sz; /* early termination */ if(memsz == 0) break; /* increment our memory pointer */ ptr = out_change_type( octx, ptr, type_ptr_to(type_nav_btype(cc1_type_nav, type_uchar))); ptr = out_op(octx, op_plus, ptr, out_new_l( octx, type_nav_btype(cc1_type_nav, type_intptr_t), pws)); } out_val_release(octx, ptr); /* done, unreserve all registers */ for(reg_i = 0; reg_i < nregs; reg_i++) v_unreserve_reg(octx, ®s[reg_i]); }