📄 genc30.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 * * * 1995 Ivo Oesch, Started in to write a codegenerator for the * signalprocessor TMS320C30 (December) *//****************************************************************************** * * this module contains all of the code generation routines for evaluating * expressions and conditions. * *****************************************************************************/#include "config.h"#ifdef TMS320C30#define GEN_MODULE#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"#include "genc30.h"#include "outproto.h"/********************************************************* Macro Definitions */#define NEW_BITFIELDSTUFF#define best_flags(requested, possible) ((FLAGS)((requested&possible)!=0 ? requested&possible : possible))#define isanyreg(AP) ((AP->mode==am_areg)||(AP->mode==am_dreg)||(AP->mode==am_ireg)||(AP->mode==am_sreg))#define AL_DEFAULT (g_alignments[bt_ellipsis])#define is_op3_violated(ap) ( ((ap)->mode == am_ainc) || ((ap)->mode == am_adec) \ ||((ap)->mode == am_preinc)|| ((ap)->mode == am_predec) \ ||((ap)->mode == am_direct)|| ((ap)->mode == am_immed) \ ||((ap)->mode == am_const_direct))/********************************************************** Type Definitions */typedef struct _itree{ LABEL label; EXPR *value; struct _itree *less; struct _itree *more;}ITREE;/********************************************************** Static Variables */static unsigned peep_option = PEEP_STANDARD; /* peehole optimisations */static int regs_used = 0; /* number of register variable allocated */static int address_reg_used = 0; /* number of register variable allocated to addressregisters */static REGMASK restore_mask; /* register restore mask */static REGMASK floatrestore_mask; /* register restore mask */static REGMASK interrupt_restore_mask = 0; /* register restore mask */static REGMASK interrupt_floatrestore_mask = 0; /* register restore mask */static REGMASK return_register_mask = 0; /* used returnregister */static SIZE max_stack_adjust = 0L; /* largest amount stack is altered */static REGMASK forced_save_mask = 0;#if 0static REGMASK forced_floatsave_mask = 0;#else#define forced_floatsave_mask (forced_save_mask & MASK_REG_DATA)#endif/* * The following tables specify the alignment requirements of the * basic types depending on the processor type. */static SIZE alignments_c30[] = { 1L, /* bt_void */ 1L, /* bt_bool */ 1L, /* bt_char */ 1L, /* bt_charu */ 1L, /* bt_uchar */ 1L, /* bt_schar */ 1L, /* bt_short */ 1L, /* bt_ushort */ 1L, /* bt_int16 */ 1L, /* bt_uint16 */ 1L, /* bt_int32 */ 1L, /* bt_uint32 */ 1L, /* bt_long */ 1L, /* bt_ulong */ 1L, /* bt_longlong */ 1L, /* bt_ulonglong */ 1L, /* bt_float */ 1L, /* bt_double */ 1L, /* bt_longdouble */ 1L, /* bt_floatcomplex */ 1L, /* bt_doublecomplex */ 1L, /* bt_longdoublecomplex */ 1L, /* bt_floatimaginary */ 1L, /* bt_doubleimaginary */ 1L, /* bt_longdoubleimaginary */ 1L, /* bt_pointer16 */ 1L, /* bt_pointer32 */ 1L, /* bt_struct */ 1L, /* bt_union */ 1L, /* bt_func */ 1L, /* bt_bitfield */ 1L, /* bt_ubitfield */ 1L, /* bt_bbitfield */ 1L /* bt_ellipsis - used for alignment suitable for all types */};/* * support routines, define as pointers to be sure to have only * one copy in memory of them, else symsearch does not work * properly sinc it compares pointers and not contents of strings */static const CHAR *psup_fpdiv = SUP_FPDIV;static const CHAR *psup_fprem = SUP_FPREM;static const CHAR *psup_ldiv = SUP_LDIV;static const CHAR *psup_lrem = SUP_LREM;static const CHAR *psup_uldiv = SUP_ULDIV;static const CHAR *psup_ulrem = SUP_ULREM;static int opt_const_in_ram = OPT_NO;static int opt_true_long = OPT_NO;static int stackopt_option = OPT_SAFE;static int opt_shortfloat = 1;static int interrupt_option = OPT_NO;static int opt_traps = OPT_NO;int opt_branches = OPT_LEVEL1;int opt_delayed_branches = 2;const CHAR *opt_peep_sequence = (const CHAR *) "";int opt_peep_test = 0;REG frameptr = FRAMEPTR;#ifndef MULTIPLE_PROCESSORSPRIVATE SIZE *g_alignments = &alignments_c30[0];#endif /* MULTIPLE_PROCESSORS *//*********************************************** Static Function Definitions */static ADDRESS *as_fcall P_ ((const EXPR *, FLAGS, const CHAR *, ITYPE));static ADDRESS *func_result P_ ((FLAGS, SIZE, TYP *));static ADDRESS *g_addsub P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_aincdec P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_asadd P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_asbitfield P_ ((const EXPR *, FLAGS, OPCODE, BOOL));static ADDRESS *g_asdiv P_ ((const EXPR *, FLAGS, BOOL));static ADDRESS *g_aslogic P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_asmul P_ ((const EXPR *, FLAGS));static ADDRESS *g_asshift P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_assign P_ ((const EXPR *, FLAGS));static ADDRESS *g_cast P_ ((ADDRESS *, TYP *, TYP *, FLAGS));static ADDRESS *g_conditionalloadP_ ((const EXPR *, ADDRESS *, ADDRESS *, ITYPE, FLAGS));static ADDRESS *g_deref P_ ((const EXPR *, TYP *, FLAGS));static ADDRESS *g_div P_ ((const EXPR *, FLAGS, BOOL));static ADDRESS *g_expr P_ ((const EXPR *, FLAGS));static ADDRESS *g_fcall P_ ((const EXPR *, FLAGS));static ADDRESS *g_fderef P_ ((const EXPR *, FLAGS));static ADDRESS *g_hook P_ ((const EXPR *, FLAGS));static ADDRESS *g_index P_ ((const EXPR *));static ADDRESS *g_logic P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_mul P_ ((const EXPR *, FLAGS));static ADDRESS *g_shift P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *g_unary P_ ((const EXPR *, FLAGS, OPCODE));static ADDRESS *mk_legal P_ ((ADDRESS *, FLAGS, ITYPE));static ADDRESS *mk_ilabel P_ ((const EXPR *));static ADDRESS *check_trap P_ ((const EXPR *));static ADDRESS *mk_indirect P_ ((REG, EXPR *));static BOOL g_compare P_ ((const EXPR *));static BOOL tst_iconst P_ ((const EXPR *));static EXPR *copy_iexpr P_ ((const EXPR *));static SIZE g_parms P_ ((const EXPR *));static SIZE push_param P_ ((const EXPR *));static void call_library_r0_r1 P_ ((const CHAR *));static void g_immed P_ ((OPCODE, IVAL, ADDRESS *));static void g_rotate P_ ((ADDRESS *, int, TYP *, int));static void g_test P_ ((const EXPR *));static void structassign P_ ((ADDRESS *, ADDRESS *, SIZE));static void g_truejp P_ ((const EXPR *, LABEL));static void g_falsejp P_ ((const EXPR *, LABEL));static void allocate_blockrepeat_registers P_ ((void));/*********************************************** Global Function Definitions */#ifdef MULTIPLE_PROCESSORSPRIVATE BOOL g_is_ascending_stack P_ ((void));PRIVATE BOOL g_is_bigendian P_ ((void));PRIVATE EXPR *g_transform P_ ((EXPR *));PRIVATE void g_allocate P_ ((CSE *));PRIVATE void g_auto_align P_ ((void));PRIVATE void g_entry P_ ((SIZE));PRIVATE void g_epilogue P_ ((void));PRIVATE void g_expression P_ ((const EXPR *));PRIVATE void g_flush P_ ((SYM *));PRIVATE void g_initialize P_ ((void));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));#endif /* MULTIPLE_PROCESSORS *//*****************************************************************************//*****************************************************************************/static ADDRESS *mk_amode P1 (AMODE, mode){ ADDRESS *ap; ap = (ADDRESS *) xalloc ((size_t) 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;}/* * make a node to reference a line number. */static ADDRESS *mk_line P1 (LINE, i){ return mk_expr (am_line, mk_const ((IVAL) i));}/* * 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);}/* * copy an address mode structure. */ADDRESS *copy_addr P2 (ADDRESS *, ap, AMODE, mode){ ADDRESS *newap; assert (ap); newap = (ADDRESS *) xalloc ((size_t) sizeof (ADDRESS)); *newap = *ap; newap->mode = mode; return newap;}/* * make a node to reference an signed immediate value i. */static ADDRESS *mk_immed P1 (IVAL, i){ if ((i <= 32767L) && (i >= -32768L)) return mk_expr (am_immed, mk_const (i)); else return mk_ilabel (mk_const (i));}/* * make a node to reference an unsigned immediate value i. */static ADDRESS *mk_uimmed P1 (IVAL, i){ if (i < 0) FATAL ((__FILE__, "mk_uimmed", "value is negative %ld", i)); if (i <= 0xFFFFL) return mk_expr (am_immed, mk_const (i)); else return mk_ilabel (mk_const (i));}/* * construct a reference node for an internal label number. */ADDRESS *mk_label P1 (LABEL, lab){ return mk_expr (am_const_direct, mk_lcon (lab));}static ADDRESS *mk_Jumplabel P1 (LABEL, lab){ return mk_expr (am_immed, mk_lcon (lab));}/* * 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_immed, ep);}/* * generate a call to a library routine. * it is assumed that lib_name won''t be clobbered */static void call_library_r0_r1 P1 (const CHAR *, lib_name){ SYM *sp; sp = internal_symbol (lib_name, tp_void); /* routines are using all temporary-registers, so * intrruptroutines must save them */ interrupt_restore_mask |= MEMBER (REG_R0) | MEMBER (REG_R1) | MEMBER (REG_R2) | MEMBER (REG_AR0) | MEMBER (REG_AR1); interrupt_floatrestore_mask |= MEMBER (REG_R0) | MEMBER (REG_R1) | MEMBER (REG_R2); /* * op_xcall is a marker for the peephole-optimizer, * it assumes, that only xcall uses R0 and R1 registers * for parameterpassing. * all other calls are assumed to use stack for * parameterpassing, so values of r0 and r1 (and * all other tempregs) may be invalidated/overwritten * before functionscall. */ g_code (op_xcall, OP_INT, mk_strlab (nameof (sp)), NIL_ADDRESS);}/* * make an address reference to a register. */ADDRESS *mk_reg P1 (REG, r){ ADDRESS *ap; switch (r) { case REG_R0: case REG_R1: case REG_R2: case REG_R3: case REG_R4: case REG_R5: case REG_R6: case REG_R7: ap = mk_amode (am_dreg); ap->preg = r; break; case REG_AR0: case REG_AR1: case REG_AR2: case REG_AR3: case REG_AR4: case REG_AR5: case REG_AR6: case REG_AR7: ap = mk_amode (am_areg); ap->preg = r; break; case REG_IR0: case REG_IR1: ap = mk_amode (am_ireg); ap->preg = r; break; case REG_DP: case REG_BK: case REG_SP: case REG_ST: case REG_IE: case REG_IF: case REG_IOF: case REG_RS: case REG_RE: case REG_RC: ap = mk_amode (am_sreg); ap->preg = r; break; default: CANNOT_REACH_HERE (); ap = NIL_ADDRESS; } interrupt_restore_mask |= MEMBER (r); return ap;}/* * make an address reference to a floatregister. */ADDRESS *mk_freg P1 (REG, r){ ADDRESS *ap; assert (r <= REG_R7); ap = mk_amode (am_freg); ap->preg = r; interrupt_restore_mask |= MEMBER (r); interrupt_floatrestore_mask |= MEMBER (r); return ap;}/* * returns addressing mode of form offset(frameptr) * size is rounded up to AL_DEFAULT */static ADDRESS *mk_scratch P1 (SIZE, size){ ADDRESS *ap; SIZE default_alignment = AL_DEFAULT; /* round up the request */ if (size % default_alignment) size += default_alignment - (size % default_alignment); /* 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; } /* do not add act_scratch, because pointer must point to start of * scratch area */ ap = mk_indirect (frameptr, mk_const ((lc_auto_max + 1))); return ap;}/* * push all register in the masks onto stack. */static void push_registers P2 (REGMASK, mask, REGMASK, floatmask){ REG reg; for (reg = MAX_REG; reg >= REG_R0; reg--) { /* Check which registers are set in mask */ if ((mask & MEMBER (reg)) != 0) { g_code (op_pushnopeep, OP_INT, mk_reg (reg), NIL_ADDRESS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -