📄 gen86.c
字号:
case am_immed: if (flags & F_IMMED) { return ap; /* mode ok */ } break; case am_areg: if (flags & F_AREG) { if ((flags & F_VOL) && !is_temporary_register (ap->preg)) { break; } if ((flags & F_NOEDI) && (ap->preg == EDI || ap->preg == ESI)) { break; } return ap; } break; case am_dreg: if (flags & F_DREG) { if ((flags & F_VOL) && !is_temporary_register (ap->preg)) { break; } if ((flags & F_NOEDI) && (ap->preg == EDI || ap->preg == ESI)) { break; } if ((flags & F_NOECX) && (ap->preg == ECX)) { break; } if (flags & F_EAXEDX) { break; } if ((flags & F_ECX) && (ap->preg != ECX)) { break; } return ap; }#ifdef FLOAT_IEEE if (flags & F_FREG) { ap1 = mk_indirect (ESP, mk_const (-2l)); g_code (op_mov, IL2, ap, ap1); g_fcode (op_fild, IL2, ap1, NIL_ADDRESS); freeop (ap); ap = float_register (); return ap; } break; case am_freg: if (flags & F_FREG) { return ap; }#endif /* FLOAT_IEEE */ break; case am_mreg: if (flags & F_DREG) { if ((flags & F_NOEDI) && (ap->preg == EDI || ap->preg == ESI || ap->sreg == EDI || ap->sreg == ESI)) break; if ((flags & F_VOL) && !is_temporary_register (ap->preg) && !is_temporary_register (ap->sreg)) break; return ap; } break; case am_ind: case am_indx: case am_indx2: case am_direct: if (flags & F_MEM) { return ap; } break; default: FATAL ( (__FILE__, "mk_legal", "mode = %d, flags = 0x%x", ap->mode, flags)); } if (flags & F_DREG) { freeop (ap); /* maybe we can reuse it */ if (flags & F_ECX) { ap2 = cx_register (); g_code (op_mov, IL2, ap, ap2); return ap2; } if (flags & F_EAXEDX) { ap2 = axdx_register (); g_code (op_mov, IL2, ap, mk_low (ap2)); return ap2; } switch (size) { case 1L: /* * byte transfers from %edi/%esi to a scratch register come * up here */ if (ap->mode == am_dreg && (ap->preg == ESI || ap->preg == EDI)) { size = 2L; } /*FALLTHRU */ case 2L: ap2 = data_register (); g_code (op_mov, (ILEN) size, ap, ap2); return ap2; case 4L: ap2 = mdata_register (); g_code (op_mov, IL2, mk_low (ap), mk_low (ap2)); g_code (op_mov, IL2, mk_high (ap), mk_high (ap2)); return ap2; default: break; } } if (flags & F_AREG) { freeop (ap); /* maybe we can reuse it */ switch (size) { case 1L: ap2 = address_register (); ap1 = data_register (); g_code (op_mov, (ILEN) size, ap, ap1); ap1 = g_extend (ap1, tp, tp_short); g_code (op_mov, 2L, ap1, ap2); freeop (ap1); return ap2; case 2L: ap2 = address_register (); g_code (op_mov, (ILEN) size, ap, ap2); return ap2; default: break; } }#ifdef FLOAT_IEEE if (flags & F_FREG) { freeop (ap); switch (tp->type) { case bt_float: case bt_double: case bt_longdouble: ap2 = float_register (); g_fcode (op_fld, (ILEN) size, ap, NIL_ADDRESS); return ap2; case bt_char: case bt_schar:/*KDW */ case bt_short: case bt_int16: case bt_long: case bt_int32: ap2 = float_register (); g_fcode (op_fild, (ILEN) size, ap, NIL_ADDRESS); return ap2; default: break; } }#endif /* FLOAT_IEEE */ if (flags & F_MEM) { freeop (ap); ap2 = mk_scratch (tp->size); switch (tp->size) { case 1L: case 2L: switch (ap->mode) {#ifdef FLOAT_IEEE case am_freg: g_fcode (op_fstp, (ILEN) size, ap2, NIL_ADDRESS); break;#endif /* FLOAT_IEEE */ default: g_code (op_mov, (ILEN) size, ap, ap2); break; } break; case 4L: switch (ap->mode) {#ifdef FLOAT_IEEE case am_freg: g_fcode (op_fstp, (ILEN) size, ap2, NIL_ADDRESS); break;#endif /* FLOAT_IEEE */ case am_mreg: g_code (op_mov, IL2, mk_high (ap), mk_high (ap2)); g_code (op_mov, IL2, mk_low (ap), mk_low (ap2)); break; default: g_code (op_mov, (ILEN) size, ap, ap2); } break; case 8L: case 10L: switch (ap->mode) {#ifdef FLOAT_IEEE case am_freg: g_fcode (op_fstp, (ILEN) size, ap2, NIL_ADDRESS); break;#endif /* FLOAT_IEEE */ default: break; } break; default: CANNOT_REACH_HERE (); break; } return ap2; } FATAL ( (__FILE__, "mk_legal", "mode = %d, flags = 0x%x", ap->mode, flags)); return NIL_ADDRESS;}static ADDRESS *g_index P1 (const EXPR *, ep){ ADDRESS *ap1, *ap2; EXPR *ep0 = ep->v.p[0]; EXPR *ep1 = ep->v.p[1]; ap1 = g_expr (ep0, (FLAGS) (F_AREG | F_IMMED | F_VOL)); switch (ap1->mode) { case am_areg: ap2 = g_expr (ep1, F_ALL); validate (ap1); break; case am_immed: ap2 = ap1; ap1 = g_expr (ep1, (FLAGS) (F_AREG | F_IMMED)); validate (ap2); break; default: CANNOT_REACH_HERE (); } switch (ap1->mode) { case am_areg: if (!is_temporary_register (ap1->preg)) { ap1 = copy_addr (ap1, ap1->mode); switch (ap2->mode) { case am_dreg: /* 0(Rn,Rm) */ ap1->mode = am_indx2; ap1->sreg = ap2->preg; ap1->deep = ap2->deep; ap1->u.offset = mk_const (0L); return ap1; default: break; } } break; case am_immed: switch (ap2->mode) { case am_immed: ap1 = copy_addr (ap1, am_direct); ap1->u.offset = mk_add (ap1->u.offset, ap2->u.offset); return ap1; case am_areg: g_code (op_add, IL2, ap1, ap2); ap2 = copy_addr (ap2, am_ind); return ap2; default: CANNOT_REACH_HERE (); } break; default: CANNOT_REACH_HERE (); } freeop (ap2); if (!is_temporary_register (ap1->preg)) { ap1 = mk_legal (ap1, (FLAGS) (F_AREG | F_VOL), tp_pointer); } g_code (op_add, IL2, ap2, ap1); ap1 = copy_addr (ap1, am_ind); return ap1;}/* * rotate a bitfield into the required position (assumes ap is a register) */static void g_rotate P5 (ADDRESS *, ap, ILEN, ilen, int, offset, TYP *, tp, int, width){ OPCODE op; switch (tp->type) { case bt_int16: case bt_int32: /* sign bitfield */ g_code (op_asl, ilen, mk_immed (32L - (IVAL) offset - (IVAL) width), ap); g_code (op_asr, ilen, mk_immed (32L - (IVAL) width), ap); break; default: /* offset is in range -31 .. 31 */ if (offset < 0) { offset += ilen * 8; } /* offset in range 0..31 */ if (offset != 0) { if (offset > 15) { op = op_rol; offset = 32 - offset; } else { op = op_ror; } g_code (op, ilen, mk_immed ((IVAL) offset), ap); } if (tp->type != bt_void) { g_code (op_and, ilen, mk_immed ((IVAL) bitmask ((BITSIZE) width)), ap); } }}/* * 'ap' which has the size of type 'tp1' is to be extended to * be the size of 'tp2'. */static ADDRESS *g_extend P3 (ADDRESS *, ap, TYP *, tp1, TYP *, tp2){ ap = mk_legal (ap, (FLAGS) (F_DREG | F_VOL), tp1); switch (tp2->type) { case bt_int16: case bt_uint16: case bt_short: case bt_ushort: switch (tp1->type) { case bt_char: case bt_schar: if (ap->preg == EAX) { g_code (op_cbw, IL0, NIL_ADDRESS, NIL_ADDRESS); } else { if (target_option >= target_80186) { /* 80186 code */ g_code (op_asl, IL2, mk_immed (8L), mk_low (ap)); g_code (op_asr, IL2, mk_immed (8L), mk_low (ap)); } else { g_code (op_xchg, IL2, mk_low (ap), mk_reg (EAX)); g_code (op_cbw, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_xchg, IL2, mk_reg (EAX), mk_low (ap)); } } break; case bt_uchar: case bt_charu: g_code (op_and, IL2, mk_immed (255L), ap); break; case bt_int16: case bt_uint16: case bt_short: case bt_ushort: break; case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: break; default: CANNOT_REACH_HERE (); break; } break; case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: freeop (ap); ap = mdata_register (); switch (tp1->type) { case bt_char: case bt_schar: if (ap->preg == EAX) { g_code (op_cbw, IL0, NIL_ADDRESS, NIL_ADDRESS); } else { if (target_option >= target_80186) { /* 80186 code */ g_code (op_asl, IL2, mk_immed (8L), mk_low (ap)); g_code (op_asr, IL2, mk_immed (8L), mk_low (ap)); } else { g_code (op_xchg, IL2, mk_low (ap), mk_reg (EAX)); g_code (op_cbw, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_xchg, IL2, mk_reg (EAX), mk_low (ap)); } } /*FALLTHRU */ case bt_int16: case bt_short: if (ap->preg == EAX) { g_code (op_cwd, IL0, NIL_ADDRESS, NIL_ADDRESS); } else { g_code (op_mov, IL2, mk_immed (0L), mk_high (ap)); g_code (op_or, IL2, mk_low (ap), mk_low (ap)); g_code (op_bra, IL0, mk_label (nextlabel), NIL_ADDRESS); g_code (op_not, IL2, mk_high (ap), NIL_ADDRESS); g_label (nextlabel++); } break; case bt_charu: case bt_uchar: if (target_option >= target_80186) { /* 80186 code */ g_code (op_shl, IL2, mk_immed (8L), mk_low (ap)); g_code (op_shr, IL2, mk_immed (8L), mk_low (ap)); } else { g_code (op_and, IL2, mk_immed (0xFF00L), mk_low (ap)); } /*FALLTHRU */ case bt_uint16: case bt_ushort: case bt_pointer16: g_code (op_mov, IL2, mk_immed (0L), mk_high (ap)); break; case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: break; default: CANNOT_REACH_HERE (); break; } break; default: FATAL ( (__FILE__, "g_extend", "type1=%d, type2=%d", tp1->type, tp2->type)); break; } return ap;}/* * return the addressing mode of a dereferenced node. */static ADDRESS *g_deref P2 (const EXPR *, ep, TYP *, tp){ ADDRESS *ap1; /* * If a reference to a structure/union is required, return a * pointer to the struct instead. */ if (is_structure_type (tp) || is_array_assignment (tp)) { return g_expr (ep, F_ALL); } switch (ep->nodetype) { case en_add: return g_index (ep); case en_autocon: return mk_indirect (regframe, mk_const (ep->v.i)); default: ap1 = g_expr (ep, (FLAGS) (F_AREG | F_IMMED)); if (ap1->mode == am_immed) { return copy_addr (ap1, am_direct); } else { return copy_addr (ap1, am_ind); } }}/* * get a bitfield value */static ADDRESS *g_fderef P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap; ap = g_deref (ep->v.p[0], ep->etp); ap = mk_legal (ap, (FLAGS) (F_DREG | F_VOL), ep->etp); g_rotate (ap, (ILEN) ep->etp->size, (int) ep->v.bit.offset, ep->etp, (int) ep->v.bit.width); return mk_legal (ap, flags, ep->etp);}/* * generate code to evaluate a unary minus or complement. */static ADDRESS *g_unary P3 (const EXPR *, ep, FLAGS, flags, OPCODE, op){ ADDRESS *ap; switch (ep->etp->type) { case bt_char: case bt_charu: case bt_uchar: case bt_schar: case bt_short: case bt_ushort: case bt_int16: case bt_uint16: ap = g_expr (ep->v.p[0], (FLAGS) (F_DREG | F_VOL)); g_code (op, (ILEN) ep->etp->size, ap, NIL_ADDRESS); return mk_legal (ap, flags, ep->etp); case bt_int32: case bt_uint32: case bt_long: case bt_ulong: case bt_pointer32: ap = g_expr (ep->v.p[0], (FLAGS) (F_DREG | F_VOL)); switch (op) { case op_neg: g_code (op, IL2, mk_low (ap), NIL_ADDRESS); g_code (op_adc, IL2, mk_immed (0L), mk_high (ap)); g_code (op, IL2, mk_high (ap), NIL_ADDRESS); break; case op_not: g_code (op, IL2, mk_low (ap), NIL_ADDRESS); g_code (op, IL2, mk_high (ap), NIL_ADDRESS); break; default: CANNOT_REACH_HERE (); break; } return mk_legal (ap, flags, ep->etp);#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: ap = g_expr (ep->v.p[0], F_FREG); g_fcode (op_fchs, IL0, NIL_ADDRESS, NIL_ADDRESS); return mk_legal (ap, flags, ep->etp);#endif /* FLOAT_IEEE */ default: FATAL ((__FILE__, "g_unary", "illegal type or operation")); break; } return NIL_ADDRESS;}/* * generate code to evaluate a autoincrement/autodecrement node */static ADDRESS *g_aincdec P3 (const EXPR *, ep, FLAGS, flags, OPCODE, op){ ADDRESS *ap1, *ap2;#ifdef FLOAT_IEEE ILEN ilen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -