📄 arc.c
字号:
if (epilogue_delay) { final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1); } } /* Emit the return instruction. */ { static const int regs[4] = { 0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM }; fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]); } /* If the only register saved is the return address, we need a nop, unless we have an instruction to put into it. Otherwise we don't since reloading multiple registers doesn't reference the register being loaded. */ if (ARC_INTERRUPT_P (fn_type)) fprintf (file, "\tadd %s,%s,16\n", sp_str, sp_str); else if (epilogue_delay != NULL_RTX) { if (frame_pointer_needed && !fp_restored_p) abort (); if (restored < size) abort (); final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1); } else if (frame_pointer_needed && !fp_restored_p) { if (!SMALL_INT (frame_size)) abort (); /* Note that we restore fp and sp here! */ fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size); } else if (restored < size) { if (!SMALL_INT (size - restored)) abort (); fprintf (file, "\tadd %s,%s,%d\n", sp_str, sp_str, size - restored); } else fprintf (file, "\tnop\n"); } /* Reset state info for each function. */ current_frame_info = zero_frame_info; arc_compute_function_type (NULL_TREE);}/* Define the number of delay slots needed for the function epilogue. Interrupt handlers can't have any epilogue delay slots (it's always needed for something else, I think). For normal functions, we have to worry about using call-saved regs as they'll be restored before the delay slot insn. Functions with non-empty frames already have enough choices for the epilogue delay slot so for now we only consider functions with empty frames. */intarc_delay_slots_for_epilogue (){ if (arc_compute_function_type (current_function_decl) != ARC_FUNCTION_NORMAL) return 0; if (!current_frame_info.initialized) (void) arc_compute_frame_size (get_frame_size ()); if (current_frame_info.total_size == 0) return 1; return 0;}/* Return true if TRIAL is a valid insn for the epilogue delay slot. Any single length instruction which doesn't reference the stack or frame pointer or any call-saved register is OK. SLOT will always be 0. */intarc_eligible_for_epilogue_delay (trial, slot) rtx trial; int slot;{ if (slot != 0) abort (); if (get_attr_length (trial) == 1 /* If registers where saved, presumably there's more than enough possibilities for the delay slot. The alternative is something more complicated (of course, if we expanded the epilogue as rtl this problem would go away). */ /* ??? Note that this will always be true since only functions with empty frames have epilogue delay slots. See arc_delay_slots_for_epilogue. */ && current_frame_info.gmask == 0 && ! reg_mentioned_p (stack_pointer_rtx, PATTERN (trial)) && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (trial))) return 1; return 0;}/* PIC *//* Emit special PIC prologues and epilogues. */voidarc_finalize_pic (){ /* nothing to do */}/* Return true if OP is a shift operator. */intshift_operator (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ switch (GET_CODE (op)) { case ASHIFTRT: case LSHIFTRT: case ASHIFT: return 1; default: return 0; }}/* Output the assembler code for doing a shift. We go to a bit of trouble to generate efficient code as the ARC only has single bit shifts. This is taken from the h8300 port. We only have one mode of shifting and can't access individual bytes like the h8300 can, so this is greatly simplified (at the expense of not generating hyper- efficient code). This function is not used if the variable shift insns are present. *//* ??? We assume the output operand is the same as operand 1. This can be optimized (deleted) in the case of 1 bit shifts. *//* ??? We use the loop register here. We don't use it elsewhere (yet) and using it here will give us a chance to play with it. */const char *output_shift (operands) rtx *operands;{ rtx shift = operands[3]; enum machine_mode mode = GET_MODE (shift); enum rtx_code code = GET_CODE (shift); const char *shift_one; if (mode != SImode) abort (); switch (code) { case ASHIFT: shift_one = "asl %0,%0"; break; case ASHIFTRT: shift_one = "asr %0,%0"; break; case LSHIFTRT: shift_one = "lsr %0,%0"; break; default: abort (); } if (GET_CODE (operands[2]) != CONST_INT) { if (optimize) output_asm_insn ("mov lp_count,%2", operands); else output_asm_insn ("mov %4,%2", operands); goto shiftloop; } else { int n = INTVAL (operands[2]); /* If the count is negative, make it 0. */ if (n < 0) n = 0; /* If the count is too big, truncate it. ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to do the intuitive thing. */ else if (n > GET_MODE_BITSIZE (mode)) n = GET_MODE_BITSIZE (mode); /* First see if we can do them inline. */ if (n <= 8) { while (--n >= 0) output_asm_insn (shift_one, operands); } /* See if we can use a rotate/and. */ else if (n == BITS_PER_WORD - 1) { switch (code) { case ASHIFT : output_asm_insn ("and %0,%0,1\n\tror %0,%0", operands); break; case ASHIFTRT : /* The ARC doesn't have a rol insn. Use something else. */ output_asm_insn ("asl.f 0,%0\n\tsbc %0,0,0", operands); break; case LSHIFTRT : /* The ARC doesn't have a rol insn. Use something else. */ output_asm_insn ("asl.f 0,%0\n\tadc %0,0,0", operands); break; default: break; } } /* Must loop. */ else { char buf[100]; if (optimize) output_asm_insn ("mov lp_count,%c2", operands); else output_asm_insn ("mov %4,%c2", operands); shiftloop: if (optimize) { if (flag_pic) sprintf (buf, "lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start", ASM_COMMENT_START); else sprintf (buf, "mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2", ASM_COMMENT_START); output_asm_insn (buf, operands); output_asm_insn ("sr %4,[lp_start]", operands); output_asm_insn ("add %4,%4,1", operands); output_asm_insn ("sr %4,[lp_end]", operands); output_asm_insn ("nop\n\tnop", operands); if (flag_pic) fprintf (asm_out_file, "\t%s single insn loop\n", ASM_COMMENT_START); else fprintf (asm_out_file, "1:\t%s single insn loop\n", ASM_COMMENT_START); output_asm_insn (shift_one, operands); } else { fprintf (asm_out_file, "1:\t%s begin shift loop\n", ASM_COMMENT_START); output_asm_insn ("sub.f %4,%4,1", operands); output_asm_insn ("nop", operands); output_asm_insn ("bn.nd 2f", operands); output_asm_insn (shift_one, operands); output_asm_insn ("b.nd 1b", operands); fprintf (asm_out_file, "2:\t%s end shift loop\n", ASM_COMMENT_START); } } } return "";}/* Nested function support. *//* Emit RTL insns to initialize the variable parts of a trampoline. FNADDR is an RTX for the address of the function's pure code. CXT is an RTX for the static chain value for the function. */voidarc_initialize_trampoline (tramp, fnaddr, cxt) rtx tramp ATTRIBUTE_UNUSED, fnaddr ATTRIBUTE_UNUSED, cxt ATTRIBUTE_UNUSED;{}/* Set the cpu type and print out other fancy things, at the top of the file. */voidarc_asm_file_start (file) FILE *file;{ fprintf (file, "\t.cpu %s\n", arc_cpu_string);}/* Print operand X (an rtx) in assembler syntax to file FILE. CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. For `%' followed by punctuation, CODE is the punctuation and X is null. */voidarc_print_operand (file, x, code) FILE *file; rtx x; int code;{ switch (code) { case '#' : /* Conditional branches. For now these are equivalent. */ case '*' : /* Unconditional branches. Output the appropriate delay slot suffix. */ if (!final_sequence || XVECLEN (final_sequence, 0) == 1) { /* There's nothing in the delay slot. */ fputs (".nd", file); } else { rtx jump = XVECEXP (final_sequence, 0, 0); rtx delay = XVECEXP (final_sequence, 0, 1); if (INSN_ANNULLED_BRANCH_P (jump)) fputs (INSN_FROM_TARGET_P (delay) ? ".jd" : ".nd", file); else fputs (".d", file); } return; case '?' : /* with leading "." */ case '!' : /* without leading "." */ /* This insn can be conditionally executed. See if the ccfsm machinery says it should be conditionalized. */ if (arc_ccfsm_state == 3 || arc_ccfsm_state == 4) { /* Is this insn in a delay slot? */ if (final_sequence && XVECLEN (final_sequence, 0) == 2) { rtx insn = XVECEXP (final_sequence, 0, 1); /* If the insn is annulled and is from the target path, we need to inverse the condition test. */ if (INSN_ANNULLED_BRANCH_P (insn)) { if (INSN_FROM_TARGET_P (insn)) fprintf (file, "%s%s", code == '?' ? "." : "", arc_condition_codes[ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc)]); else fprintf (file, "%s%s", code == '?' ? "." : "", arc_condition_codes[arc_ccfsm_current_cc]); } else { /* This insn is executed for either path, so don't conditionalize it at all. */ ; /* nothing to do */ } } else { /* This insn isn't in a delay slot. */ fprintf (file, "%s%s", code == '?' ? "." : "", arc_condition_codes[arc_ccfsm_current_cc]); } } return; case '~' : /* Output a nop if we're between a set of the condition codes, and a conditional branch. */ if (last_insn_set_cc_p) fputs ("nop\n\t", file); return; case 'd' : fputs (arc_condition_codes[get_arc_condition_code (x)], file); return; case 'D' : fputs (arc_condition_codes[ARC_INVERSE_CONDITION_CODE (get_arc_condition_code (x))], file); return; case 'R' : /* Write second word of DImode or DFmode reference, register or memory. */ if (GET_CODE (x) == REG) fputs (reg_names[REGNO (x)+1], file); else if (GET_CODE (x) == MEM) { fputc ('[', file); /* Handle possible auto-increment. Since it is pre-increment and we have already done it, we can just use an offset of four. */ /* ??? This is taken from rs6000.c I think. I don't think it is currently necessary, but keep it around. */ if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4)); else output_address (plus_constant (XEXP (x, 0), 4)); fputc (']', file); } else output_operand_lossage ("invalid operand to %%R code"); return; case 'S' : if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x)) || GET_CODE (x) == LABEL_REF) { fprintf (file, "%%st("); output_addr_const (file, x); fprintf (file, ")"); return; } break; case 'H' : case 'L' : if (GET_CODE (x) == REG) { /* L = least significant word, H = most significant word */ if ((TARGET_BIG_ENDIAN != 0) ^ (code == 'L')) fputs (reg_names[REGNO (x)], file); else fputs (reg_names[REGNO (x)+1], file); } else if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) { rtx first, second; split_double (x, &first, &second); fprintf (file, "0x%08lx", (long)(code == 'L' ? INTVAL (first) : INTVAL (second))); } else output_operand_lossage ("invalid operand to %%H/%%L code"); return; case 'A' : { char str[30]; if (GET_CODE (x) != CONST_DOUBLE || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT) abort (); real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1); fprintf (file, "%s", str); return; } case 'U' : /* Output a load/store with update indicator if appropriate. */ if (GET_CODE (x) == MEM) { if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) fputs (".a", file); } else output_operand_lossage ("invalid operand to %%U code"); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -