📄 gen86.c
字号:
} return size;}/* * push a list of parameters onto the stack and return the number of * bytes that the parameters occupy. */static SIZE g_parms P1 (const EXPR *, ep){ SIZE size; is_parameter++; for (size = 0L; ep != NIL_EXPR; ep = ep->v.p[1]) { size += push_param (ep->v.p[0]); } is_parameter--; return size;}static ADDRESS *func_result P3 (FLAGS, flags, SIZE, bytes, TYP *, tp){ ADDRESS *ap; stack_offset += bytes; if (is_parameter) { g_stack (bytes); } if (flags & F_NOVALUE) { return NIL_ADDRESS; } switch (tp->type) {#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = float_register (); break;#endif /* FLOAT_IEEE */ case bt_int32: case bt_uint32: case bt_long: case bt_ulong: case bt_pointer32: if (!(flags & F_DREG)) { FATAL ((__FILE__, "func_result", "not F_DREG")); } ap = mdata_register (); g_code (op_mov, IL2, mk_reg (reg_usage->result->reg[0]), mk_low (ap)); g_code (op_mov, IL2, mk_reg (reg_usage->result->reg[1]), mk_high (ap)); break; default: if (flags & F_DREG) { ap = data_register (); } else if (flags & F_AREG) { ap = address_register (); } else { FATAL ( (__FILE__, "func_result", "not F_DREG or F_AREG (%d)", flags)); } if (ap->preg != reg_usage->result->reg[0]) { g_code (op_mov, IL2, &eax_reg, ap); } break; } return ap;}/* * generate a function call node and return the address mode of the result. */static ADDRESS *g_fcall P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap, *ap1; SIZE size; EXPR *ep0 = ep->v.p[0]; REG reg; if (!is_parameter && ep->nodetype != en_call) { switch (stackopt_option) { case OPT_SAFE: /* * no stack optimisation */ g_stack (stack_offset); break; case OPT_MINIMUM: /* * "Minimum" stack optimisation. Perform a stack optimisation * unless: * 1. The alloca() routine is called * 2. The function call is via a variable * 3. The function starts with an underscore character */ if ((ep0->nodetype != en_nacon) || (ep0->v.str[0] == (CHAR) '_') || (ep0->v.str == alloca_name)) { g_stack (stack_offset); } break; case OPT_AVERAGE: /* * "Average" stack optimisation. This will not suppress * the optimisation on encountering calls to functions * whose names begin with underscore. */ if ((ep0->nodetype != en_nacon) || (ep0->v.str == alloca_name)) { g_stack (stack_offset); } break; case OPT_MAXIMUM: /* * "Maximum" stack optimisation. This will not suppress * the optimisation on encountering calls to functions * whose names begin with underscore or via a function * variable. */ if ((ep0->nodetype == en_nacon) && (ep0->v.str == alloca_name)) { g_stack (stack_offset); } break; default: CANNOT_REACH_HERE (); break; } } /* push any used registers */ temp_inv (); for (reg = EAX; reg <= EBP; reg++) { if (regsave_option & MEMBER (reg)) { g_code (op_push, IL2, mk_reg (reg), NIL_ADDRESS); } } size = g_parms (ep->v.p[1]); /* generate parameters */ /* * for functions returning a structure or a union, push a pointer to the * return value as additional argument The scratch space will be * allocated in the stack frame of the calling function. */ if (is_structure_type (ep->etp)) { ap = mk_scratch (ep->etp->size); ap1 = address_register (); g_code (op_lea, IL2, ap, ap1); g_code (op_push, IL2, ap1, NIL_ADDRESS); freeop (ap1); freeop (ap); size += tp_pointer->size; } if (ep->nodetype == en_call) { size = 0L; } /* call the function */ switch (ep0->nodetype) { case en_nacon: case en_labcon: ap = mk_direct (ep0); break; default: ap = g_expr (ep0, F_AREG); ap = copy_addr (ap, am_ind); ap->u.offset = NIL_EXPR; freeop (ap); break; } g_code (op_call, IL0, ap, NIL_ADDRESS); for (reg = EBP + 1; reg > EAX; reg--) { if (regsave_option & MEMBER ((int) reg - 1)) { g_stack (size); size = 0L; g_code (op_pop, IL2, mk_reg ((REG) ((int) reg - 1)), NIL_ADDRESS); } } ap = func_result (flags, size, ep->etp); return mk_legal (ap, flags, ep->etp);}/* * generates code for a en_cast node */static ADDRESS *g_cast P4 (ADDRESS *, ap, TYP *, tp1, TYP *, tp2, FLAGS, flags){ ADDRESS *ap1; if (flags & F_NOVALUE) { freeop (ap); return NIL_ADDRESS; } /* * Casts to a narrower integer type are no-ops since the 8086 is * low-endian to avoid code duplication, float/double is shared */ switch (tp2->type) { /* type to cast to */#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: switch (tp1->type) { case bt_float: if (tp2->type != bt_float && ap->mode == am_freg) { /* * A double or long double value which is in the FP * registers must be stored and then reloaded in order * to correctly round the bits of a float. Although * this looks like a NULL operation is isn't! */ ap1 = mk_scratch (tp_float->size); g_fcode (op_fstp, IL4, ap1, NIL_ADDRESS); g_fcode (op_fld, IL4, ap1, NIL_ADDRESS); freeop (ap1); } /*FALLTHRU */ case bt_double: ap = mk_legal (ap, F_FREG, tp1); return mk_legal (ap, flags, tp2); case bt_uchar: case bt_schar: case bt_char: case bt_charu: ap = g_cast (ap, tp1, tp_short, F_ALL); /*FALLTHRU */ case bt_short: case bt_int16: /* * For the conversion signed short --> float/double, there is * a 8087 instruction */ switch (ap->mode) { default: /* * FPU-code for a signed short that is in a register: * the value is written to the stack and loaded from * there since there is no direct path between CPU * and FPU registers. */ ap1 = mk_scratch (2L); g_code (op_mov, IL2, ap, ap1); g_fcode (op_fild, IL2, ap1, NIL_ADDRESS); freeop (ap1); break; case am_direct: case am_indx: case am_indx2: g_fcode (op_fild, IL2, ap, NIL_ADDRESS); break; } freeop (ap); ap = float_register (); return mk_legal (ap, flags, tp2); case bt_pointer16: case bt_ushort: case bt_uint16: ap = g_cast (ap, tp1, tp_long, F_ALL); /*FALLTHRU */ case bt_int32: case bt_long: /* * For the conversion signed long --> float/double, there is * a 8087 instruction */ switch (ap->mode) { default: /* * FPU-code for a signed short that is in a register: * the value is written to and stack and loaded from * there since there is no direct path between CPU * and FPU registers. */ ap1 = mk_scratch (4L); g_code (op_mov, IL2, mk_low (ap), mk_low (ap1)); g_code (op_mov, IL2, mk_high (ap), mk_high (ap1)); g_fcode (op_fild, IL4, ap1, NIL_ADDRESS); freeop (ap1); break; case am_direct: case am_indx: case am_indx2: g_fcode (op_fild, IL4, ap, NIL_ADDRESS); break; } freeop (ap); ap = float_register (); return mk_legal (ap, flags, tp2); case bt_uint32: case bt_ulong: case bt_pointer32: ap = mk_legal (ap, F_DREG, tp1); ap1 = mk_scratch (8L); g_code (op_mov, IL2, mk_offset (ap1, 6L), mk_immed (0L)); g_code (op_mov, IL2, mk_offset (ap1, 4L), mk_immed (0L)); g_code (op_mov, IL2, mk_high (ap1), mk_high (ap)); g_code (op_mov, IL2, mk_low (ap1), mk_low (ap)); g_fcode (op_fild, IL4, ap1, NIL_ADDRESS); freeop (ap1); freeop (ap); ap = float_register (); return mk_legal (ap, flags, tp2); default: break; } break;#endif /* FLOAT_IEEE */ case bt_uchar: case bt_schar: case bt_char: case bt_charu: flags = (FLAGS) (flags | F_NOEDI); switch (tp1->type) { case bt_uchar: case bt_schar: case bt_char: case bt_charu: case bt_ushort: case bt_short: case bt_int16: case bt_uint16: case bt_pointer16: return mk_legal (ap, flags, tp2); case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: if (ap->mode == am_mreg) { freeop (ap); ap1 = data_register (); g_code (op_mov, IL1, mk_low (ap), ap1); ap = ap1; } return mk_legal (ap, flags, tp2);#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = mk_legal (ap, F_FREG, tp1); freeop (ap); ap = data_register (); ap1 = mk_scratch (2L); g_fcode (op_fistp, IL2, ap1, NIL_ADDRESS); g_fcode (op_fwait, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_mov, IL2, ap1, ap); freeop (ap1); return mk_legal (ap, flags, tp2);#endif /* FLOAT_IEEE */ default: break; } break; case bt_short: case bt_int16: switch (tp1->type) { case bt_charu: case bt_uchar: case bt_char: case bt_schar: ap = g_extend (ap, tp1, tp2); return mk_legal (ap, flags, tp2); case bt_short: case bt_ushort: case bt_int16: case bt_uint16: case bt_pointer16: return mk_legal (ap, flags, tp2); case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: ap1 = mk_legal (ap, flags, tp2); freeop (ap1); ap = data_register (); g_code (op_mov, IL2, mk_low (ap1), ap); return mk_legal (ap, flags, tp2);#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = mk_legal (ap, F_FREG, tp1); freeop (ap); ap = data_register (); ap1 = mk_scratch (2L); g_fcode (op_fistp, IL2, ap1, NIL_ADDRESS); g_fcode (op_fwait, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_mov, IL2, ap1, ap); freeop (ap1); return mk_legal (ap, flags, tp2);#endif /* FLOAT_IEEE */ default: break; } break; case bt_ushort: case bt_uint16: case bt_pointer16: switch (tp1->type) { case bt_charu: case bt_uchar: case bt_char: case bt_schar: ap = g_extend (ap, tp1, tp2); return mk_legal (ap, flags, tp2); case bt_short: case bt_ushort: case bt_int16: case bt_uint16: case bt_pointer16: return mk_legal (ap, flags, tp2); case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: ap1 = mk_legal (ap, flags, tp2); freeop (ap1); ap = data_register (); g_code (op_mov, IL2, ap, mk_low (ap1)); return mk_legal (ap, flags, tp2);#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = mk_legal (ap, F_FREG, tp1); freeop (ap); ap = data_register (); ap1 = mk_scratch (2L); g_fcode (op_fistp, IL2, ap1, NIL_ADDRESS); g_fcode (op_fwait, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_mov, IL2, ap1, ap); freeop (ap1); return mk_legal (ap, flags, tp2);#endif /* FLOAT_IEEE */ default: break; } break; case bt_int32: case bt_long: switch (tp1->type) { case bt_charu: case bt_uchar: case bt_char: case bt_schar: case bt_short: case bt_ushort: case bt_int16: case bt_uint16: case bt_pointer16: ap = g_extend (ap, tp1, tp2); return mk_legal (ap, flags, tp2); case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: return mk_legal (ap, flags, tp2);#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = mk_legal (ap, F_FREG, tp1); freeop (ap); ap = mdata_register (); ap1 = mk_scratch (4L); g_fcode (op_fistp, IL4, ap1, NIL_ADDRESS); g_fcode (op_fwait, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_mov, IL2, mk_low (ap1), mk_low (ap)); g_code (op_mov, IL2, mk_high (ap1), mk_high (ap)); freeop (ap1); return mk_legal (ap, flags, tp2);#endif /* FLOAT_IEEE */ default: break; } break; case bt_uint32: case bt_ulong: case bt_pointer32: switch (tp1->type) { case bt_charu: case bt_uchar: case bt_char: case bt_schar: case bt_short: case bt_ushort: case bt_int16: case bt_uint16: case bt_pointer16: ap = g_extend (ap, tp1, tp2); return mk_legal (ap, flags, tp2); case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: return mk_legal (ap, flags, tp2);#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = mk_legal (ap, F_FREG, tp1); freeop (ap); ap = mdata_register (); ap1 = mk_scratch (8L); g_fcode (op_fistp, IL8, ap1, NIL_ADDRESS); g_fcode (op_fwait, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_mov, IL2, mk_low (ap1), mk_low (ap)); g_code (op_mov, IL2, mk_high (ap1), mk_high (ap)); freeop (ap1); return mk_legal (ap, flags, tp2);#endif /* FLOAT_IEEE */ default: break; } default: break; } FATAL ((__FILE__, "g_cast", "type1=%d, type2=%d", tp1->type, tp2->type)); return NIL_ADDRESS;}/* * generate code to do a comparison of the two operands of node. */static void g_compare P4 (const EXPR *, ep, OPCODE, opu, OPCODE, ops, LABEL, label1){ EXPR *ep0 = ep->v.p[0]; EXPR *ep1 = ep->v.p[1]; ADDRESS *ap1, *ap2; FLAGS flagx; LABEL label2; OPCODE op1, op2, op3, op4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -