📄 gen68k.c
字号:
break; case 12L: g_move8 (ap, ap2); break; default: CANNOT_REACH_HERE (); break; } return ap2; } FATAL ((__FILE__, "mk_legal", ""));
return NIL_ADDRESS; /*lint !e527*/ /* unreachable */}/* * If ap is an immediate value between -128 and 127 and the size of the * operation is 4 bytes then load the value into a data register if * there is one free. */static ADDRESS *mk_quick P2 (ADDRESS *, ap, const TYP *, tp){ if (tp->size == 4L && is_free_data () && ap->mode == am_immed && is_byte (ap->u.offset)) { ap = mk_legal (ap, F_DREG, tp); } return ap;}/* * If ap is an immediate value between -128 and 127, excluding the values * 1 to 8, and the size of the operation is 4 bytes then load the value into * a data register if there is one free. * This is used for "quick" operations to the "add" and "sub" commands * which aren't covered by the addq and subq instructions. * Don't "quick"en the value 0 as this is best left for the peephole * optimiser as it can then generally remove the instruction. */static ADDRESS *mk_quick2 P2 (ADDRESS *, ap, const TYP *, tp){ if (ap->mode == am_immed && is_icon (ap->u.offset) && (ap->u.offset->v.i < 0L || ap->u.offset->v.i > 8L)) { ap = mk_quick (ap, tp); } return ap;}/* * add a compiler generated label to the peep list. */PRIVATE void g_label P1 (LABEL, labno){ sync_stack (); g_code (op_label, IL0, mk_label (labno), NIL_ADDRESS);}#ifdef DEBUGOPT/* * add a source line number to the peep list. */PRIVATE void g_line P2 (LINE, line, const CHAR *, linetxt){ g_code (op_line, IL0, mk_line (line), mk_linetxt (linetxt));}#endif /*DEBUGOPT *//* * add a conditional branch instruction to the peep list. */static void g_cbranch P2 (OPCODE, op, LABEL, labno){ sync_stack (); g_code (op, IL0, mk_label (labno), NIL_ADDRESS);}/* * add a branch instruction to the peep list. */PRIVATE void g_branch P1 (LABEL, labno){ g_cbranch (op_bra, labno);}/* * adjust the stack by "bytes" bytes. */PRIVATE void g_stack P1 (SIZE, bytes){ if (bytes != 0L) { /* adjust stack pointer */ g_add (IL4, mk_immed ((IVAL) bytes), mk_reg (STACKPTR)); stack_offset -= bytes; if (max_stack_adjust < bytes) { max_stack_adjust = bytes; } }}/* * Generate an instruction which takes an immediate option with optimal * (for space) instruction(s). */static void g_immed P4 (OPCODE, op, const TYP *, tp, IVAL, i, ADDRESS *, ap){ ADDRESS *ap1 = mk_immed (i); ap1 = mk_quick (ap1, tp); g_code (op, (ILEN) tp->size, ap1, ap); freeop (ap1);}static void g_immed2 P4 (OPCODE, op, const TYP *, tp, IVAL, i, ADDRESS *, ap){ ADDRESS *ap1 = mk_immed (i); ap1 = mk_quick2 (ap1, tp); g_code (op, (ILEN) tp->size, ap1, ap); freeop (ap1);}static ADDRESS *g_extend P3 (ADDRESS *, ap, const TYP *, tp1, const TYP *, tp2){ if (ap->mode == am_immed) { return ap; } switch (tp2->type) { case bt_int16: case bt_uint16: case bt_short: case bt_ushort: switch (tp1->type) { case bt_char: case bt_schar: ap = mk_legal (ap, F_DREG, tp1); g_code (op_ext, IL2, ap, NIL_ADDRESS); break; case bt_bool: case bt_uchar: case bt_charu: g_code (op_and, IL2, mk_immed ((IVAL) 255L), ap);
break; default: break; } break; case bt_int32: case bt_uint32: case bt_long: case bt_ulong: case bt_pointer32: switch (tp1->type) { case bt_char: case bt_schar: ap = mk_legal (ap, F_DREG, tp1); if (target_option >= target_coldfire) { g_code (op_extb, IL4, ap, NIL_ADDRESS); } else { g_code (op_ext, IL2, ap, NIL_ADDRESS); g_code (op_ext, IL4, ap, NIL_ADDRESS); } break; case bt_int16: case bt_short: ap = mk_legal (ap, F_DREG, tp1); g_code (op_ext, IL4, ap, NIL_ADDRESS); break; case bt_bool: case bt_uchar: case bt_charu: g_code (op_and, IL4, mk_immed ((IVAL) 255L), ap); break; case bt_uint16: case bt_ushort: g_code (op_and, IL4, mk_immed ((IVAL) 65535L), ap); break; default: break; } break;#ifdef LONGLONG_SUPPORT case bt_longlong: case bt_ulonglong: switch (tp1->type) { ADDRESS *ap1; case bt_char: case bt_schar: ap = mk_legal (ap, F_DREG | F_AREG | F_MEM, tp1); freeop (ap); ap1 = mdata_register (); g_code (op_move, IL1, ap, mk_high (ap1)); if (target_option >= target_coldfire) { g_code (op_extb, IL4, mk_high (ap1), NIL_ADDRESS); } else { g_code (op_ext, IL2, mk_high (ap1), NIL_ADDRESS); g_code (op_ext, IL4, mk_high (ap1), NIL_ADDRESS); } g_code (op_slt, IL0, mk_low (ap1), NIL_ADDRESS); VOIDCAST g_extend (mk_low (ap1), tp_schar, tp_long); ap = ap1; break; case bt_bool: case bt_uchar: case bt_charu: ap = mk_legal (ap, F_DREG | F_AREG | F_MEM, tp1); freeop (ap); ap1 = mdata_register (); g_code (op_move, IL1, ap, mk_high (ap1)); g_code (op_and, IL4, mk_immed ((IVAL) 255L), mk_high (ap1)); g_code (op_clr, IL4, mk_low (ap1), NIL_ADDRESS); ap = ap1; break; case bt_int16: case bt_short: ap = mk_legal (ap, F_DREG | F_AREG | F_MEM, tp1); freeop (ap); ap1 = mdata_register (); g_code (op_move, IL2, ap, mk_high (ap1)); g_code (op_ext, IL4, mk_high (ap1), NIL_ADDRESS); g_code (op_slt, IL0, mk_low (ap1), NIL_ADDRESS); VOIDCAST g_extend (mk_low (ap1), tp_schar, tp_long); ap = ap1; break; case bt_uint16: case bt_ushort: ap = mk_legal (ap, F_DREG | F_AREG | F_MEM, tp1); freeop (ap); ap1 = mdata_register (); g_code (op_move, IL2, ap, mk_high (ap1)); g_code (op_and, IL4, mk_immed ((IVAL) 65535L), mk_high (ap)); g_code (op_clr, IL4, mk_low (ap1), NIL_ADDRESS); ap = ap1; break; case bt_int32: case bt_long: ap = mk_legal (ap, F_DREG | F_AREG | F_MEM, tp1); freeop (ap); ap1 = mdata_register (); g_code (op_move, IL4, ap, mk_high (ap1)); g_code (op_slt, IL0, mk_low (ap1), NIL_ADDRESS); VOIDCAST g_extend (mk_low (ap1), tp_schar, tp_long); ap = ap1; break; case bt_uint32: case bt_ulong: ap = mk_legal (ap, F_DREG, tp1); freeop (ap); ap1 = mdata_register (); g_code (op_move, IL4, ap, mk_high (ap1)); g_code (op_clr, IL4, mk_low (ap1), NIL_ADDRESS); ap = ap1; break; default: break; } break;#endif /* LONGLONG_SUPPORT */ default: CANNOT_REACH_HERE (); break; } return ap;}static ADDRESS *mk_low P1 (ADDRESS *, ap){ switch (ap->mode) { case am_immed: if (is_icon (ap->u.offset)) { EXPR *ep = ap->u.offset; if (is_signed_type (ep->etp)) { IVAL i = ep->v.i;#ifdef LONGLONG i >>= 32;#else if (ep->v.i < 0) { i = (IVAL) -1; } else { i = 0; }#endif /* LONGLONG */ return mk_immed (i); } else { UVAL u = ep->v.u;#ifdef LONGLONG u >>= 32;#else u = 0;#endif /* LONGLONG */ return mk_immed ((IVAL) u); } } break; case am_ainc: case am_adec: case am_freg: return ap; case am_mreg: case am_xreg: return mk_reg (ap->preg); case am_ind: case am_indx: case am_indx2: case am_indx3: case am_indx4: case am_direct: return mk_offset (ap, 0L); default: FATAL ((__FILE__, "mk_low", "illegal mode %d", ap->mode)); break; } return NIL_ADDRESS;}static ADDRESS *mk_high P1 (ADDRESS *, ap){ switch (ap->mode) { case am_immed: if (is_icon (ap->u.offset)) {#ifdef LONGLONG return mk_immed ((IVAL) (ap->u.offset->v.u & 0xFFFFFFFFUL));#else return mk_immed (ap->u.offset->v.i);#endif } break; case am_dreg: case am_areg: case am_ainc: case am_adec: return ap; case am_mreg: case am_xreg: return mk_reg (ap->sreg); case am_ind: case am_indx: case am_indx2: case am_indx3: case am_indx4: case am_direct: return mk_offset (ap, 4L); default: FATAL ((__FILE__, "mk_high", "illegal mode %d", ap->mode)); break; } return NIL_ADDRESS;}static ADDRESS *mk_top P1 (ADDRESS *, ap){ switch (ap->mode) { case am_ainc: case am_adec: return ap; case am_xreg: return mk_reg (ap->u.xreg); case am_ind: case am_indx: case am_indx2: case am_indx3: case am_indx4: case am_direct: return mk_offset (ap, 8L); default: FATAL ((__FILE__, "mk_top", "illegal mode %d", ap->mode)); break; }
return NIL_ADDRESS; /*lint !e527*/ /* unreachable */}/* * return ap, if ap can be switched to address a location with a short * offset, otherwise return 0. Typical application: * cast long -> short: 8(a6) --> 10(a6) offset is a small number (1,2 or 3) */static ADDRESS *mk_offset P2 (ADDRESS *, ap, SIZE, off){ switch (ap->mode) { case am_ind: if (off) { ap = copy_addr (ap, am_indx); ap->u.offset = mk_const ((IVAL) off); } return ap; case am_indx: if (is_icon (ap->u.offset) && ((IVAL) off + ap->u.offset->v.i <= (IVAL) 32767L)) { ap = copy_addr (ap, ap->mode); ap->u.offset = mk_const (ap->u.offset->v.i + (IVAL) off); return ap; } break; case am_indx2: case am_indx3: case am_indx4: if (is_icon (ap->u.offset) && ((IVAL) off + ap->u.offset->v.i <= (IVAL) 127L || target_option < target_68020)) { ap = copy_addr (ap, ap->mode); ap->u.offset = mk_const (ap->u.offset->v.i + (IVAL) off); return ap; } break; case am_direct: ap = copy_addr (ap, ap->mode); ap->u.offset = mk_add (ap->u.offset, mk_const ((IVAL) off)); return ap; default: break; } /* special value indicating that it must be done by hand */ return NIL_ADDRESS;}/* * generate code to evaluate an index node and return the addressing * mode of the result. */static ADDRESS *g_index P1 (const EXPR *, ep){ ADDRESS *ap1, *ap2; EXPR *ep0 = ep->v.p[0]; EXPR *ep1 = ep->v.p[1]; /* * Try and ensure that we evaluate address registers first ... * this leads to better code */ if (ep1->nodetype == en_register && is_address_register (ep1->v.r)) { ep0 = ep->v.p[1]; ep1 = ep->v.p[0]; } if (ep1->nodetype == en_register && ep0->nodetype == en_register) { if (is_address_register (ep0->v.r)) { /* first node is address register */ ap1 = g_expr (ep0, F_AREG); ap1 = copy_addr (ap1, am_none); ap2 = g_expr (ep1, (FLAGS) (F_AREG | F_DREG)); if (ap2->mode == am_dreg) { /* 0(Ax,Dx) */ ap1->mode = am_indx2; } else { /* 0(Ax,Ay) */ ap1->mode = am_indx3; } ap1->sreg = ap2->preg; ap1->u.offset = mk_const ((IVAL) 0L); return ap1; } else if (is_address_register (ep1->v.r)) { /* second node is address register */ ap1 = g_expr (ep1, F_AREG); ap1 = copy_addr (ap1, am_indx2); /* 0(Ax,Dx) */ ap1->sreg = ep0->v.r; ap1->u.offset = mk_const ((IVAL) 0L); return ap1; } } /* * The general case (no register) */ ap1 = g_expr (ep0, (FLAGS) (F_AREG | F_IMMED)); 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 (); } /* * possible combinations: * * F_AREG + F_AREG * F_AREG + F_DREG * F_AREG + F_IMMED * F_IMMED + F_IMMED * F_IMMED + F_AREG */ if (ap1->mode == am_areg) { /* * watch out for: * register(addr) + address_register * register(addr) + data_register */ if (!is_temporary_register (ap1->preg)) { /* ap1 = register variable address register */ ap1 = copy_addr (ap1, ap1->mode); switch (ap2->mode) { case am_dreg: /* 0(Ax,Dy) */ ap1->mode = am_indx2; ap1->sreg = ap2->preg; ap1->deep = ap2->deep; ap1->u.offset = mk_const ((IVAL) 0L); return ap1; case am_areg: /* 0(Ax,Ay) */ ap1->mode = am_indx3; ap1->sreg = ap2->preg; ap1->deep = ap2->deep; ap1->u.offset = mk_const ((IVAL) 0L); return ap1; case am_immed: if (!is_short (ap2->u.offset)) { /* we want to add to ap1 later... */ ap1 = mk_legal (ap1, (FLAGS) (F_AREG | F_VOL), tp_pointer); } break; default: break; } } /* * watch out for: * address_register + register(data) */ if (ap2->mode == am_dreg && !is_temporary_data_register (ap2->preg)) { ap1 = copy_addr (ap1, am_indx2); ap1->sreg = ap2->preg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -