📄 c4x.c
字号:
cum->ints = cum->floats = 0; cum->init = 1; } 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;}static intc4x_isr_reg_used_p (regno) int regno;{ /* Don't save/restore FP or ST, we handle them separately. */ if (regno == FRAME_POINTER_REGNUM || IS_ST_REG (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_REG (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_REG (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;}static 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]);}/* Write function prologue. */voidc4x_function_prologue (file, size) FILE *file; int size;{ int regno;/* 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 be needlessly push the frame pointer. */ int dont_push_ar3; /* For __assembler__ function don't build a prologue. */ if (c4x_assembler_function_p ()) { fprintf (file, "; *** Assembler Function ***\n"); return; } /* For __interrupt__ function build specific prologue. */ if (c4x_interrupt_function_p ()) { c4x_leaf_function = c4x_leaf_function_p (); fprintf (file, "; *** Interrupt Entry %s ***\n", c4x_leaf_function ? "(leaf)" : ""); fprintf (file, "\tpush\tst\n"); if (size) { fprintf (file, "\tpush\tar3\n\tldi\tsp,ar3\n"); /* FIXME: Assume ISR doesn't require more than 32767 words of local variables. */ if (size > 32767) error ("ISR %s requires %d words of local variables, " "maximum is 32767.", current_function_name, size); fprintf (file, "\taddi\t%d,sp\n", size); } for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (c4x_isr_reg_used_p (regno)) { fprintf (file, "\tpush\t%s\n", reg_names[regno]); if (IS_EXT_REG (regno)) /* save 32MSB of R0--R11 */ fprintf (file, "\tpushf\t%s\n", float_reg_names[regno]); } } /* 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]) fprintf (file, "\tandn\t0100h,st\n"); /* Reload DP reg if we are paranoid about some turkey violating small memory model rules. */ if (TARGET_SMALL && TARGET_PARANOID) fprintf (file, TARGET_C3X ? "\tldp\t@data_sec\n" : "\tldpk\t@data_sec\n"); } else { if (frame_pointer_needed) { if ((size != 0) || (current_function_args_size != 0) || (optimize < 2)) { fprintf (file, "\tpush\tar3\n"); fprintf (file, "\tldi\tsp,ar3\n"); 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) { fprintf (file, "\tldi\t%d,r1\n", size >> 16); fprintf (file, "\tlsh\t16,r1\n"); } else fprintf (file, "\tldhi\t%d,r1\n", size >> 16); fprintf (file, "\tor\t%d,r1\n", size & 0xffff); fprintf (file, "\taddi\tr1,sp\n"); } else if (size != 0) { /* Local vars take up less than 32767 words, so we can directly add the number. */ fprintf (file, "\taddi\t%d,sp\n", size); } for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (regs_ever_live[regno] && ! call_used_regs[regno]) { if ((regno == R6_REGNO) || (regno == R7_REGNO)) { /* R6 and R7 are saved as floating point */ if (TARGET_PRESERVE_FLOAT) fprintf (file, "\tpush\t%s\n", reg_names[regno]); fprintf (file, "\tpushf\t%s\n", float_reg_names[regno]); } else if ((! dont_push_ar3) || (regno != AR3_REGNO)) { fprintf (file, "\tpush\t%s\n", reg_names[regno]); } } } }}/* Write function epilogue. */voidc4x_function_epilogue (file, size) FILE *file; int size;{ int regno; int restore_count = 0; int delayed_jump = 0; int dont_pop_ar3; rtx insn; insn = get_last_insn (); if (insn && GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) return; /* For __assembler__ function build no epilogue. */ if (c4x_assembler_function_p ()) { fprintf (file, "\trets\n"); /* Play it safe */ return; }#ifdef FUNCTION_BLOCK_PROFILER_EXIT if (profile_block_flag == 2) { FUNCTION_BLOCK_PROFILER_EXIT (file); }#endif /* For __interrupt__ function build specific epilogue. */ if (c4x_interrupt_function_p ()) { for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; --regno) { if (! c4x_isr_reg_used_p (regno)) continue; if (IS_EXT_REG (regno)) fprintf (file, "\tpopf\t%s\n", float_reg_names[regno]); fprintf (file, "\tpop\t%s\n", reg_names[regno]); } if (size) { fprintf (file, "\tsubi\t%d,sp\n", size); fprintf (file, "\tpop\tar3\n"); } fprintf (file, "\tpop\tst\n"); fprintf (file, "\treti\n"); } else { if (frame_pointer_needed) { if ((size != 0) || (current_function_args_size != 0) || (optimize < 2)) { /* R2 holds the return value. */ fprintf (file, "\tldi\t*-ar3(1),r2\n"); /* We already have the return value and the fp, so we need to add those to the stack. */ size += 2; delayed_jump = 1; restore_count = 1; dont_pop_ar3 = 1; } else { /* Since ar3 is not used for anything, we don't need to pop it. */ dont_pop_ar3 = 1; } } else { dont_pop_ar3 = 0; /* If we use ar3, we need to pop it */ if (size || current_function_args_size) { /* If we are ommitting 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; } } /* Now get the number of instructions required to restore the registers. */ for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) { if ((regs_ever_live[regno] && ! call_used_regs[regno]) && ((! dont_pop_ar3) || (regno != AR3_REGNO))) { restore_count++; if (TARGET_PRESERVE_FLOAT && ((regno == R6_REGNO) || (regno == R7_REGNO))) restore_count++; } } /* Get the number of instructions required to restore the stack. */ if (size > 32767) restore_count += (TARGET_C3X ? 4 : 3); else if (size != 0) restore_count += 1; if (delayed_jump && (restore_count < 3)) { /* We don't have enough instructions to account for the delayed branch, so put some nops in. */ fprintf (file, "\tbud\tr2\n"); while (restore_count < 3) { fprintf (file, "\tnop\n"); restore_count++; } restore_count = 0; } /* Now restore the saved registers, putting in the delayed branch where required. */ for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) { if (regs_ever_live[regno] && ! call_used_regs[regno]) { if (regno == AR3_REGNO && dont_pop_ar3) continue; if (delayed_jump && (restore_count == 3)) fprintf (file, "\tbud\tr2\n"); /* R6 and R7 are saved as floating point. */ if ((regno == R6_REGNO) || (regno == R7_REGNO)) { fprintf (file, "\tpopf\t%s\n", float_reg_names[regno]); if (TARGET_PRESERVE_FLOAT) { restore_count--; if (delayed_jump && (restore_count == 3)) fprintf (file, "\tbud\tr2\n"); fprintf (file, "\tpop\t%s\n", reg_names[regno]); } } else fprintf (file, "\tpop\t%s\n", reg_names[regno]); restore_count--; } } if (delayed_jump && (restore_count == 3)) fprintf (file, "\tbud\tr2\n"); if (frame_pointer_needed) { if ((size != 0) || (current_function_args_size != 0) || (optimize < 2)) { /* Restore the old FP. */ fprintf (file, "\tldi\t*ar3,ar3\n"); restore_count--; if (delayed_jump && (restore_count == 3)) fprintf (file, "\tbud\tr2\n"); } } if (size > 32767) { /* Local vars are too big, it will take multiple operations to decrement SP. */ if (TARGET_C3X) { fprintf (file, "\tldi\t%d,r3\n", size >> 16); if (delayed_jump) fprintf (file, "\tbud\tr2\n"); fprintf (file, "\tlsh\t16,r3\n"); } else fprintf (file, "\tldhi\t%d,r3\n", size >> 16); fprintf (file, "\tor\t%d,r3\n", size & 0xffff); fprintf (file, "\tsubi\tr3,sp\n"); } else if (size != 0) { /* Local vars take up less than 32768 words, so we can directly subtract the number. */ fprintf (file, "\tsubi\t%d,sp\n", size); } if (! delayed_jump) fprintf (file, "\trets\n"); }}intc4x_null_epilogue_p (){ int regno; if (reload_completed && ! c4x_assembler_function_p () && ! c4x_interrupt_function_p () && ! current_function_calls_alloca && ! current_function_args_size && ! (profile_block_flag == 2) && ! (optimize < 2) && ! get_frame_size ()) { for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) if (regs_ever_live[regno] && ! call_used_regs[regno] && (regno != AR3_REGNO)) return 0; return 1; } return 0;}intc4x_emit_move_sequence (operands, mode) rtx *operands; enum machine_mode mode; { rtx op0 = operands[0]; rtx op1 = operands[1]; if (! reload_in_progress && ! REG_P (op0) && ! REG_P (op1) && ! (stik_const_operand (op1, mode) && ! push_operand (op0, mode))) op1 = force_reg (mode, op1); if (GET_CODE (op1) == LO_SUM && GET_MODE (op1) == Pmode && dp_reg_operand (XEXP (op1, 0), mode)) { /* expand_increment will sometimes create a LO_SUM immediate address. */ op1 = XEXP (op1, 1); } else if (symbolic_address_operand (op1, mode))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -