📄 c4x.c
字号:
the stack in reverse order (right to left). GCC handles that for us. c4x_init_cumulative_args() is called at the start, so we can parse the args to see how many floating point arguments and how many integer (or pointer) arguments there are. c4x_function_arg() is then called (sometimes repeatedly) for each argument (parsed left to right) to obtain the register to pass the argument in, or zero if the argument is to be passed on the stack. Once the compiler is happy, c4x_function_arg_advance() is called. Don't use R0 to pass arguments in, we use 0 to indicate a stack argument. */static const int c4x_int_reglist[3][6] ={ {AR2_REGNO, R2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO}, {AR2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0}, {AR2_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0, 0}};static const int c4x_fp_reglist[2] = {R2_REGNO, R3_REGNO};/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */voidc4x_init_cumulative_args (cum, fntype, libname) CUMULATIVE_ARGS *cum; /* Argument info to initialize. */ tree fntype; /* Tree ptr for function decl. */ rtx libname; /* SYMBOL_REF of library name or 0. */{ tree param, next_param; cum->floats = cum->ints = 0; cum->init = 0; cum->var = 0; cum->args = 0; if (TARGET_DEBUG) { fprintf (stderr, "\nc4x_init_cumulative_args ("); if (fntype) { tree ret_type = TREE_TYPE (fntype); fprintf (stderr, "fntype code = %s, ret code = %s", tree_code_name[(int) TREE_CODE (fntype)], tree_code_name[(int) TREE_CODE (ret_type)]); } else fprintf (stderr, "no fntype"); if (libname) fprintf (stderr, ", libname = %s", XSTR (libname, 0)); } cum->prototype = (fntype && TYPE_ARG_TYPES (fntype)); for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0; param; param = next_param) { tree type; next_param = TREE_CHAIN (param); type = TREE_VALUE (param); if (type && type != void_type_node) { enum machine_mode mode; /* If the last arg doesn't have void type then we have variable arguments. */ if (! next_param) cum->var = 1; if ((mode = TYPE_MODE (type))) { if (! MUST_PASS_IN_STACK (mode, type)) { /* Look for float, double, or long double argument. */ if (mode == QFmode || mode == HFmode) cum->floats++; /* Look for integer, enumeral, boolean, char, or pointer argument. */ else if (mode == QImode || mode == Pmode) cum->ints++; } } cum->args++; } } if (TARGET_DEBUG) fprintf (stderr, "%s%s, args = %d)\n", cum->prototype ? ", prototype" : "", cum->var ? ", variable args" : "", cum->args);}/* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */voidc4x_function_arg_advance (cum, mode, type, named) CUMULATIVE_ARGS *cum; /* Current arg information. */ enum machine_mode mode; /* Current arg mode. */ tree type; /* Type of the arg or 0 if lib support. */ int named; /* Whether or not the argument was named. */{ if (TARGET_DEBUG) fprintf (stderr, "c4x_function_adv(mode=%s, named=%d)\n\n", GET_MODE_NAME (mode), named); if (! TARGET_MEMPARM && named && type && ! MUST_PASS_IN_STACK (mode, type)) { /* Look for float, double, or long double argument. */ if (mode == QFmode || mode == HFmode) cum->floats++; /* Look for integer, enumeral, boolean, char, or pointer argument. */ else if (mode == QImode || mode == Pmode) cum->ints++; } else if (! TARGET_MEMPARM && ! type) { /* Handle libcall arguments. */ if (mode == QFmode || mode == HFmode) cum->floats++; else if (mode == QImode || mode == Pmode) cum->ints++; } return;}/* Define where to put the arguments to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. MODE is the argument's machine mode. TYPE is the data type of the argument (as a tree). This is null for libcalls where that information may not be available. CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called. NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). */struct rtx_def *c4x_function_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; /* Current arg information. */ enum machine_mode mode; /* Current arg mode. */ tree type; /* Type of the arg or 0 if lib support. */ int named; /* != 0 for normal args, == 0 for ... args. */{ int reg = 0; /* Default to passing argument on stack. */ if (! cum->init) { /* We can handle at most 2 floats in R2, R3. */ cum->maxfloats = (cum->floats > 2) ? 2 : cum->floats; /* We can handle at most 6 integers minus number of floats passed in registers. */ cum->maxints = (cum->ints > 6 - cum->maxfloats) ? 6 - cum->maxfloats : cum->ints; /* If there is no prototype, assume all the arguments are integers. */ if (! cum->prototype) cum->maxints = 6; cum->ints = cum->floats = 0; cum->init = 1; } /* This marks the last argument. We don't need to pass this through to the call insn. */ if (type == void_type_node) return 0; if (! TARGET_MEMPARM && named && type && ! MUST_PASS_IN_STACK (mode, type)) { /* Look for float, double, or long double argument. */ if (mode == QFmode || mode == HFmode) { if (cum->floats < cum->maxfloats) reg = c4x_fp_reglist[cum->floats]; } /* Look for integer, enumeral, boolean, char, or pointer argument. */ else if (mode == QImode || mode == Pmode) { if (cum->ints < cum->maxints) reg = c4x_int_reglist[cum->maxfloats][cum->ints]; } } else if (! TARGET_MEMPARM && ! type) { /* We could use a different argument calling model for libcalls, since we're only calling functions in libgcc. Thus we could pass arguments for long longs in registers rather than on the stack. In the meantime, use the odd TI format. We make the assumption that we won't have more than two floating point args, six integer args, and that all the arguments are of the same mode. */ if (mode == QFmode || mode == HFmode) reg = c4x_fp_reglist[cum->floats]; else if (mode == QImode || mode == Pmode) reg = c4x_int_reglist[0][cum->ints]; } if (TARGET_DEBUG) { fprintf (stderr, "c4x_function_arg(mode=%s, named=%d", GET_MODE_NAME (mode), named); if (reg) fprintf (stderr, ", reg=%s", reg_names[reg]); else fprintf (stderr, ", stack"); fprintf (stderr, ")\n"); } if (reg) return gen_rtx_REG (mode, reg); else return NULL_RTX;}/* C[34]x arguments grow in weird ways (downwards) that the standard varargs stuff can't handle.. */rtxc4x_va_arg (valist, type) tree valist, type;{ tree t; t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist, build_int_2 (int_size_in_bytes (type), 0)); TREE_SIDE_EFFECTS (t) = 1; return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);}static intc4x_isr_reg_used_p (regno) unsigned int regno;{ /* Don't save/restore FP or ST, we handle them separately. */ if (regno == FRAME_POINTER_REGNUM || IS_ST_REGNO (regno)) return 0; /* We could be a little smarter abut saving/restoring DP. We'll only save if for the big memory model or if we're paranoid. ;-) */ if (IS_DP_REGNO (regno)) return ! TARGET_SMALL || TARGET_PARANOID; /* Only save/restore regs in leaf function that are used. */ if (c4x_leaf_function) return regs_ever_live[regno] && fixed_regs[regno] == 0; /* Only save/restore regs that are used by the ISR and regs that are likely to be used by functions the ISR calls if they are not fixed. */ return IS_EXT_REGNO (regno) || ((regs_ever_live[regno] || call_used_regs[regno]) && fixed_regs[regno] == 0);}static intc4x_leaf_function_p (){ /* A leaf function makes no calls, so we only need to save/restore the registers we actually use. For the global variable leaf_function to be set, we need to define LEAF_REGISTERS and all that it entails. Let's check ourselves... */ if (lookup_attribute ("leaf_pretend", TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) return 1; /* Use the leaf_pretend attribute at your own risk. This is a hack to speed up ISRs that call a function infrequently where the overhead of saving and restoring the additional registers is not warranted. You must save and restore the additional registers required by the called function. Caveat emptor. Here's enough rope... */ if (leaf_function_p ()) return 1; return 0;}static intc4x_assembler_function_p (){ tree type; type = TREE_TYPE (current_function_decl); return (lookup_attribute ("assembler", TYPE_ATTRIBUTES (type)) != NULL) || (lookup_attribute ("naked", TYPE_ATTRIBUTES (type)) != NULL);}intc4x_interrupt_function_p (){ if (lookup_attribute ("interrupt", TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) return 1; /* Look for TI style c_intnn. */ return current_function_name[0] == 'c' && current_function_name[1] == '_' && current_function_name[2] == 'i' && current_function_name[3] == 'n' && current_function_name[4] == 't' && ISDIGIT (current_function_name[5]) && ISDIGIT (current_function_name[6]);}voidc4x_expand_prologue (){ unsigned int regno; int size = get_frame_size (); rtx insn; /* In functions where ar3 is not used but frame pointers are still specified, frame pointers are not adjusted (if >= -O2) and this is used so it won't needlessly push the frame pointer. */ int dont_push_ar3; /* For __assembler__ function don't build a prologue. */ if (c4x_assembler_function_p ()) { return; } /* For __interrupt__ function build specific prologue. */ if (c4x_interrupt_function_p ()) { c4x_leaf_function = c4x_leaf_function_p (); insn = emit_insn (gen_push_st ()); RTX_FRAME_RELATED_P (insn) = 1; if (size) { insn = emit_insn (gen_pushqi ( gen_rtx_REG (QImode, AR3_REGNO))); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_movqi (gen_rtx_REG (QImode, AR3_REGNO), gen_rtx_REG (QImode, SP_REGNO))); RTX_FRAME_RELATED_P (insn) = 1; /* We require that an ISR uses fewer than 32768 words of local variables, otherwise we have to go to lots of effort to save a register, load it with the desired size, adjust the stack pointer, and then restore the modified register. Frankly, I think it is a poor ISR that requires more than 32767 words of local temporary storage! */ if (size > 32767) error ("ISR %s requires %d words of local vars, max is 32767", current_function_name, size); insn = emit_insn (gen_addqi3 (gen_rtx_REG (QImode, SP_REGNO), gen_rtx_REG (QImode, SP_REGNO), GEN_INT (size))); RTX_FRAME_RELATED_P (insn) = 1; } for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (c4x_isr_reg_used_p (regno)) { if (regno == DP_REGNO) { insn = emit_insn (gen_push_dp ()); RTX_FRAME_RELATED_P (insn) = 1; } else { insn = emit_insn (gen_pushqi (gen_rtx_REG (QImode, regno))); RTX_FRAME_RELATED_P (insn) = 1; if (IS_EXT_REGNO (regno)) { insn = emit_insn (gen_pushqf (gen_rtx_REG (QFmode, regno))); RTX_FRAME_RELATED_P (insn) = 1; } } } } /* We need to clear the repeat mode flag if the ISR is going to use a RPTB instruction or uses the RC, RS, or RE registers. */ if (regs_ever_live[RC_REGNO] || regs_ever_live[RS_REGNO] || regs_ever_live[RE_REGNO]) { insn = emit_insn (gen_andn_st (GEN_INT(~0x100))); RTX_FRAME_RELATED_P (insn) = 1; } /* Reload DP reg if we are paranoid about some turkey violating small memory model rules. */ if (TARGET_SMALL && TARGET_PARANOID) { insn = emit_insn (gen_set_ldp_prologue (gen_rtx_REG (QImode, DP_REGNO), gen_rtx_SYMBOL_REF (QImode, "data_sec"))); RTX_FRAME_RELATED_P (insn) = 1; } } else { if (frame_pointer_needed) { if ((size != 0) || (current_function_args_size != 0) || (optimize < 2)) { insn = emit_insn (gen_pushqi ( gen_rtx_REG (QImode, AR3_REGNO))); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_movqi (gen_rtx_REG (QImode, AR3_REGNO), gen_rtx_REG (QImode, SP_REGNO))); RTX_FRAME_RELATED_P (insn) = 1; dont_push_ar3 = 1; } else { /* Since ar3 is not used, we don't need to push it. */ dont_push_ar3 = 1; } } else { /* If we use ar3, we need to push it. */ dont_push_ar3 = 0; if ((size != 0) || (current_function_args_size != 0)) { /* If we are omitting the frame pointer, we still have to make space for it so the offsets are correct unless we don't use anything on the stack at all. */ size += 1; } } if (size > 32767) { /* Local vars are too big, it will take multiple operations to increment SP. */ if (TARGET_C3X) { insn = emit_insn (gen_movqi (gen_rtx_REG (QImode, R1_REGNO), GEN_INT(size >> 16))); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_lshrqi3 (gen_rtx_REG (QImode, R1_REGNO), gen_rtx_REG (QImode, R1_REGNO), GEN_INT(-16))); RTX_FRAME_RELATED_P (insn) = 1; } else { insn = emit_insn (gen_movqi (gen_rtx_REG (QImode, R1_REGNO), GEN_INT(size & ~0xffff))); RTX_FRAME_RELATED_P (insn) = 1; } insn = emit_insn (gen_iorqi3 (gen_rtx_REG (QImode, R1_REGNO),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -