📄 gen86.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_86/****************************************************************************** * * this module contains all of the code generation routines for evaluating * expressions and conditions for the INTEL 8086 processor. * *****************************************************************************/#define GEN_MODULE#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"#include "gen86.h"#include "outproto.h"/********************************************************* Macro Definitions */#define AL_DEFAULT (g_alignments[bt_ellipsis])/********************************************************** Static Variables */static unsigned peep_option = PEEP_ALL; /* peephole optimisation */static int target_option = target_8086; /* code generator target */static int stackopt_option = OPT_MINIMUM; /* Use lazy stack optimisation */static int regs_used = 0; /* number of register variable allocated */static REGMASK restore_mask; /* register restore mask */static SIZE max_stack_adjust = 0L; /* largest amount stack is altered */static REG regframe = FRAMEPTR;static SETVAL regsave_option = EMPTY_SET; /* registers to save on call */static ADDRESS eax_reg = { am_dreg, EAX, (REG) 0, (DEEP) 0, {NIL_EXPR}};static ADDRESS ecx_reg = { am_dreg, ECX, (REG) 0, (DEEP) 0, {NIL_EXPR}};static ADDRESS edx_reg = { am_dreg, EDX, (REG) 0, (DEEP) 0, {NIL_EXPR}};static ADDRESS esp_reg = { am_dreg, ESP, (REG) 0, (DEEP) 0, {NIL_EXPR}};static ADDRESS edi_reg = { am_dreg, EDI, (REG) 0, (DEEP) 0, {NIL_EXPR}};static ADDRESS esi_reg = { am_dreg, ESI, (REG) 0, (DEEP) 0, {NIL_EXPR}};static REGTYPE reg_type[] = { (REGTYPE) (D_REG | T_REG | X_REG), /* EAX */ (REGTYPE) (D_REG | T_REG | X_REG), /* EDX */ (REGTYPE) (D_REG | T_REG | Y_REG | C_REG), /* ECX */ (REGTYPE) (D_REG | T_REG), /* EBX */ (REGTYPE) (A_REG | T_REG), /* ESI */ (REGTYPE) (A_REG | T_REG), /* EDI */ 0, /* ESP */ 0, /* EBP */ 0, /* AX */ 0, /* DX */ 0, /* CX */ 0, /* BX */ 0, /* SI */ 0, /* DI */ 0, /* SP */ 0, /* BP */ 0, /* AL */ 0, /* DL */ 0, /* CL */ 0, /* BL */ (REGTYPE) (F_REG | T_REG), /* ST0 */ (REGTYPE) (F_REG | T_REG), /* ST1 */ (REGTYPE) (F_REG | T_REG), /* ST2 */ (REGTYPE) (F_REG | T_REG), /* ST3 */ (REGTYPE) (F_REG | T_REG), /* ST4 */ (REGTYPE) (F_REG | T_REG), /* ST5 */ (REGTYPE) (F_REG | T_REG), /* ST6 */ (REGTYPE) (F_REG | T_REG) /* ST7 */};/* * The following tables specify the alignment requirements of the * basic types depending on the processor type. */static SIZE alignments_8086[] = { 1L, /* bt_void */ 1L, /* bt_bool */ 1L, /* bt_char */ 1L, /* bt_charu */ 1L, /* bt_uchar */ 1L, /* bt_schar */ 2L, /* bt_short */ 2L, /* bt_ushort */ 2L, /* bt_int16 */ 2L, /* bt_uint16 */ 2L, /* bt_int32 */ 2L, /* bt_uint32 */ 2L, /* bt_long */ 2L, /* bt_ulong */ 2L, /* bt_longlong */ 2L, /* bt_ulonglong */ 2L, /* bt_float */ 2L, /* bt_double */ 2L, /* bt_longdouble */ 2L, /* bt_floatcomplex */ 2L, /* bt_doublecomplex */ 2L, /* bt_longdoublecomplex */ 2L, /* bt_floatimaginary */ 2L, /* bt_doubleimaginary */ 2L, /* bt_longdoubleimaginary */ 2L, /* bt_pointer16 */ 2L, /* bt_pointer32 */ 2L, /* bt_struct */ 2L, /* bt_union */ 2L, /* bt_func */ 2L, /* bt_bitfield */ 2L, /* bt_ubitfield */ 1L, /* bt_bbitfield */ 2L /* bt_ellipsis - used for alignment suitable for all types */};#ifndef MULTIPLE_PROCESSORSPRIVATE SIZE *g_alignments = &alignments_8086[0];#endif /* MULTIPLE_PROCESSORS *//*********************************************** Static Function Definitions */static ADDRESS *func_result P_ ((FLAGS, SIZE, TYP *));static ADDRESS *g_asbin P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_asbitfield P_ ((const EXPR *, FLAGS, OPCODE, BOOL));static ADDRESS *g_expr P_ ((const EXPR *, FLAGS));static ADDRESS *g_extend P_ ((ADDRESS *, TYP *, TYP *));static ADDRESS *mk_amode P_ ((AMODE));static ADDRESS *mk_expr P_ ((AMODE, EXPR *));static ADDRESS *mk_indirect P_ ((REG, EXPR *));static ADDRESS *mk_low P_ ((ADDRESS *));static ADDRESS *mk_high P_ ((ADDRESS *));static void g_compare P_ ((const EXPR *, OPCODE, OPCODE, LABEL));static void g_falsejp P_ ((const EXPR *, LABEL));static void g_test P_ ((const EXPR *));static void g_truejp P_ ((const EXPR *, LABEL));#ifdef STACK_CHECKstatic ADDRESS *mk_strlab P_ ((const CHAR *));#endif /* STACK_CHECK *//*********************************************** Global Function Definitions */#ifdef MULTIPLE_PROCESSORSPRIVATE BOOL g_is_bigendian P_ ((void));PRIVATE BOOL g_is_ascending_stack P_ ((void));PRIVATE void g_auto_align P_ ((void));PRIVATE void g_flush P_ ((SYM *));PRIVATE void g_allocate P_ ((CSE *));PRIVATE void g_branch P_ ((LABEL));PRIVATE void g_entry P_ ((SIZE));PRIVATE void g_epilogue P_ ((void));PRIVATE void g_expression P_ ((const EXPR *));PRIVATE void g_jfalse P_ ((const EXPR *, LABEL));PRIVATE void g_jtrue P_ ((const EXPR *, LABEL));PRIVATE void g_label P_ ((LABEL));PRIVATE void g_return P_ ((const EXPR *, TYP *));PRIVATE void g_stack P_ ((SIZE));PRIVATE void g_switch_compare P_ ((const EXPR *, STMT *));PRIVATE void g_switch_table P_ ((const EXPR *, const SWITCH *, UVAL, UVAL));PRIVATE void g_initialize P_ ((void));#endif /* MULTIPLE_PROCESSORS *//*****************************************************************************//* * copy an address mode structure. */static ADDRESS *copy_addr P2 (ADDRESS *, ap, AMODE, mode){ ADDRESS *newap; if (ap == NIL_ADDRESS) { FATAL ((__FILE__, "copy_addr", "ap == 0")); } newap = (ADDRESS *) xalloc (sizeof (ADDRESS)); *newap = *ap; newap->mode = mode; return newap;}static ADDRESS *mk_amode P1 (AMODE, mode){ ADDRESS *ap; ap = (ADDRESS *) xalloc (sizeof (ADDRESS)); ap->mode = mode; return ap;}static ADDRESS *mk_expr P2 (AMODE, mode, EXPR *, ep){ ADDRESS *ap; ap = mk_amode (mode); ap->u.offset = ep; return ap;}#ifndef INTEL_386/* * make a node to reference an immediate value i. */ADDRESS *mk_immed P1 (IVAL, i){ return mk_expr (am_immed, mk_const (i));}/* * construct a reference node for an internal label number. */ADDRESS *mk_label P1 (LABEL, lab){ return mk_expr (am_direct, mk_lcon (lab));}#endif /* INTEL_386 */#ifdef DEBUGOPT/* * make a node to reference a line number. */static ADDRESS *mk_line P1 (LINE, i){ return mk_expr (am_line, mk_const ((IVAL) i));}#endif /* DEBUGOPT */#ifdef DEBUGOPT/* * make a node to reference a source line. */static ADDRESS *mk_linetxt P1 (const CHAR *, s){ EXPR *ep; ep = mk_node (en_str, NIL_EXPR, NIL_EXPR, tp_void); ep->v.str = s; return mk_expr (am_str, ep);}#endif /* DEBUGOPT *//* * make a direct reference to a node. */static ADDRESS *mk_direct P1 (EXPR *, ep){ return mk_expr (am_direct, ep);}/* * make an indirect reference to a node. */static ADDRESS *mk_indirect P2 (REG, reg, EXPR *, ep){ ADDRESS *ap; ap = mk_expr (am_indx, ep); ap->preg = reg; return ap;}#ifdef STACK_CHECK/* * generate a direct reference to a string label. */static ADDRESS *mk_strlab P1 (const CHAR *, s){ EXPR *ep; ep = mk_node (en_nacon, NIL_EXPR, NIL_EXPR, tp_void); ep->v.str = s; return mk_expr (am_direct, ep);}#endif /* STACK_CHECK */#ifndef INTEL_386/* * make an address reference to a register. */ADDRESS *mk_reg P1 (REG, reg){ ADDRESS *ap; switch (reg) { case EAX: case EBX: case ECX: case EDX: case ESI: case EDI: case ESP: case EBP: ap = mk_amode (am_dreg); break;#ifdef FLOAT_IEEE case ST0: case ST1: case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: ap = mk_amode (am_freg); break;#endif /* FLOAT_IEEE */ default: CANNOT_REACH_HERE (); } ap->preg = reg; return ap;}ADDRESS *mk_mreg P2 (REG, r1, REG, r2){ ADDRESS *ap; ap = mk_amode (am_mreg); ap->preg = r1; ap->sreg = r2; return ap;}#endif /* INTEL_386 */static ADDRESS *mk_offset P2 (ADDRESS *, ap, SIZE, off){ switch (ap->mode) { case am_ind: ap = mk_indirect (ap->preg, mk_const (off)); return ap; case am_indx: case am_indx2: ap = copy_addr (ap, ap->mode); ap->u.offset = mk_const (ap->u.offset->v.i + off); return ap; case am_direct: ap = copy_addr (ap, ap->mode); ap->u.offset = mk_add (ap->u.offset, mk_const (off)); return ap; default: /* address must be done "by hand" */ return NIL_ADDRESS; }}/* * Get the low address/reference for a 4 byte item */static ADDRESS *mk_low P1 (ADDRESS *, ap){ switch (ap->mode) { case am_dreg: case am_areg: return ap; case am_mreg: return mk_reg (ap->preg); case am_ind: case am_indx: case am_indx2: case am_direct: return mk_offset (ap, 0L); case am_immed: return mk_immed ((IVAL) (ap->u.offset->v.u & 0x0000ffffL)); default: CANNOT_REACH_HERE (); break; } return NIL_ADDRESS;}/* * Get the high address/reference for a 4 byte item */static ADDRESS *mk_high P1 (ADDRESS *, ap){ switch (ap->mode) { case am_mreg: return mk_reg (ap->sreg); case am_ind: case am_indx: case am_indx2: case am_direct: return mk_offset (ap, 2L); case am_immed: return mk_immed ((IVAL) ((ap->u.offset->v.u >> 16) & 0x0000ffffL)); default: CANNOT_REACH_HERE (); break; } return NIL_ADDRESS;}/* * returns addressing mode of form offset(regframe) * size is rounded up to AL_DEFAULT */static ADDRESS *mk_scratch P1 (SIZE, size){ ADDRESS *ap; /* round up the request */ if (size % AL_DEFAULT) { size += AL_DEFAULT - (size % AL_DEFAULT); } /* allocate the storage */ act_scratch += size; /* * The next statement could be deferred and put into the * routine checkstack(), but this is just safer. */ if (act_scratch > max_scratch) { max_scratch = act_scratch; } ap = mk_indirect (regframe, mk_const (-(lc_auto_max + act_scratch))); return ap;}/* * add a label node to the peep list */PRIVATE void g_label P1 (LABEL, labno){ sync_stack (); g_code (op_label, IL0, mk_label (labno), NIL_ADDRESS);}#ifdef DEBUGOPT/* * add a source line number to the peep list. */PRIVATE void g_line P2 (LINE, line, const CHAR *, linetxt){ g_code (op_line, IL0, mk_line (line), mk_linetxt (linetxt));}#endif /*DEBUGOPT *//* * Add a conditional branch instruction to the peep list */static void g_cbranch P2 (OPCODE, op, LABEL, labno){ sync_stack (); g_code (op, IL0, mk_label (labno), NIL_ADDRESS);}/* * add a branch instruction to the peep list. */PRIVATE void g_branch P1 (LABEL, labno){ g_cbranch (op_bra, labno);}/* * adjust the stack by "bytes" bytes. */PRIVATE void g_stack P1 (SIZE, bytes){ switch (bytes) { case 0l: return; default: g_code (op_add, IL2, mk_immed (bytes), &esp_reg); } stack_offset -= bytes; if (max_stack_adjust < bytes) { max_stack_adjust = bytes; }}/* * mk_legal will coerce the addressing mode in ap1 into a mode that is * satisfactory for the flag word. */static ADDRESS *mk_legal P3 (ADDRESS *, ap, FLAGS, flags, TYP *, tp){ ADDRESS *ap1, *ap2; SIZE size = tp->size; if (flags & F_NOVALUE) { if (ap) {#ifdef FLOAT_IEEE if (ap->mode == am_freg) { g_fcode (op_fstp, IL10, mk_reg (ST0), NIL_ADDRESS); }#endif /* FLOAT_IEEE */ freeop (ap); } return NIL_ADDRESS; } if (ap == NIL_ADDRESS) { FATAL ((__FILE__, "mk_legal", "ap == 0")); } switch (ap->mode) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -