peepc30.c

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

C
2,250
字号
	case op_blo:	case op_bls:	case op_bhi:	case op_bhs:	case op_beq:	case op_bne:	case op_blt:	case op_ble:	case op_bgt:	case op_bge:	case op_bz:	case op_bnz:	case op_bp:	case op_bn:	case op_bnn:	case op_bu:	case op_br:	    branches += 3;	    tot++;	    group1blocked = 0;	    group3blocked = 0;	    break;	case op_abort:	    FATAL ((__FILE__, "analyze_code", "unexpected abort"));	    break;#ifdef ASM	case op_asm:		/* really it in unknown */	    asmstat++;	    break;#endif /* ASM */	case op_bud:	case op_brd:	default:	    map = GET_PEEP_INFO (ip, &StaticMemory);	    flags = map->used | map->updated;	    if (flags & GROUP_1_REGISTERS) {		reg += group1blocked;		group1blocked = 0;		group3blocked = 0;	    }	    if (flags & GROUP_3_REGISTERS) {		reg += group3blocked;		group1blocked = 0;		group3blocked = 0;	    }	    flags = map->read;	    if (flags & GROUP_1_READ) {		/* Delay is 1, but will allready be decremented in		 * this loop, so set to 2		 */		group1blocked = 2;	    }	    if (flags & GROUP_3_READ) {		/* Delay is 1, but will allready be decremented in		 * this loop, so set to 2		 */		group3blocked = 2;	    }	    flags = map->modified | map->write;	    if (flags & GROUP_1_WRITE) {		/* Delay is 2, but will allready be decremented in		 * this loop, so set to 3		 */		group1blocked = 3;	    }	    if (flags & GROUP_3_WRITE) {		/* Delay is 2, but will allready be decremented in		 * this loop, so set to 3		 */		group3blocked = 3;	    }	    if (group1blocked > 0) {		group1blocked--;	    }	    if (group3blocked > 0) {		group3blocked--;	    }	    tot++;	    break;	case op_label:	case op_line:	    break;	}    }    *totsize += tot;    *branchconflicts += branches;    *registerconflicts += reg;    *asmstatements += asmstat;}/* * Returns false if the register reg1 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, reg1, const ADDRESS *, ap2){    if (ap2 == NIL_ADDRESS)	return FALSE;    switch (ap2->mode) {    case am_areg:    case am_dreg:    case am_freg:    case am_ireg:    case am_sreg:    case am_ainc:    case am_adec:    case am_preinc:    case am_predec:    case am_ind:    case am_const_ind:    case am_indx:	return ap2->preg == reg1;    case am_indx2:    case am_indxs:	return ap2->sreg == reg1 || ap2->preg == reg1;    case am_immed:    case am_direct:    case am_const_direct:    case am_none:    case am_line:	return FALSE;    default:	break;    }    return TRUE;}/* * Checks to see if the register reg is overwritten with a new value * before the value is used (or the value is never used!). * If the value is not used again, FALSE is returned. */static BOOL is_value_used P2 (REG, reg, const CODE *, ip){    CODE   *ip2, *target;    BOOL    result = FALSE;    OPCODE  op;    SWITCH *sw, *table;    LABEL   label;    unsigned i;    REGBITMAP needed;    REGBITMAP regbit = (1UL << (int) reg);    PEEPINFO *map;#ifdef SAVE_PEEP_MEMORY    PEEPINFO StaticMemory;#endif /* SAVE_PEEP_MEMORY */    if (ip == NIL_CODE)	return FALSE;    for (ip2 = ip->fwd; ip2 != NIL_CODE; ip2 = ip2->fwd) {	switch (ip2->opcode) {	case op_retsu:	    if ((reg == RESULT)		|| (reg == STACKPTR)) {		/*		 **  Might be a return value		 */		return TRUE;	    } else {		return FALSE;	    }	case op_retiu:	case op_abort:	    return FALSE;#ifdef ASM	case op_asm:		/* really it in unknown */	    return TRUE;#endif /* ASM */	case op_blo:	case op_bls:	case op_bhi:	case op_bhs:	case op_beq:	case op_bne:	case op_blt:	case op_ble:	case op_bgt:	case op_bge:	case op_bz:	case op_bnz:	case op_bp:	case op_bn:	case op_bnn:	    op = ip2->opcode;	    ip2->opcode = op_abort;	/* to prevent looping */	    /* follow both paths of the branch */	    result = is_value_used (reg, ip2) ||		is_value_used (reg, find_label (ip2->src1->u.offset->v.l));	    ip2->opcode = op;	    return result;	case op_bud:	case op_brd:	    /*	     * brd should not be found in this stage of	     * codeanalysis. return TRUE if still found.	     */	    return TRUE;	case op_bu:	    /*	     * bu is used in switchtable, so we cannot say	     * (we had to check al paths of the switch), assume	     * value is used, thats save in any case	     * if enabled in option we analyse switches too	     */	    if (!is_peep_phase (peep_level, PEEP_SWITCH)) {		return TRUE;	    }	    /* look for the switchtable belonging to that op_bu */	    table = NIL_SWITCH;	    for (sw = swtables; sw != NIL_SWITCH; sw = sw->next) {		/* genc30 adds the labelname into the offsetfield of src1 */		if (ip2->src1->u.offset->v.l == sw->tablab) {		    table = sw;		    break;		}	    }	    if (table != NIL_SWITCH) {		op = ip2->opcode;		ip2->opcode = op_abort;	/* to prevent looping */		result = is_register_used (reg, ip2->src1);		/* follow all paths of the switch */		for (i = 0; i < table->numlabs; i++) {		    label = table->labels[i];		    target = find_label (label);		    if (target == NULL) {			FATAL (			       (__FILE__, "is_value_used",				"switch_target not found"));		    }		    result |= is_value_used (reg, target);		}		ip2->opcode = op;		return result;	    } else {		FATAL (		       (__FILE__, "is_value_used",			"switchtable for bu not found"));	    }	    return TRUE;	case op_br:	    op = ip2->opcode;	    ip2->opcode = op_abort;	/* to prevent looping */	    result = is_register_used (reg, ip2->src1) ||		is_value_used (reg, find_label (ip2->src1->u.offset->v.l));	    ip2->opcode = op;	    return result;#ifndef PEEP_CALL_ALSO_VIA_TABLE	case op_xcall:	    if (is_temporary_register (reg)) {		if ((reg == REG_R0) || (reg == REG_R1))		    return TRUE;	/* may be used to pass parameters */		else		    return FALSE;	    }	    /*lint -fallthrough */	case op_callu:	case op_trapu:	case op_call:	    if (reg == STACKPTR)		return TRUE;	    if (is_temporary_register (reg)) {		return FALSE;	    }	    /*lint -fallthrough */#endif /* PEEP_CALL_ALSO_VIA_TABLE */	default:	    map = GET_PEEP_INFO (ip2, &StaticMemory);	    needed = map->read | map->modified | map->used | map->updated;	    /*	     *  if register is used (read or modified)	     *  we return TRUE (it is used :-) )	     */	    if (needed & regbit) {		return TRUE;	    }	    /*	     *  if register is written to	     *  we return FALSE ( Contents are obviously not used)	     */	    if (map->write & regbit) {		return FALSE;	    }	    break;	case op_label:	case op_line:	    break;	}    }    return FALSE;}/* * Checks to see if a remap of registers is possible in a forward direction * e.g. if register 'search' may be replaced with 'replace' in the * following instruction sequence. * * This is not possible if: * *       'search' is STACKPTR. * *       'search' is RESULT and sequence ends with return. * *       An asm-statement is in the sequence. * *       'replace' is used or modified. * *       'replace' is overwritten and more replacements follow in *       this sequence. * *       'replace' is not an address register and 'search' is used *       as an address register or index register in an indirect *       address mode. * * By branches, labels and jumps we return FALSE, because following * all paths and do all replacements correctly is somewhat hairy * (I just dont know how to do it, so I let it be). * * The sequence ends if return is found or 'search' is overwritten. */static BOOL is_remap_possible_fwd P3 (REG, search_reg, REG, replace,
				      const CODE *, ip){    CODE   *ip2;    BOOL    replacement_forbidden = FALSE;    BOOL    result;    REGBITMAP changed;    REGBITMAP needed;    REGBITMAP replacebit = (1UL << (int) replace);    REGBITMAP searchbit = (1UL << (int) search_reg);    PEEPINFO *map;#ifdef SAVE_PEEP_MEMORY    PEEPINFO StaticMemory;#endif /* SAVE_PEEP_MEMORY */    if (ip == NIL_CODE)	return FALSE;    for (ip2 = ip->fwd; ip2 != NIL_CODE; ip2 = ip2->fwd) {	switch (ip2->opcode) {	case op_retsu:	    /* We are at the end of the block, if search_reg is sp	     * or RESULT we cannot replace registers */	    if ((search_reg == RESULT)		|| (search_reg == STACKPTR)) {		/*		 **  Might be a return value		 */		return FALSE;	    } else {		return TRUE;	    }	case op_retiu:	case op_abort:	    return FALSE;#ifdef ASM	case op_asm:		/* really it in unknown */	    return FALSE;#endif /* ASM */	case op_blo:	case op_bls:	case op_bhi:	case op_bhs:	case op_beq:	case op_bne:	case op_blt:	case op_ble:	case op_bgt:	case op_bge:	case op_bz:	case op_bnz:	case op_bp:	case op_bn:	case op_bnn:	    /* may be too complicated to follow, so we let it be for now */	    /* so we use the simpler variant of just checking if search  */	    /* and replace are not used anymore on jumpdestination       */#if 1	    if (is_peep_phase (peep_level, PEEP_HARD_REMAP)) {		result =		    is_value_used (search_reg,				   find_label (ip2->src1->u.offset->v.l));		result = result		    || is_value_used (replace,				      find_label (ip2->src1->u.offset->v.l));		if (result == TRUE) {		    return FALSE;		}	    } else {		return FALSE;	    }	    break;#else	    return FALSE;#endif	case op_br:#if 1	    if (is_peep_phase (peep_level, PEEP_HARD_REMAP)) {		result =		    is_value_used (search_reg,				   find_label (ip2->src1->u.offset->v.l));		result = result		    || is_value_used (replace,				      find_label (ip2->src1->u.offset->v.l));		if (result == TRUE) {		    return FALSE;		}		return TRUE;	    }#endif	    return FALSE;	case op_bu:#if 1	    if (is_peep_phase (peep_level, PEEP_VERY_HARD_REMAP)) {		/* use ip2->back, then is_value_used will analyze the switch for us */		result = is_value_used (search_reg, ip2->back);		result = result || is_value_used (replace, ip2->back);		if (result == TRUE) {		    return FALSE;		}		return TRUE;	    }#endif	    return FALSE;	case op_bud:	case op_brd:	    /* We wont follow branches, too difficult */	    return FALSE;#ifdef  PEEP_CALL_ALSO_VIA_TABLE	case op_xcall:	    if ((search_reg == REG_R0) || (search_reg == REG_R1)) {		/*		 * Registers are used to pass parameters,

⌨️ 快捷键说明

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