📄 peepx86.c
字号:
/* * 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 INTEL#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"#include "genx86.h"#include "outproto.h"/********************************************************* Macro Definitions */#define DEST_MODIFY ((unsigned char)1)#define DEST_OVERWRITE ((unsigned char)2)#define DEST_ALTERED (DEST_MODIFY | DEST_OVERWRITE)/* * 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_jbe)/*********************************************** Static Function Definitions */static CODE *code P_ ((OPCODE, ILEN, ADDRESS *, ADDRESS *));static CODE *find_label P_ ((LABEL));static BOOL is_label_used P_ ((ADDRESS *, LABEL));static BOOL is_address_used P_ ((ADDRESS *, ADDRESS *));static BOOL is_dest_overwritten P_ ((ADDRESS *, CODE *));static void add_peep P_ ((CODE *));static void peep_delete P_ ((CODE *));static void peep_test P_ ((CODE *));static void peep_mov P_ ((CODE *));static void peep_cmp P_ ((CODE *));static void peep_lea P_ ((CODE *));static void peep_xtend P_ ((CODE *));static void peep_addsub P_ ((CODE *, IVAL));static void peep_uctran P_ ((CODE *));static void peep_bxx P_ ((CODE *));static void peep_label P_ ((CODE *));static void peep_line P_ ((CODE *));static void check_label P_ ((CODE *, CODE *));static void peep_bra P_ ((CODE *));static void opt3 P_ ((unsigned));static BOOL is_equal_oper P_ ((ADDRESS *, ADDRESS *));/********************************************************** Static Variables */static unsigned char op_flags[] = { /* op_movsbl */ DEST_OVERWRITE, /* op_movzbl */ DEST_OVERWRITE, /* op_movswl */ DEST_OVERWRITE, /* op_movzwl */ DEST_OVERWRITE, /* op_movsbw */ DEST_OVERWRITE, /* op_movzbw */ DEST_OVERWRITE, /* op_cdq */ DEST_OVERWRITE, /* op_cwd */ DEST_OVERWRITE, /* op_cbw */ DEST_OVERWRITE, /* op_mov */ DEST_OVERWRITE, /* op_xchg */ DEST_OVERWRITE, /* op_lea */ DEST_OVERWRITE, /* op_not */ DEST_MODIFY, /* op_neg */ DEST_MODIFY, /* op_add */ DEST_MODIFY, /* op_sub */ DEST_MODIFY, /* op_adc */ DEST_MODIFY, /* op_sbb */ DEST_MODIFY, /* op_imul */ DEST_MODIFY, /* op_idiv */ DEST_MODIFY, /* op_div */ DEST_MODIFY, /* op_and */ DEST_MODIFY, /* op_or */ DEST_MODIFY, /* op_xor */ DEST_MODIFY, /* op_inc */ DEST_MODIFY, /* op_dec */ DEST_MODIFY, /* op_cmp */ 0, /* op_push */ 0, /* op_pop */ DEST_OVERWRITE, /* op_jmp */ 0, /* op_loop */ 0, /* op_call */ 0, /* op_leave */ DEST_OVERWRITE, /* op_enter */ 0, /* op_ret */ 0, /* op_test */ 0, /* op_bra */ 0, /* op_je */ 0, /* op_jne */ 0, /* op_jl */ 0, /* op_jle */ 0, /* op_jg */ 0, /* op_jge */ 0, /* op_ja */ 0, /* op_jae */ 0, /* op_jb */ 0, /* op_jbe */ 0, /* op_rep */ 0, /* op_smov */ DEST_OVERWRITE, /* op_shl */ DEST_MODIFY, /* op_shr */ DEST_MODIFY, /* op_asl */ DEST_MODIFY, /* op_asr */ DEST_MODIFY, /* op_rol */ DEST_MODIFY, /* op_ror */ DEST_MODIFY, /* op_sahf */ DEST_MODIFY, /* op_sete */ DEST_OVERWRITE, /* op_setne */ DEST_OVERWRITE, /* op_setb */ DEST_OVERWRITE, /* op_setbe */ DEST_OVERWRITE, /* op_seta */ DEST_OVERWRITE, /* op_setae */ DEST_OVERWRITE, /* op_setl */ DEST_OVERWRITE, /* op_setle */ DEST_OVERWRITE, /* op_setg */ DEST_OVERWRITE, /* op_setge */ DEST_OVERWRITE, /* op_nop */ 0,#ifdef FLOAT_IEEE /* op_fadd */ 0, /* op_faddp */ 0, /* op_fsub */ 0, /* op_fsubp */ 0, /* op_fdiv */ 0, /* op_fdivp */ 0, /* op_fmul */ 0, /* op_fmulp */ 0, /* op_fsubr */ 0, /* op_fsubrp */ 0, /* op_fdivr */ 0, /* op_fdivrp */ 0, /* op_fld */ 0, /* op_fldz */ 0, /* op_fst */ 0, /* op_fstp */ 0, /* op_fpop */ 0, /* op_fild */ 0, /* op_fildl */ 0, /* op_fistp */ 0, /* op_fistpl */ 0, /* op_ftst */ 0, /* op_fchs */ 0, /* op_fcomp */ 0, /* op_fcompp */ 0, /* op_fnstsw */ 0, /* op_fwait */ 0,#endif /* FLOAT_IEEE */ /* op_line */ 0, /* op_label */ 0};static CODE *peep_head = NIL_CODE;static CODE *next_ip;static int changes;/*****************************************************************************//* * 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_ret)) { if (count == BRANCH_COUNT) { return NIL_CODE; } if (branch (ip)) { count++; } ip = ip->fwd; } return ip;}/* * find the node which contains the label 'lab' */static 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;}/* * Returns false if the <ea> does is not a label or else isn't equal to label */static BOOL is_label_used P2 (ADDRESS *, ap, LABEL, label){ return (ap != NIL_ADDRESS && ap->mode == am_direct && ap->u.offset->nodetype == en_labcon && ap->u.offset->v.l == label);}/* * Returns false if the <ea> of ap1 is not used in the <ea> of ap2, * otherwise it returns true. If we arn't sure then returns true anyway. */static BOOL is_address_used P2 (ADDRESS *, ap1, ADDRESS *, ap2){ if (ap1 == NIL_ADDRESS || ap2 == NIL_ADDRESS) { return FALSE; } switch (ap1->mode) { case am_dreg: case am_areg: switch (ap2->mode) { case am_dreg: case am_areg: case am_ind: case am_indx: case am_indx2: return ap2->preg == ap1->preg; case am_direct: case am_immed: case am_line: return FALSE; default: break; } break; case am_immed: return FALSE; default: break; } return TRUE;}/* * Checks to see if the addressing mode ap is overwritten with a new * value before the value is used. */static BOOL is_dest_overwritten P2 (ADDRESS *, ap, CODE *, ip){ CODE *ip2, *ip3; if (ap->mode != am_dreg && ap->mode != am_areg) { return FALSE; } for (ip3 = NIL_CODE, ip2 = ip->fwd; ip2 != NIL_CODE;) { switch (ip2->opcode) { case op_leave: peep_delete (ip); return TRUE; case op_lea: if (ip2->oper2->preg == STACKPTR) { peep_delete (ip); return TRUE; }; goto def; case op_ret: case op_je: /* use of SP unknown */ case op_jne: case op_jl: case op_jle: case op_jg: case op_jge: case op_ja: case op_jae: case op_jb: case op_jbe: case op_jmp: return FALSE; case op_call: /* implicit use of SP */ case op_pop: case op_push: if (ap->preg == STACKPTR) { return FALSE; } /*FALLTHRU */ default: def: if (is_address_used (ap, ip2->oper1) || is_address_used (ap, ip2->oper2)) { return FALSE; } /*FALLTHRU */ case op_label: ip2 = ip2->fwd; break; case op_bra: if (ip2 == ip3) /* check to see if we are looping */ return FALSE; ip3 = ip2; /* remember that we have been here */ ip2 = find_label (ip2->oper1->u.offset->v.l); break; } } return FALSE;}/* * compare two address nodes and return true if they are equivalent. */BOOL is_equal_address P2 (ADDRESS *, ap1, 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_dreg: case am_areg: case am_freg: case am_ind: return (ap1->preg == ap2->preg); case am_indx: return (ap1->preg == ap2->preg && is_equalnode (ap1->u.offset, ap2->u.offset)); case am_indx2: return (ap1->preg == ap2->preg && ap1->sreg == ap2->sreg && is_equalnode (ap1->u.offset, ap2->u.offset)); case am_mreg: return (ap1->preg == ap2->preg && ap1->sreg == ap2->sreg); case am_direct: return is_equalnode (ap1->u.offset, ap2->u.offset); default: break; } return FALSE;}static BOOL is_equal_oper P2 (ADDRESS *, ap1, 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_dreg: case am_areg: case am_ind: return ap1->preg == ap2->preg; case am_freg: return TRUE; case am_indx: return ap1->preg == ap2->preg && is_equalnode (ap1->u.offset, ap2->u.offset); case am_direct: return is_equalnode (ap1->u.offset, ap2->u.offset); case am_immed: return ap1->u.offset->v.i == ap2->u.offset->v.i; default: break; } return FALSE;}/* * Determine whether a move is 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; SWITCH *sw; for (ip2 = ip2->back; ip2 != NIL_CODE; ip2 = ip2->back) { switch (ip2->opcode) { case op_label: label = ip2->oper1->u.offset->v.l; /* first check code before the label */ if (!was_move_redundant (ip, ip2, memory)) { return FALSE; } /* ... and then check all branches to this label */ for (ip2 = peep_head; ip2 != NIL_CODE; ip2 = ip2->fwd) { if (branch (ip2)) { if (is_label_used (ip2->oper1, label)) { OPCODE op = ip2->opcode; ip2->opcode = op_nop; if (!was_move_redundant (ip, ip2, memory)) { ip2->opcode = op; return FALSE; } ip2->opcode = op; } } } /* but if it is via a jump table we cannot determine it */ for (sw = swtables; sw != NIL_SWITCH; sw = sw->next) { LABEL lab; for (lab = (LABEL) 0; lab < sw->numlabs; lab++) { if (sw->labels[lab] == label) { return FALSE; } } } return TRUE; case op_ret: case op_jmp: case op_bra: /* should have at least hit a label before here! */ case op_nop: return TRUE; case op_call:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -