peep68k.c
来自「一款拥有一定历史的C语言编译器」· C语言 代码 · 共 2,521 行 · 第 1/4 页
C
2,521 行
(ip2->oper1->u.offset->v.u << 16); peep_delete (ip2); return; } /* * The M68000 reads the operand to be cleared. * This is unsafe e.g. when manipulating interface * registers, and clr is not too fast for this reason * (although it is a considerable smaller instruction). * We will therefore only do this optimisation on the * M68000 if volatile is not set. * * M68010, M68020 etc. do not have this bug so always * replace move immediate of zero by a CLR instruction. * * N. B. The special case of moving zero to a register * will already have been optimised to MOVEQ or SUBA. */ if (target_option >= target_68000 || !volatile_found) { if (ep->v.i == 0L) { ip->opcode = op_clr; ip->oper1 = ip->oper2; ip->oper2 = NIL_ADDRESS; changes++; return; } } } /*lint -fallthrough */ case am_dreg: case am_areg: case am_freg: case am_direct: switch (ip->oper2->mode) { case am_dreg: if (is_flag_used (ip)) { break; /* sets the flags so cannot be deleted */ } /*lint -fallthrough */ case am_areg: case am_freg: if (was_move_redundant (ip, ip, FALSE) || is_move_redundant (ip, ip, FALSE)) { peep_delete (ip); return; } break; default: break; } break; case am_ind: case am_indx: switch (ip->oper2->mode) { case am_areg: if (ip->oper1->preg == ip->oper2->preg) { break; } if (was_move_redundant (ip, ip, TRUE) || is_move_redundant (ip, ip, TRUE)) { peep_delete (ip); return; } break; case am_dreg: if (is_flag_used (ip)) { break; /* sets the flags so cannot be deleted */ } /*lint -fallthrough */ case am_freg: if (was_move_redundant (ip, ip, TRUE) || is_move_redundant (ip, ip, TRUE)) { peep_delete (ip); return; } break; default: break; } break; default: break; }}static void peep_moveq P1 (CODE *, ip){ if (was_move_redundant (ip, ip, TRUE)) { peep_delete (ip); return; }}/* * peephole optimization for (f)movem instructions. * (f)movem instructions are used to save registers on the stack. * if only one register is being saved we can convert the (f)movem to a * (f)move instruction. * */static void peep_movem P1 (CODE *, ip){ REG reg; ADDRESS *ap = (ip->oper1->mode == am_smask) ? ip->oper1 : ip->oper2; for (reg = FP7; reg >= D0; reg--) { if (ap->u.mask == REGBIT (reg)) { switch (reg) { case D0: case D1: case D2: case D3: case D4: case D5: case D6: case D7: ap->mode = am_dreg; ip->opcode = op_move; break; case A0: case A1: case A2: case A3: case A4: case A5: case A6: case A7: ap->mode = am_areg; if (ip->oper2->mode == am_rmask) { ip->opcode = op_movea; } else { ip->opcode = op_move; } break;#ifdef FLOAT_IEEE case FP0: case FP1: case FP2: case FP3: case FP4: case FP5: case FP6: case FP7: ap->mode = am_freg; ip->opcode = op_fmove; break;#endif /* FLOAT_IEEE */ default: CANNOT_REACH_HERE (); } ap->preg = reg; changes++; return; } } if (was_move_redundant (ip, ip, TRUE)) { peep_delete (ip); }}/* * peephole optimization for add instructions. * makes quick immediates out of small constants (redundant for most as's). * change add immediate to address registers to lea where possible */static void peep_add P1 (CODE *, ip){ EXPR *ep; CODE *next; if (ip->oper1->mode != am_immed) { return; } ep = ip->oper1->u.offset; if (ip->oper2->mode == am_areg) { if (ip->oper2->preg == STACKPTR && is_dest_overwritten (ip->oper2, ip)) { peep_delete (ip); return; } /* adda.w extents the first argument automatically */#ifdef COLDFIRE if (is_short (ep) && !is_coldfire ()) { ip->length = IL2; }#else if (is_short (ep)) { ip->length = IL2; }#endif /* COLDFIRE */ } else { ip->opcode = op_addi; } if (ep->nodetype != en_icon) { return; } if (ep->v.i == 0L) { if (ip->oper2->mode == am_areg) { /* * ADD #0, An redundant */ peep_delete (ip); } else { /* * ADD #0, <ea> => TST <ea> */ ip->oper1 = ip->oper2; ip->oper2 = NIL_ADDRESS; ip->opcode = op_tst; changes++; } return; } if ((IVAL) 1 <= ep->v.i && ep->v.i <= (IVAL) 8) { next = ip->fwd; if (ip->oper2->mode == am_areg && next && next->opcode == op_move && next->length == (ILEN) ep->v.i && next->oper2->mode == am_adec && next->oper2->preg == ip->oper2->preg && !is_address_used (ip->oper2, next->oper1)) { /* * The sequence: * ADD.W #4, A7 * MOVE.L <ea>, -(A7) * becomes * MOVE.L <ea>, (A7) */ next->oper2 = copy_addr (next->oper2, am_ind); peep_delete (ip); } else { ip->opcode = op_addq; } return; } if ((IVAL) -8 <= ep->v.i && ep->v.i <= (IVAL) -1) { /* * ADD #-n, <ea> => SUB #n, <ea> * * where 1 <= n <= 8 */ ep->v.i = -ep->v.i; ip->opcode = op_subq; changes++; return; } if (ip->oper2->mode == am_areg && is_short (ep)) { /* * ADDA.W #X, An => LEA X(An), An * * they are the same size, but the lea version is quicker */ ip->oper1 = copy_addr (ip->oper1, am_indx); ip->oper1->preg = ip->oper2->preg; ip->length = IL0; ip->opcode = op_lea; changes++; return; }}/* * conversion of unsigned data types often yields statements like * move.b source,d0 + andi.l #255,d0 * which should be converted to * clr.l d0 + move.b source,d0 * deletes and #-1 */static void peep_and P1 (CODE *, ip){ CODE *prev; ILEN size; IVAL val; if (ip->oper1->mode != am_immed || ip->oper1->u.offset->nodetype != en_icon) { return; } val = ip->oper1->u.offset->v.i; if (val == -1L) { /* * AND #-1, <ea> * * only sets flags, which the code generator does not know */ peep_delete (ip); return; } if ((prev = ip->back) == NIL_CODE) { return; } if (prev->opcode == op_and && prev->oper1->mode == am_immed && is_icon (prev->oper1->u.offset) && is_equal_address (ip->oper2, prev->oper2)) { /* * AND #M, <ea> => AND #(M&N), <ea> * AND #N, <ea> */ prev->oper1->u.offset->v.i &= val; if (prev->length < ip->length) { prev->length = ip->length; } peep_delete (ip); return; } /* * MOVE <ea>, <EA> => CLR <EA> * AND #N, <EA> MOVE <ea>, <EA> * * where N is 255 for byte instructions and 65535 for word * instructions. Also Dn is not used in the addressing mode * for <ea>. */ if (val == 255L) { size = IL1; } else if (val == 65535L) { size = IL2; } else { return; } if (prev->opcode != op_move || prev->length != size || !is_equal_address (ip->oper2, prev->oper2) || is_address_used (ip->oper2, prev->oper1)) { return; } prev->length = ip->length; ip->opcode = op_move; ip->oper1 = prev->oper1; ip->length = size; prev->opcode = op_clr; prev->oper1 = prev->oper2; prev->oper2 = NIL_ADDRESS; next_ip = prev;}static void peep_or P1 (const CODE *, ip){ CODE *prev; IVAL val; if (ip->oper1->mode != am_immed) { return; } val = ip->oper1->u.offset->v.i; if (val == 0L) { /* * OR #0, <ea> */ peep_delete (ip); return; } if ((prev = ip->back) == NIL_CODE) { return; } if (prev->opcode == op_or && prev->oper1->mode == am_immed && is_icon (prev->oper1->u.offset) && is_equal_address (ip->oper2, prev->oper2)) { /* * OR #M, <ea> => OR #(M|N), <ea> * OR #N, <ea> */ prev->oper1->u.offset->v.i |= val; if (prev->length < ip->length) { prev->length = ip->length; } peep_delete (ip); return; }}/* * removes consecutive clr-statements * */static void peep_clr P1 (const CODE *, ip){ CODE *prev; if ((prev = ip->back) == NIL_CODE || prev->opcode != op_clr || !is_equal_address (ip->oper1, prev->oper1)) return; if (prev->length < ip->length) { prev->length = ip->length; } peep_delete (ip);}/* * peephole optimization for subtract instructions. * makes quick immediates out of small constants (redundant for most as's). */static void peep_sub P1 (CODE *, ip){ EXPR *ep; if (ip->oper1->mode != am_immed) { return; } ep = ip->oper1->u.offset; if (ip->oper2->mode == am_areg) { /* * SUBA.W extents the first argument automatically */#ifdef COLDFIRE if (is_short (ep) && !is_coldfire ()) { ip->length = IL2; }#else if (is_short (ep)) { ip->length = IL2; }#endif /* COLDFIRE */ } else { ip->opcode = op_subi; } if (ep->nodetype != en_icon) { return; } if (ep->v.i == 0L) { if (ip->oper2->mode == am_areg) { /* * SUB #0, An redundant */ peep_delete (ip); } else { /* * SUB #0, <ea> => TST <ea> * * provide <ea> != An */ ip->oper1 = ip->oper2; ip->oper2 = NIL_ADDRESS; ip->opcode = op_tst; changes++; return; } } if ((IVAL) 1 <= ep->v.i && ep->v.i <= (IVAL) 8) { ip->opcode = op_subq; return; } else if ((IVAL) -8 <= ep->v.i && ep->v.i <= (IVAL) -1) { /* * SUB #-n, <ea> => ADD #n, <ea> * * where 1<= n <= 8 */ ep->v.i = -ep->v.i; ip->opcode = op_addq; changes++; return; }}/* * peephole optimization for compare instructions. * changes compare #0 to tst */static void peep_cmp P1 (CODE *, ip){ EXPR *ep; if (ip->oper1->mode != am_immed) { return; } ep = ip->oper1->u.offset; if (ip->oper2->mode == am_areg) { /* * CMPA.W extents the first argument automatically */ if (is_short (ep)) { ip->length = IL2; } return; } ip->opcode = op_cmpi; if (is_icon (ep) && ep->v.i == 0L) { /* * CMP #0, <ea> => TST <ea> */ ip->oper1 = ip->oper2; ip->oper2 = NIL_ADDRESS; ip->opcode = op_tst; next_ip = ip; return; }}/* * deletes a tst instruction if the flags are already set. */static void peep_tst P1 (const CODE *, ip){ CODE *prev; prev = ip->back; if (prev == NIL_CODE) { return; } switch (prev->opcode) { case op_label: /* * List all pseudo-instructions here. Of course, they do not do * anything. */ case op_line:#ifdef ASM case op_asm:#endif /* ASM */ return; case op_add: case op_addi: case op_addq: case op_adda: case op_addx: case op_sub: case op_subi: case op_subq: case op_suba: case op_subx: case op_asl: case op_asr: case op_neg: case op_negx: /* * These instructions can set the carry and overflow flags which a * tst instruction always clears. */ return; case op_mulu: case op_muls: /* * These instructions set flags on full 32 bit register. */ if (prev->length < IL4) { return; } break; case op_movea: /* * A move TO an address register does not set the flags */ return; case op_move: case op_moveq: case op_clr: /* * All other MOVE and CLR instructions set the flags according to * the moved operand, which is prev->oper1 */ if (is_equal_address (prev->oper1, ip->oper1)) { break; } /*lint -fallthrough */ default: /* * If instructions have different length then the flags will not be * set correctly. */ if (prev->length != ip->length) { return; } /* * All instructions that have a target set the flags according to the * target (prev->oper2) * Note that is_equal_address may be called with a NIL pointer */ if (is_equal_address (prev->oper2 ? prev->oper2 : prev->oper1, ip->oper1)) {break; } return; } /* * We come here if the flags are already set, thus the tst * instruction can be deleted. */ peep_delete (ip);}/* * peephole optimization for unconditional transfers. deletes instructions * which have no path. applies to bra, jmp, and rts instructions. */static void peep_uctran P1 (const CODE *, ip){
if (ip) { while (ip->fwd != NIL_CODE && ip->fwd->opcode != op_label) { peep_delete (ip->fwd);
}
}}/* * optimizes conditional branch over a bra. */static void peep_bxx P1 (const CODE *, ip){ CODE *p;
LABEL label = ip->oper1->u.offset->v.l;
#if 0 CODE *target; LABEL label = ip->oper1->u.offset->v.l;#endif static OPCODE revcond[] = { op_bne, op_beq, op_bge, op_bgt, op_ble, op_blt, op_bls, op_blo, op_bhs, op_bhi }; CODE *next = ip->fwd; if (next == NIL_CODE) { return; } if (next->opcode == op_bra) { /* peep_uctran increases the 'hit' probability */ peep_uctran (next); next = next->fwd; if (next == NIL_CODE) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?