📄 genarm.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 *//****************************************************************************** * * this module contains all of the code generation routines for evaluating * expressions and conditions. * *****************************************************************************/#include "config.h"#ifdef ARM#define GEN_MODULE#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"#include "genarm.h"#include "outproto.h"/********************************************************* Macro Definitions */#define AL_DEFAULT (g_alignments[bt_ellipsis])/*********************************************** Static Function Definitions */static ADDRESS *mk_legal P_ ((ADDRESS *, FLAGS));static BOOL g_compare P_ ((const EXPR *));static ADDRESS *g_cast P_ ((ADDRESS *, TYP *, TYP *, FLAGS));static ADDRESS *g_expr P_ ((const EXPR *, FLAGS));static void g_falsejp P_ ((const EXPR *, LABEL));static void g_truejp P_ ((const EXPR *, LABEL));#ifdef MULTIPLE_PROCESSORSPRIVATE 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_stack P_ ((SIZE));PRIVATE void g_switch_table P_ ((const EXPR *, const SWITCH *, UVAL, UVAL));PRIVATE void g_switch_compare P_ ((const EXPR *, STMT *));PRIVATE void g_entry P_ ((SIZE));PRIVATE void g_return P_ ((const EXPR *, TYP *));PRIVATE void g_epilogue P_ ((void));PRIVATE void g_allocate P_ ((CSE *));PRIVATE void g_flush P_ ((SYM *));PRIVATE void g_auto_align P_ ((void));PRIVATE BOOL g_is_bigendian P_ ((void));PRIVATE BOOL g_is_ascending_stack P_ ((void));PRIVATE void g_initialize P_ ((void));#endif /* MULTIPLE_PROCESSORS *//********************************************************** Static Variables */static unsigned peep_option = PEEP_ALL; /* peephole optimisations */static int stackopt_option = 1L; /* Use lazy stack optimisation */static BOOL regs_used = 0; /* number of register variables allocated */static SIZE max_stack_adjust = 0L; /* largest amount stack is altered */static REG frameptr = FRAMEPTR;static REGMASK restore_mask; /* list of registers used by function *//* * The following tables specify the alignment requirements of the * basic types depending on the processor type. */static SIZE alignments_arm[] = { 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 */ 4L, /* bt_int32 */ 4L, /* bt_uint32 */ 4L, /* bt_long */ 4L, /* bt_ulong */ 4L, /* bt_longlong */ 4L, /* bt_ulonglong */ 4L, /* bt_float */ 4L, /* bt_double */ 4L, /* bt_longdouble */ 4L, /* bt_floatcomplex */ 4L, /* bt_doublecomplex */ 4L, /* bt_longdoublecomplex */ 4L, /* bt_float */ 4L, /* bt_double */ 4L, /* bt_longdouble */ 4L, /* bt_pointer16 */ 4L, /* bt_pointer32 */ 4L, /* bt_struct */ 4L, /* bt_union */ 4L, /* bt_func */ 4L, /* bt_bitfield */ 4L, /* bt_ubitfield */ 1L, /* bt_bbitfield */ 4L /* bt_ellipsis - used for alignment suitable for all types */};#ifndef MULTIPLE_PROCESSORSPRIVATE SIZE *g_alignments = &alignments_arm[0];#endif /* MULTIPLE_PROCESSORS *//*****************************************************************************/static ADDRESS *mk_amode P1 (AMODE, mode){ ADDRESS *ap; ap = (ADDRESS *) xalloc (sizeof (ADDRESS)); ap->mode = mode; return ap;}/* * 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;}/* * make a ep to reference an immediate value i. */static ADDRESS *mk_immed P1 (IVAL, i){ ADDRESS *ap; ap = mk_amode (am_immed); ap->offset = mk_const (i); return ap;}/* * construct a reference node for an internal label number. */static ADDRESS *mk_label P1 (LABEL, lab){ ADDRESS *ap; ap = mk_amode (am_direct); ap->offset = mk_lcon (lab); return ap;}/* * make a node to reference a line number. */static ADDRESS *mk_line P1 (LINE, i){ ADDRESS *ap; ap = mk_amode (am_line); ap->offset = mk_const ((IVAL) i); return ap;}#if 0/* * generate a direct reference to a string label. */ADDRESS *mk_strlab P1 (CHAR *, s){ ADDRESS *ap; ap = mk_amode (am_direct); ap->offset = mk_node (en_nacon, NIL_EXPR, NIL_EXPR, tp_void); ap->offset->v.sp = s; return ap;}#endif/* * make an address reference to a register. */ADDRESS *mk_reg P1 (REG, r){ ADDRESS *ap; ap = mk_amode (am_reg); ap->preg = r; return ap;}/* * make an address reference to a register mask list. */static ADDRESS *mk_mask P1 (REGMASK, mask){ ADDRESS *ap; ap = mk_amode (am_mask); ap->offset = mk_const ((IVAL) mask); return ap;}static ADDRESS *mk_direct P1 (EXPR *, ep){ ADDRESS *ap; ap = mk_amode (am_direct); ap->offset = ep; return ap;}static ADDRESS *mk_address P3 (AMODE, mode, REG, reg, SIZE, off){ ADDRESS *ap; ap = mk_amode (mode); ap->preg = reg; ap->offset = mk_const (off); return ap;}static ADDRESS *mk_legal P2 (ADDRESS *, ap, FLAGS, flags){ ADDRESS *ap2; if (flags & F_NOVALUE) { freeop (ap); return NIL_ADDRESS; } switch (ap->mode) { case am_immed: if (flags & F_IMMED) { return ap; } break; case am_reg: if (flags & F_REG) { return ap; } break; default: break; } if (flags & F_REG) { freeop (ap); ap2 = data_register (); g_code (op_mov, cc_al, ap2, ap, NIL_ADDRESS); return ap2; } FATAL ((__FILE__, "mk_legal", "mode = %d, flags = %d", ap->mode, flags)); return NIL_ADDRESS;}/* * add a compiler generated label to the peep list. */PRIVATE void g_label P1 (LABEL, labno){ sync_stack (); g_code (op_label, cc_al, mk_label (labno), NIL_ADDRESS, NIL_ADDRESS);}#ifdef DEBUGOPT/* * add a source line number to the peep list. */PRIVATE void g_line P2 (LINE, line, const CHAR *, str){ (void) str; g_code (op_line, cc_al, mk_line (line), NIL_ADDRESS, NIL_ADDRESS);}#endif /*DEBUGOPT *//* * add a conditional branch instruction to the peep list. */static void g_cbranch P2 (CONDITION, cc, LABEL, labno){ sync_stack (); g_code (op_b, cc, mk_label (labno), NIL_ADDRESS, NIL_ADDRESS);}/* * add a branch instruction to the peep list. */PRIVATE void g_branch P1 (LABEL, labno){ g_code (op_b, cc_al, mk_label (labno), NIL_ADDRESS, NIL_ADDRESS);}/* * adjust the stack by "bytes" bytes. */PRIVATE void g_stack P1 (SIZE, bytes){ if (bytes != 0L) { /* adjust stack pointer */ stack_offset -= bytes; if (max_stack_adjust < bytes) { max_stack_adjust = bytes; } }}/* * generate the code to access an object. */static ADDRESS *g_deref P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap1; (void) flags; switch (ep->nodetype) { case en_autocon: ap1 = mk_amode (am_pre); ap1->preg = frameptr; ap1->offset = mk_const (ep->v.i); return ap1; default: ap1 = g_expr (ep, (FLAGS) (F_REG | F_IMMED)); if (ap1->mode == am_immed) { return copy_addr (ap1, am_pre); } return copy_addr (ap1, am_direct); }}/* * generate the code for a unary minus */static ADDRESS *g_uminus P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap1, *ap2; switch (ep->etp->type) { case bt_char: case bt_schar: case bt_uchar: case bt_charu: case bt_short: case bt_int16: case bt_ushort: case bt_uint16: case bt_long: case bt_ulong: case bt_int32: case bt_uint32: case bt_pointer32: ap2 = g_expr (ep->v.p[0], F_REG); freeop (ap2); ap1 = data_register (); g_code (op_rsb, cc_al, ap1, ap2, mk_immed (0L)); return mk_legal (ap1, flags); default: FATAL ((__FILE__, "g_uminus", "type = %d", ep->etp->type)); break; } return NIL_ADDRESS;}/* * generate the code for a negate */static ADDRESS *g_negate P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap1, *ap2; switch (ep->etp->type) { case bt_char: case bt_schar: case bt_uchar: case bt_charu: case bt_short: case bt_int16: case bt_ushort: case bt_uint16: case bt_long: case bt_ulong: case bt_int32: case bt_uint32: case bt_pointer32: ap2 = g_expr (ep->v.p[0], F_REG); freeop (ap2); ap1 = data_register (); g_code (op_mvn, cc_al, ap1, ap2, NIL_ADDRESS); return mk_legal (ap1, flags); default: FATAL ((__FILE__, "g_negate", "type = %d", ep->etp->type)); break; } return NIL_ADDRESS;}/* * generate code to evaluate a and/or/xor node and return the addressing * node of the result */static ADDRESS *g_logic P3 (const EXPR *, ep, FLAGS, flags, OPCODE, op){ ADDRESS *ap1, *ap2; switch (ep->etp->type) { case bt_int32: case bt_uint32: case bt_long: case bt_ulong: case bt_pointer32: ap1 = g_expr (ep->v.p[0], F_REG); ap2 = g_expr (ep->v.p[1], (FLAGS) (F_REG | F_IMMED)); validate (ap1); freeop (ap2); g_code (op, cc_al, ap1, ap1, ap2); return mk_legal (ap1, flags); default: FATAL ((__FILE__, "g_logic", "illegal type %d", ep->etp->type)); break; } return NIL_ADDRESS;}static ADDRESS *g_aslogic P3 (const EXPR *, ep, FLAGS, flags, OPCODE, op){ (void) flags; (void) op; FATAL ((__FILE__, "g_aslogic", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}/* * generate code to evaluate an add/subtract node and return the addressing * node of the result */static ADDRESS *g_add P3 (const EXPR *, ep, FLAGS, flags, OPCODE, op){ ADDRESS *ap1, *ap2; switch (ep->etp->type) { case bt_int32: case bt_uint32: case bt_long: case bt_ulong: case bt_pointer32: ap1 = g_expr (ep->v.p[0], F_REG); ap2 = g_expr (ep->v.p[1], (FLAGS) (F_REG | F_IMMED)); validate (ap1); freeop (ap2); g_code (op, cc_al, ap1, ap1, ap2); return mk_legal (ap1, flags); default: FATAL ((__FILE__, "g_add", "illegal type %d", ep->etp->type)); break; } return NIL_ADDRESS;}static ADDRESS *g_asadd P3 (const EXPR *, ep, FLAGS, flags, OPCODE, op){ (void) flags; (void) op; FATAL ((__FILE__, "g_asadd", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_mul P2 (const EXPR *, ep, FLAGS, flags){ (void) flags; (void) ep; FATAL ((__FILE__, "g_mul", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_asmul P2 (const EXPR *, ep, FLAGS, flags){ (void) flags; FATAL ((__FILE__, "g_asmul", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_div P2 (const EXPR *, ep, FLAGS, flags){ (void) flags; FATAL ((__FILE__, "g_div", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_asdiv P2 (const EXPR *, ep, FLAGS, flags){ (void) flags; FATAL ((__FILE__, "g_asdiv", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_mod P2 (const EXPR *, ep, FLAGS, flags){ (void) flags; FATAL ((__FILE__, "g_mod", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_asmod P2 (const EXPR *, ep, FLAGS, flags){ (void) flags; FATAL ((__FILE__, "g_asmod", "typ = %d", ep->etp->type)); return NIL_ADDRESS;}static ADDRESS *g_lshift P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap1, *ap2, *ap3; switch (ep->etp->type) { case bt_int32: case bt_uint32: case bt_long: case bt_ulong: case bt_pointer32: ap1 = g_expr (ep->v.p[0], F_REG); ap2 = g_expr (ep->v.p[1], (FLAGS) (F_REG | F_IMMED)); validate (ap1); freeop (ap2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -