📄 genarm.c
字号:
*/static void g_test P1 (const EXPR *, ep){ ADDRESS *ap; switch (ep->etp->type) { case bt_char: case bt_schar: case bt_short: case bt_int16: case bt_int32: case bt_long: case bt_uchar: case bt_charu: case bt_ushort: case bt_uint16: case bt_uint32: case bt_ulong: case bt_pointer32: ap = g_expr (ep, F_REG); g_code (op_movs, cc_al, ap, ap, NIL_ADDRESS); freeop (ap); return; default: FATAL ((__FILE__, "g_test", "typ = %d\n", ep->etp->type)); break; }}/* * generate a jump to label if the node passed evaluates to a true condition. */static void g_truejp P2 (const EXPR *, ep, LABEL, label){ CONDITION cc; LABEL lab0; if (is_icon (ep)) { if (ep->v.i) { g_branch (label); } return; } switch (ep->nodetype) { case en_eq: VOIDCAST g_compare (ep); cc = cc_eq; goto cont1; case en_ne: VOIDCAST g_compare (ep); cc = cc_ne; goto cont1; case en_lt: cc = g_compare (ep) ? cc_cc : cc_lt; goto cont1; case en_le: cc = g_compare (ep) ? cc_ls : cc_le; goto cont1; case en_gt: cc = g_compare (ep) ? cc_hi : cc_gt; goto cont1; case en_ge: cc = g_compare (ep) ? cc_cs : cc_ge; cont1: g_cbranch (cc, label); return; case en_land: lab0 = nextlabel++; g_falsejp (ep->v.p[0], lab0); g_truejp (ep->v.p[1], label); g_label (lab0); return; case en_lor: g_truejp (ep->v.p[0], label); g_truejp (ep->v.p[1], label); return; case en_not: g_falsejp (ep->v.p[0], label); return; default: g_test (ep); g_cbranch (cc_ne, label); return; }}/* * generate code to execute a jump to label if the expression passed is * false. */static void g_falsejp P2 (const EXPR *, ep, LABEL, label){ CONDITION cc; LABEL lab0; if (is_icon (ep)) { if (ep->v.i) { g_branch (label); } return; } switch (ep->nodetype) { case en_eq: VOIDCAST g_compare (ep); cc = cc_ne; goto cont1; case en_ne: VOIDCAST g_compare (ep); cc = cc_eq; goto cont1; case en_lt: cc = g_compare (ep) ? cc_cs : cc_ge; goto cont1; case en_le: cc = g_compare (ep) ? cc_hi : cc_gt; goto cont1; case en_gt: cc = g_compare (ep) ? cc_ls : cc_le; goto cont1; case en_ge: cc = g_compare (ep) ? cc_cc : cc_lt; cont1: g_cbranch (cc, label); return; case en_land: g_falsejp (ep->v.p[0], label); g_falsejp (ep->v.p[1], label); return; case en_lor: lab0 = nextlabel++; g_truejp (ep->v.p[0], lab0); g_falsejp (ep->v.p[1], label); g_label (lab0); return; case en_not: g_truejp (ep->v.p[0], label); return; default: g_test (ep); g_cbranch (cc_eq, label); return; }}PRIVATE void g_jtrue P2 (const EXPR *, ep, LABEL, label){ initstack (); g_truejp (ep, label); checkstack ();}PRIVATE void g_jfalse P2 (const EXPR *, ep, LABEL, label){ initstack (); g_falsejp (ep, label); checkstack ();}PRIVATE void g_switch_table P4 (const EXPR *, ep, const SWITCH *, sw, UVAL, min_caselabel, UVAL, max_caselabel){ (void) ep; (void) sw; (void) min_caselabel; (void) max_caselabel; initstack (); checkstack ();}/* * Generate the body of a switch statement by comparing each case value * in turn. The comparison is in fact done by using subtraction as this * actually generates more efficient code (and would work best if the * labels were sorted!) */PRIVATE void g_switch_compare P2 (const EXPR *, ep, STMT *, stmt){ (void) ep; (void) stmt; initstack (); checkstack ();}PRIVATE void g_entry P1 (SIZE, frame_size){ (void) frame_size;#if 0 SYM *sp; if (framesize > 0L) { sp = runtime_symbol (SYM_STACK); g_code (op_bl, cc_al, mk_strlab (nameof (sp)), NIL_ADDRESS, NIL_ADDRESS); }#endif}PRIVATE void g_return P2 (const EXPR *, stmtexp, TYP *, tp){ ADDRESS *ap; (void) tp; initstack (); ap = g_expr (stmtexp, F_ALL); g_code (op_mov, cc_al, mk_reg (reg_usage->result->reg[0]), ap, NIL_ADDRESS); freeop (ap); checkstack ();}PRIVATE void g_epilogue P0 (void){ if (restore_mask) { g_code (op_ldmea, cc_al, mk_reg (FRAMEPTR), mk_mask (restore_mask), NIL_ADDRESS); } g_code (op_mov, cc_al, mk_reg (R14), mk_reg (R15), NIL_ADDRESS);}/* * allocate will allocate registers for the expressions that have a high * enough desirability. */PRIVATE void g_allocate P1 (CSE *, olist){ CSE *csp; REG reg = (REG) ((int) max_reg + 1); REGMASK mask = (REGMASK) 0; TYP *tp; regs_used = 0; for (csp = olist; csp != NIL_CSE; csp = csp->next) { tp = csp->exp->etp; if (!reg_option && desire (csp) < (USES) 5000) { csp->reg = NO_REG; } else if (reg < frameptr && csp->exp->nodetype != en_icon && csp->exp->nodetype != en_nacon && (tp->type == bt_pointer32 || tp->type == bt_long || tp->type == bt_ulong || tp->type == bt_int16 || tp->type == bt_uint16 || tp->type == bt_int32 || tp->type == bt_uint32 || tp->type == bt_short || tp->type == bt_ushort || tp->type == bt_char || tp->type == bt_schar || tp->type == bt_uchar || tp->type == bt_charu)) { csp->reg = reg++; mask |= REGBIT (csp->reg); regs_used++; } else { csp->reg = NO_REG; } } if (mask != (REGMASK) 0) { g_code (op_stmfd, cc_al, mk_reg (STACKPTR), mk_mask (mask), NIL_ADDRESS); } restore_mask = mask;}/* * Go through the common sub-expression tree and check to see if * any registers must be loaded with a value. */PRIVATE void g_preload P1 (CSE *, olist){ CSE *csp; EXPR *ep; ADDRESS *ap, *ap2; for (csp = olist; csp != NIL_CSE; csp = csp->next) { if (csp->reg != NO_REG) { ep = csp->exp; if ((!is_lvalue (ep)) || ep->v.p[0]->v.i > 0L) { initstack (); ap = g_expr (ep, F_ALL); ap2 = mk_reg (csp->reg); g_code (op_mov, cc_al, ap, ap2, NIL_ADDRESS); freeop (ap); } } }}PRIVATE void g_flush P1 (SYM *, sp){ put_literals (); if (sp) { put_cseg (alignment_of_type (typeof (sp))); put_name (sp); } flush_peep (peep_option); put_epilogue (sp, nextlabel++);
}PRIVATE void g_auto_align P0 (void){ if (lc_auto_max % AL_DEFAULT != 0L) { lc_auto_max += AL_DEFAULT - (lc_auto_max % AL_DEFAULT); }}PRIVATE BOOL g_is_bigendian P0 (void){ return TRUE;}PRIVATE BOOL g_is_ascending_stack P0 (void){ return FALSE;}/* * This routine does any code generator specific transformations * on the expression tree. * * For example it can replace operator nodes with calls to runtime * routines. This allows the global optimiser to perform optimisations * on such calls which wouldn't be possible if the calls were * generated in the code generator routines themselves. */PRIVATE EXPR *g_transform P1 (EXPR *, ep){ if (ep == NIL_EXPR) { return ep; } switch (ep->nodetype) { case en_icon: case en_nacon: case en_labcon: case en_autocon: case en_sym: case en_ref: case en_fieldref: case en_register: case en_uminus: case en_test: case en_not: case en_compl: case en_ainc: case en_adec: case en_cast: case en_deref: case en_add: case en_sub: case en_div: case en_mod: case en_lsh: case en_rsh: case en_and: case en_or: case en_xor: case en_land: case en_lor: case en_eq: case en_ne: case en_lt: case en_le: case en_gt: case en_ge: case en_cond: case en_comma: case en_list: case en_asadd: case en_assub: case en_asmul: case en_asdiv: case en_asor: case en_asxor: case en_asand: case en_asmod: case en_aslsh: case en_asrsh: case en_fcall: case en_call:
case en_usercall: case en_assign: case en_mul: break; default: CANNOT_REACH_HERE (); break; } return ep;}/* * This routine is called after the global optimizer has done it's * work re-organizing the expression tree. This allows a code * generator to make code generator specific changes to the expression * tree which will result in better code generation. */PRIVATE EXPR *g_order P1 (EXPR *, ep){ return ep;}/* * This routine is called when the compiler is initialising, i.e. * before it even starts scanning tokens. */PRIVATE void g_initialize P0 (void){ if (!optimize_option) { stackopt_option = 0; } if (stackopt_option) { is_parameter = FALSE; }}/* * This routine is called when the compiler is closing down. */PRIVATE void g_terminate P0 (void){}/* * Returns the current register usage. */PRIVATE REGUSAGE *g_regusage P1 (TYP *, tp){ (void) tp; return reg_usage;}#ifdef MULTIPLE_PROCESSORS#define MCARM_FUNCS (void *)&mcarm_funcs#else#define MCARM_FUNCS (void *)NULL#endif /* MULTIPLE_PROCESSORS */static OPTSET peepset[] = { {(const CHAR *) "none", PEEP_NONE}, {(const CHAR *) "flow", PEEP_FLOW}, {(const CHAR *) "all", PEEP_ALL}, {(const CHAR *) NULL, 0}};static OPTENUM yesnoopts[] = { {(const CHAR *) "yes", 1}, {(const CHAR *) "no", 0}, {(const CHAR *) NULL, 0}};static OPTION opts[] = { { (const CHAR *) "peep=", set_option, {&peep_option}, {&peepset[0]} }, { (const CHAR *) "prefix=", string_option, {(void *) &external_prefix}, {NULL} }, { (const CHAR *) "reg=", enumeration_option, {®_option}, {&yesnoopts[0]} },#ifdef TRANSLATE { (const CHAR *) "trans=", enumeration_option, {&trans_option}, {&yesnoopts[0]} },#endif /* TRANSLATE */#ifdef MULTIPLE_ASSEMBLERS#ifdef TARGET_ARM { (const CHAR *) "armarm", chip_option, {&armarm_funcs}, {MCARM_FUNCS} },#endif /* TARGET_OBJ */#ifdef TARGET_OBJ { (const CHAR *) "objarm", chip_option, {&armobj_funcs}, {MCARM_FUNCS} },#endif /* TARGET_OBJ */#else#ifdef TARGET_ARM { (const CHAR *) "armarm", chip_option, {NULL}, {MCARM_FUNCS} },#endif /* TARGET_OBJ */#ifdef TARGET_OBJ { (const CHAR *) "objarm", chip_option, {NULL}, {MCARM_FUNCS} },#endif /* TARGET_OBJ */#endif /* MULTIPLE_ASSEMBLERS */ { (const CHAR *) NULL, NULL, {NULL}, {NULL} }};OPTIONS optsarm = { (const CHAR *) "ARM ", opts};#ifdef MULTIPLE_PROCESSORSstruct genfuncs mcarm_funcs = { g_expression, g_jtrue, g_jfalse, g_stack, g_switch_table, g_switch_compare, g_entry, g_return, g_epilogue, g_label, g_branch,#ifdef DEBUGOPT g_line,#endif /*DEBUGOPT */ g_allocate, g_preload, g_flush, g_auto_align, g_is_bigendian, g_is_ascending_stack, g_order, g_transform, g_initialize, g_terminate, g_regusage, &alignments_arm[0]};#endif /* MULTIPLE_PROCESSORS */#endif /* ARM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -