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 + -
显示快捷键?