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