peep68k.c

来自「一款拥有一定历史的C语言编译器」· C语言 代码 · 共 2,521 行 · 第 1/4 页

C
2,521
字号
/* * C compiler * ========== * * Copyright 1989, 1990, 1991 Christoph van Wuellen. * Credits to Matthew Brandt. * All commercial rights reserved. * * This compiler may be redistributed as long there is no * commercial interest. The compiler must not be redistributed * without its full sources. This notice must stay intact. * * History: * * 1989   starting an 68000 C compiler, starting with material *		  originally by M. Brandt * 1990   68000 C compiler further bug fixes *		  started i386 port (December) * 1991   i386 port finished (January) *		  further corrections in the front end and in the 68000 *		  code generator. *		  The next port will be a SPARC port *//*****************************************************************************/#include "config.h"#ifdef MC680X0#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"#include "gen68k.h"#include "outproto.h"/********************************************************* Macro Definitions */typedef unsigned OPFLAG;#define DEST_MODIFY ((OPFLAG)0000001)#define DEST_OVERWRITE	((OPFLAG)0000002)#define DEST_ALTERED	(DEST_MODIFY | DEST_OVERWRITE)#define SET_FLAGS	((OPFLAG)0000004)#define USE_FLAGS	((OPFLAG)0000010)#define NOSET_FLAGS ((OPFLAG)0000020)#define USES_A7 	((OPFLAG)0000040)#define FX0 	((OPFLAG)0000100)#define FX1 	((OPFLAG)0000200)#define FX		(FX0|FX1)#define FN0 	((OPFLAG)0000400)#define FN1 	((OPFLAG)0001000)#define FN		(FN0|FN1)#define FZ0 	((OPFLAG)0002000)#define FZ1 	((OPFLAG)0004000)#define FZ		(FZ0|FZ1)#define FV0 	((OPFLAG)0010000)#define FV1 	((OPFLAG)0020000)#define FV		(FV0|FV1)#define FC0 	((OPFLAG)0040000)#define FC1 	((OPFLAG)0100000)#define FC		(FC0|FC1)#define is_overwrite(op)	((op_flags[op] & DEST_OVERWRITE) != 0)#define is_altered(op)		((op_flags[op] & DEST_ALTERED) != 0)#define is_set_flags(op)	((op_flags[op] & SET_FLAGS) != 0)#define is_use_flags(op)	((op_flags[op] & USE_FLAGS) != 0)#define is_noset_flags(op)	((op_flags[op] & NOSET_FLAGS) != 0)#ifdef PEEPFLOW
#define is_modify(op)		((op_flags[op] & DEST_MODIFY) != 0)
#define is_uses_sp(op)		((op_flags[op] & USES_A7) != 0)#endif /* PEEPFLOW */
/* *	  The next two #define statements are to make the *		code in the branch optimisation clearer.  Tests *		have shown that the in-line size cost is about *		the same as making them functions so we keep *		them in-line for speed. */#define is_same_instruction(ip1,ip2) \	((ip1 != NIL_CODE) && (ip2 != NIL_CODE) && \	(ip1->opcode == ip2->opcode) && \	(ip1->length == ip2->length) && \	(is_equal_oper (ip1->oper1, ip2->oper1)) && \	(is_equal_oper (ip1->oper2, ip2->oper2)))/* backup over any sequence of labels to previous instruction */#define previous_instruction(ip) \	do { \	ip = ip->back; \	} while (ip != NIL_CODE && ip->opcode == op_label)#define branch(ip)	(ip->opcode >= op_bra && ip->opcode <= op_bls)/*********************************************** Static Function Definitions */static CODE *block_end P_ ((CODE *));static CODE *code P_ ((OPCODE, ILEN, ADDRESS *, ADDRESS *));static int label_references P_ ((const CODE *));static BOOL is_label_used P_ ((const ADDRESS *, LABEL));static BOOL is_address_used P_ ((const ADDRESS *, const ADDRESS *));static BOOL is_dest_overwritten P_ ((ADDRESS *, const CODE *));static BOOL is_equal_oper P_ ((const ADDRESS *, const ADDRESS *));static void add_peep P_ ((CODE *));static void peep_delete P_ ((const CODE *));static void peep_pea P_ ((const CODE *));static void peep_lea P_ ((CODE *));static void peep_move P_ ((CODE *));static void peep_movem P_ ((CODE *));static void peep_add P_ ((CODE *));static void peep_and P_ ((CODE *));static void peep_or P_ ((const CODE *));static void peep_clr P_ ((const CODE *));static void peep_sub P_ ((CODE *));static void peep_cmp P_ ((CODE *));static void peep_tst P_ ((const CODE *));static void peep_uctran P_ ((const CODE *));static void peep_bxx P_ ((const CODE *));static void peep_ext P_ ((const CODE *));static void peep_label P_ ((CODE *));static void check_label P_ ((const CODE *, CODE *));static void peep_bra P_ ((CODE *));static void peep_jmp P_ ((CODE *));static void peep_line P_ ((CODE *));static void opt3 P_ ((unsigned));/********************************************************** Static Variables */static CODE *peep_head = NIL_CODE;static CODE *next_ip;static int changes;static OPFLAG op_flags[] = {    /* op_move */ DEST_OVERWRITE | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_moveq */ DEST_OVERWRITE | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_movea */ DEST_OVERWRITE,    /* op_add */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_addi */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_addq */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_adda */ DEST_MODIFY | NOSET_FLAGS,    /* op_addx */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_sub */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_subi */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_subq */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FC,    /* op_suba */ DEST_MODIFY | NOSET_FLAGS,    /* op_subx */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FC,    /* op_muls */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV | FC0,    /* op_mulu */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV | FC0,    /* op_divs */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV | FC0,    /* op_divu */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV | FC0,    /* op_and */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_or */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_eor */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_asl */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_lsr */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV0 | FC,    /* op_jmp */ (OPFLAG) 0,    /* op_jsr */ USES_A7 | SET_FLAGS,    /* op_bsr */ USES_A7 | SET_FLAGS,    /* op_movem */ DEST_OVERWRITE,    /* op_rts */ USES_A7,    /* op_rte */ USES_A7,    /* op_bra */ (OPFLAG) 0,    /* op_beq */ USE_FLAGS | FZ,    /* op_bne */ USE_FLAGS | FZ,    /* op_blt */ USE_FLAGS | FN | FV,    /* op_ble */ USE_FLAGS | FN | FZ | FV,    /* op_bgt */ USE_FLAGS | FN | FZ | FV,    /* op_bge */ USE_FLAGS | FN | FV,    /* op_bhi */ USE_FLAGS | FC,    /* op_bhs */ USE_FLAGS | FZ | FC,    /* op_blo */ USE_FLAGS | FC,    /* op_bls */ USE_FLAGS | FZ | FC,    /* op_tst */ SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_ext */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_extb */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_lea */ DEST_OVERWRITE,    /* op_swap */ DEST_OVERWRITE | SET_FLAGS | FN | FZ | FV0 | FC0,    /* op_neg */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_negx */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC, 	/* op_not */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FV0,    /* op_cmp */ SET_FLAGS | FN | FZ | FV | FC,    /* op_cmpa */ SET_FLAGS | FN | FZ | FV | FC,    /* op_clr */ DEST_OVERWRITE | SET_FLAGS | FN0 | FZ1 | FV0 | FC0,    /* op_link */ DEST_OVERWRITE | USES_A7,    /* op_unlk */ DEST_OVERWRITE | USES_A7,    /* op_pea */ DEST_OVERWRITE,    /* op_cmpi */ (OPFLAG) 0,    /* op_dbra */ DEST_OVERWRITE,    /* op_asr */ DEST_MODIFY | SET_FLAGS | FX | FN | FZ | FV | FC,    /* op_rol */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC,    /* op_ror */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC,    /* op_roxl */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC,    /* op_roxr */ DEST_MODIFY | SET_FLAGS | FN | FZ | FV0 | FC,    /* op_seq */ DEST_OVERWRITE | USE_FLAGS | FZ,    /* op_sne */ DEST_OVERWRITE | USE_FLAGS | FZ,    /* op_slt */ DEST_OVERWRITE | USE_FLAGS | FN | FV,    /* op_sle */ DEST_OVERWRITE | USE_FLAGS | FN | FZ | FV,    /* op_sgt */ DEST_OVERWRITE | USE_FLAGS | FN | FZ | FV,    /* op_sge */ DEST_OVERWRITE | USE_FLAGS | FN | FV,    /* op_shi */ DEST_OVERWRITE | USE_FLAGS | FC,    /* op_shs */ DEST_OVERWRITE | USE_FLAGS | FZ | FC,    /* op_slo */ DEST_OVERWRITE | USE_FLAGS | FZ,    /* op_sls */ DEST_OVERWRITE | USE_FLAGS | FZ | FC,    /* op_nop */ (OPFLAG) 0,
    /* op_trap */ USES_A7 | SET_FLAGS,#ifdef FLOAT_IEEE    /* op_fadd */ DEST_MODIFY | SET_FLAGS,    /* op_fsub */ DEST_MODIFY | SET_FLAGS,    /* op_fdiv */ DEST_MODIFY | SET_FLAGS,    /* op_fmul */ DEST_MODIFY | SET_FLAGS,    /* op_fcmp */ SET_FLAGS,    /* op_fmove */ DEST_OVERWRITE | SET_FLAGS,    /* op_fmovem */ DEST_OVERWRITE,#endif				/* FLOAT_IEEE */#ifdef ASM    /* op_asm */ DEST_OVERWRITE,#endif				/* ASM */    /* op_line */ (OPFLAG) 0,    /* op_label */ (OPFLAG) 0,};/*****************************************************************************//* * find the end of a block of code. */static CODE *block_end P1 (CODE *, ip){    int     count = 0;    while (ip != NIL_CODE && ip->opcode != op_bra	   && ip->opcode != op_jmp	   && ip->opcode != op_rts && ip->opcode != op_rte) {	if (count == BRANCH_COUNT) {	    return NIL_CODE;	}	if (branch (ip)) {	    count++;	}	ip = ip->fwd;    }    return ip;}/* * find the node which contains the label 'lab' */CODE   *find_label P1 (LABEL, lab){    register CODE *ip;    for (ip = peep_head; ip != NIL_CODE; ip = ip->fwd) {	if (ip->opcode == op_label && ip->oper1->u.offset->v.l == lab) {	    return ip;	}    }    /* we should have found it */    return NIL_CODE;}/* * counts the number of times that a label node is referenced */static int label_references P1 (const CODE *, ip){    CODE   *target;    SWITCH *sw;    LABEL   i;    LABEL   lab = ip->oper1->u.offset->v.l;    int     count = 0;    for (target = peep_head; target != NIL_CODE; target = target->fwd) {	if ((target != ip) &&	    (is_label_used (target->oper1, lab) ||	     is_label_used (target->oper2, lab)))	    count++;    }    for (sw = swtables; sw != NIL_SWITCH; sw = sw->next) {	for (i = (LABEL) 0; i < sw->numlabs; i++) {	    if (sw->labels[i] == lab) {		count++;	    }	}    }    if (ip->back != NIL_CODE && ip->back->opcode == op_label) {	count++;    }    if (ip->fwd != NIL_CODE && ip->fwd->opcode == op_label) {	count++;    }    return count;}static BOOL is_label_used_in_expr P2 (const EXPR *, ep, LABEL, label){    if (ep == NIL_EXPR) {	return FALSE;    }    switch (ep->nodetype) {    case en_labcon:	return (ep->v.l == label);    case en_add:    case en_sub:	return (is_label_used_in_expr (ep->v.p[0], label) ||		is_label_used_in_expr (ep->v.p[1], label));    case en_uminus:    case en_cast:	return (is_label_used_in_expr (ep->v.p[0], label));    default:	return FALSE;    }}#if 0/* * Returns false if ip2 alters the flags used by the conditional jump * in ip. */static BOOL is_flags_unchanged P2 (CODE *, ip, CODE *, ip2){    return (op_flags[ip2->opcode] & (SET_FLAGS | USE_FLAGS)) == 0;}#endif/* * Returns false if the <ea> does not use the label specified. */
static BOOL is_label_used P2 (const ADDRESS *, ap, LABEL, label){    if (ap == NIL_ADDRESS) {	return FALSE;    }    switch (ap->mode) {    case am_direct:    case am_immed:    case am_indx:    case am_indx2:    case am_indx3:    case am_indx4:    case am_indxpc:    case am_indx2pc:    case am_line:    case am_str:	return (is_label_used_in_expr (ap->u.offset, label));    default:	return FALSE;    }}/* * Returns false if the register of ap1 is not used in the <ea> of ap2, * otherwise it returns true.  If we aren't sure then return true anyway. */BOOL is_register_used P2 (REG, reg, const ADDRESS *, ap){    switch (ap->mode) {    case am_dreg:    case am_areg:    case am_ainc:    case am_adec:    case am_ind:    case am_indx:    case am_freg:    case am_indx2pc:	return reg == ap->preg;    case am_indx2:    case am_indx4:    case am_mreg:	return reg == ap->preg || reg == ap->sreg;    case am_smask:    case am_rmask:	return ((ap->u.mask & (((REGMASK) 1) << (int) reg)) != (REGMASK) 0);    case am_immed:    case am_direct:    case am_indxpc:    case am_none:    case am_line:	return FALSE;    default:	break;    }    return TRUE;}/* * Returns false if the <ea> of ap1 is not used in the <ea> of ap2, otherwise * it returns true.  If we aren't sure then return true anyway. */static BOOL is_address_used P2 (const ADDRESS *, ap1, const ADDRESS *, ap2){    if (ap1 == NIL_ADDRESS || ap2 == NIL_ADDRESS) {	return FALSE;    }    switch (ap1->mode) {    case am_dreg:    case am_areg:    case am_freg:	return is_register_used (ap1->preg, ap2);    case am_immed:	return FALSE;    default:	break;    }    return TRUE;}/* * returns true if the value at the address ap1 id changed by the * addressing mode of ap2. */static BOOL is_address_changed P2 (const ADDRESS *, ap1, const ADDRESS *, ap2){    switch (ap2->mode) {    case am_ainc:    case am_adec:	return is_address_used (ap1, ap2);    default:	break;    }    return FALSE;}/* * Checks to see if the addressing mode ap is overwritten with a new value * before the value is used (or the value is never used!). */static BOOL is_dest_overwritten P2 (ADDRESS *, ap, const CODE *, ip){    CODE   *ip2;    BOOL    result = FALSE;    OPCODE  op;    if (ip == NIL_CODE) {	return FALSE;    }    switch (ap->mode) {    case am_areg:    case am_dreg:    case am_freg:	for (ip2 = ip->fwd; ip2 != NIL_CODE; ip2 = ip2->fwd) {	    switch (ip2->opcode) {	    case op_unlk:	    case op_rts:	    case op_rte:		if (is_temporary_data_register (ap->preg) ||		    is_temporary_float_register (ap->preg)) {		    /*		     *               Might be a return value		     */		    return FALSE;		} else {		    return TRUE;		}	    case op_jmp:	    case op_nop:#ifdef ASM	    case op_asm:	/* really it in unknown */#endif /* ASM */		return FALSE;	    case op_beq:	/* use of A7 unknown */	    case op_bne:	    case op_bgt:	    case op_bge:	    case op_blt:	    case op_ble:	    case op_bls:	    case op_blo:	    case op_bhi:	    case op_bhs:		op = ip2->opcode;		ip2->opcode = op_nop;	/* to prevent looping */		result = is_dest_overwritten (ap, ip2) &&		    is_dest_overwritten (ap,					 find_label (ip2->oper1->u.offset->						     v.l));		ip2->opcode = op;		return result;	    case op_bra:		op = ip2->opcode;		ip2->opcode = op_nop;	/* to prevent looping */		result =		    is_dest_overwritten (ap,					 find_label (ip2->oper1->u.offset->						     v.l));		ip2->opcode = op;		return result;	    case op_pea:	/* implicit use of A7 */	    case op_link:		if (ap->preg == STACKPTR) {		    return FALSE;		}		break;	    case op_jsr:	    case op_bsr:		if (is_temporary_register (ap->preg)) {		    return TRUE;		}		/*lint -fallthrough */	    default:		if (is_address_used (ap, ip2->oper1)		    || is_address_used (ap, ip2->oper2)) {		    return FALSE;		}		break;	    case op_label:	    case op_line:		break;	    }	}	break;    default:	break;    }    return FALSE;}/* * compare two address nodes and return true if they are equivalent. */BOOL is_equal_address P2 (const ADDRESS *, ap1, const ADDRESS *, ap2){    if (ap1 == NIL_ADDRESS && ap2 == NIL_ADDRESS) {	return TRUE;    }    if (ap1 == NIL_ADDRESS || ap2 == NIL_ADDRESS) {	return FALSE;    }    if (ap1->mode != ap2->mode) {	switch (ap1->mode) {	case am_rmask:	case am_smask:	    switch (ap2->mode) {	    case am_rmask:	    case am_smask:		break;	    default:		return FALSE;	    }	    break;	default:	    return FALSE;	}    }    switch (ap1->mode) {    case am_areg:    case am_dreg:    case am_ind:    case am_freg:	return ap1->preg == ap2->preg;    case am_indx:	return ap1->preg == ap2->preg &&	    is_equalnode (ap1->u.offset, ap2->u.offset);    case am_indx2:    case am_indx3:    case am_indx4:	return ap1->sreg == ap2->sreg &&	    ap1->preg == ap2->preg &&	    is_equalnode (ap1->u.offset, ap2->u.offset);    case am_rmask:    case am_smask:	return ap1->u.mask == ap2->u.mask;    case am_mreg:	return ap1->sreg == ap2->sreg && ap1->preg == ap2->preg;    case am_direct:    case am_immed:	return is_equalnode (ap1->u.offset, ap2->u.offset);    default:	break;    }    return FALSE;}static BOOL is_equal_oper P2 (const ADDRESS *, ap1, const ADDRESS *, ap2){    if (ap1 == NIL_ADDRESS && ap2 == NIL_ADDRESS) {	return TRUE;    }    if (ap1 == NIL_ADDRESS || ap2 == NIL_ADDRESS) {	return FALSE;    }    if (ap1->mode != ap2->mode) {	return FALSE;    }    switch (ap1->mode) {    case am_areg:    case am_dreg:    case am_ind:    case am_ainc:    case am_adec:    case am_freg:    case am_indx2pc:	return ap1->preg == ap2->preg;    case am_indx:	return ap1->preg == ap2->preg &&	    is_equalnode (ap1->u.offset, ap2->u.offset);    case am_indx2:    case am_indx3:    case am_indx4:	return ap1->preg == ap2->preg &&	    ap1->sreg == ap2->sreg &&	    is_equalnode (ap1->u.offset, ap2->u.offset);    case am_direct:    case am_immed:    case am_indxpc:	return is_equalnode (ap1->u.offset, ap2->u.offset);    case am_smask:    case am_rmask:	return ap1->u.mask == ap2->u.mask;    case am_none:    case am_line:	return TRUE;    default:	break;    }    return FALSE;}/* * Determine whether a move was redundant ... this is done by looking back * along the code list (following all branches to labels) to determine * whether the destination already contains the necessary result. */static BOOL was_move_redundant P3 (CODE *, ip, CODE *, ip2, BOOL, memory){    BOOL    altered, overwritten;    LABEL   label;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?