📄 sh.c
字号:
{ return output_branchy_insn (NE, "bt\t%l9\n\tfcmp/eq\t%1,%0", insn, operands);}/* Output the start of the assembler file. */static voidsh_file_start (void){ default_file_start ();#ifdef SYMBIAN /* Declare the .directive section before it is used. */ fputs ("\t.section .directive, \"SM\", @progbits, 1\n", asm_out_file); fputs ("\t.asciz \"#<SYMEDIT>#\\n\"\n", asm_out_file);#endif if (TARGET_ELF) /* We need to show the text section with the proper attributes as in TEXT_SECTION_ASM_OP, before dwarf2out emits it without attributes in TEXT_SECTION_ASM_OP, else GAS will complain. We can teach GAS specifically about the default attributes for our choice of text section, but then we would have to change GAS again if/when we change the text section name. */ fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); else /* Switch to the data section so that the coffsem symbol isn't in the text section. */ data_section (); if (TARGET_LITTLE_ENDIAN) fputs ("\t.little\n", asm_out_file); if (!TARGET_ELF) { if (TARGET_SHCOMPACT) fputs ("\t.mode\tSHcompact\n", asm_out_file); else if (TARGET_SHMEDIA) fprintf (asm_out_file, "\t.mode\tSHmedia\n\t.abi\t%i\n", TARGET_SHMEDIA64 ? 64 : 32); }}/* Check if PAT includes UNSPEC_CALLER unspec pattern. */static boolunspec_caller_rtx_p (rtx pat){ switch (GET_CODE (pat)) { case CONST: return unspec_caller_rtx_p (XEXP (pat, 0)); case PLUS: case MINUS: if (unspec_caller_rtx_p (XEXP (pat, 0))) return true; return unspec_caller_rtx_p (XEXP (pat, 1)); case UNSPEC: if (XINT (pat, 1) == UNSPEC_CALLER) return true; default: break; } return false;}/* Indicate that INSN cannot be duplicated. This is true for insn that generates a unique label. */static boolsh_cannot_copy_insn_p (rtx insn){ rtx pat; if (!reload_completed || !flag_pic) return false; if (GET_CODE (insn) != INSN) return false; if (asm_noperands (insn) >= 0) return false; pat = PATTERN (insn); if (GET_CODE (pat) != SET) return false; pat = SET_SRC (pat); if (unspec_caller_rtx_p (pat)) return true; return false;}/* Actual number of instructions used to make a shift by N. */static const char ashiftrt_insns[] = { 0,1,2,3,4,5,8,8,8,8,8,8,8,8,8,8,2,3,4,5,8,8,8,8,8,8,8,8,8,8,8,2};/* Left shift and logical right shift are the same. */static const char shift_insns[] = { 0,1,1,2,2,3,3,4,1,2,2,3,3,4,3,3,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3};/* Individual shift amounts needed to get the above length sequences. One bit right shifts clobber the T bit, so when possible, put one bit shifts in the middle of the sequence, so the ends are eligible for branch delay slots. */static const short shift_amounts[32][5] = { {0}, {1}, {2}, {2, 1}, {2, 2}, {2, 1, 2}, {2, 2, 2}, {2, 2, 1, 2}, {8}, {8, 1}, {8, 2}, {8, 1, 2}, {8, 2, 2}, {8, 2, 1, 2}, {8, -2, 8}, {8, -1, 8}, {16}, {16, 1}, {16, 2}, {16, 1, 2}, {16, 2, 2}, {16, 2, 1, 2}, {16, -2, 8}, {16, -1, 8}, {16, 8}, {16, 1, 8}, {16, 8, 2}, {16, 8, 1, 2}, {16, 8, 2, 2}, {16, -1, -2, 16}, {16, -2, 16}, {16, -1, 16}};/* Likewise, but for shift amounts < 16, up to three highmost bits might be clobbered. This is typically used when combined with some kind of sign or zero extension. */static const char ext_shift_insns[] = { 0,1,1,2,2,3,2,2,1,2,2,3,3,3,2,2,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3};static const short ext_shift_amounts[32][4] = { {0}, {1}, {2}, {2, 1}, {2, 2}, {2, 1, 2}, {8, -2}, {8, -1}, {8}, {8, 1}, {8, 2}, {8, 1, 2}, {8, 2, 2}, {16, -2, -1}, {16, -2}, {16, -1}, {16}, {16, 1}, {16, 2}, {16, 1, 2}, {16, 2, 2}, {16, 2, 1, 2}, {16, -2, 8}, {16, -1, 8}, {16, 8}, {16, 1, 8}, {16, 8, 2}, {16, 8, 1, 2}, {16, 8, 2, 2}, {16, -1, -2, 16}, {16, -2, 16}, {16, -1, 16}};/* Assuming we have a value that has been sign-extended by at least one bit, can we use the ext_shift_amounts with the last shift turned to an arithmetic shift to shift it by N without data loss, and quicker than by other means? */#define EXT_SHIFT_SIGNED(n) (((n) | 8) == 15)/* This is used in length attributes in sh.md to help compute the length of arbitrary constant shift instructions. */intshift_insns_rtx (rtx insn){ rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); int shift_count = INTVAL (XEXP (set_src, 1)); enum rtx_code shift_code = GET_CODE (set_src); switch (shift_code) { case ASHIFTRT: return ashiftrt_insns[shift_count]; case LSHIFTRT: case ASHIFT: return shift_insns[shift_count]; default: gcc_unreachable (); }}/* Return the cost of a shift. */static inline intshiftcosts (rtx x){ int value; if (TARGET_SHMEDIA) return 1; if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) { if (GET_MODE (x) == DImode && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 1) return 2; /* Everything else is invalid, because there is no pattern for it. */ return 10000; } /* If shift by a non constant, then this will be expensive. */ if (GET_CODE (XEXP (x, 1)) != CONST_INT) return SH_DYNAMIC_SHIFT_COST; value = INTVAL (XEXP (x, 1)); /* Otherwise, return the true cost in instructions. */ if (GET_CODE (x) == ASHIFTRT) { int cost = ashiftrt_insns[value]; /* If SH3, then we put the constant in a reg and use shad. */ if (cost > 1 + SH_DYNAMIC_SHIFT_COST) cost = 1 + SH_DYNAMIC_SHIFT_COST; return cost; } else return shift_insns[value];}/* Return the cost of an AND operation. */static inline intandcosts (rtx x){ int i; /* Anding with a register is a single cycle and instruction. */ if (GET_CODE (XEXP (x, 1)) != CONST_INT) return 1; i = INTVAL (XEXP (x, 1)); if (TARGET_SHMEDIA) { if ((GET_CODE (XEXP (x, 1)) == CONST_INT && CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)))) || EXTRA_CONSTRAINT_C16 (XEXP (x, 1))) return 1; else return 2; } /* These constants are single cycle extu.[bw] instructions. */ if (i == 0xff || i == 0xffff) return 1; /* Constants that can be used in an and immediate instruction in a single cycle, but this requires r0, so make it a little more expensive. */ if (CONST_OK_FOR_K08 (i)) return 2; /* Constants that can be loaded with a mov immediate and an and. This case is probably unnecessary. */ if (CONST_OK_FOR_I08 (i)) return 2; /* Any other constants requires a 2 cycle pc-relative load plus an and. This case is probably unnecessary. */ return 3;}/* Return the cost of an addition or a subtraction. */static inline intaddsubcosts (rtx x){ /* Adding a register is a single cycle insn. */ if (GET_CODE (XEXP (x, 1)) == REG || GET_CODE (XEXP (x, 1)) == SUBREG) return 1; /* Likewise for small constants. */ if (GET_CODE (XEXP (x, 1)) == CONST_INT && CONST_OK_FOR_ADD (INTVAL (XEXP (x, 1)))) return 1; if (TARGET_SHMEDIA) switch (GET_CODE (XEXP (x, 1))) { case CONST: case LABEL_REF: case SYMBOL_REF: return TARGET_SHMEDIA64 ? 5 : 3; case CONST_INT: if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)))) return 2; else if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)) >> 16)) return 3; else if (CONST_OK_FOR_I16 ((INTVAL (XEXP (x, 1)) >> 16) >> 16)) return 4; /* Fall through. */ default: return 5; } /* Any other constant requires a 2 cycle pc-relative load plus an addition. */ return 3;}/* Return the cost of a multiply. */static inline intmultcosts (rtx x ATTRIBUTE_UNUSED){ if (sh_multcost >= 0) return sh_multcost; if (TARGET_SHMEDIA) /* ??? We have a mul insn, but it has a latency of three, and doesn't accept constants. Ideally, we would use a cost of one or two and add the cost of the operand, but disregard the latter when inside loops and loop invariant code motion is still to follow. Using a multiply first and splitting it later if it's a loss doesn't work because of different sign / zero extension semantics of multiplies vs. shifts. */ return TARGET_SMALLCODE ? 2 : 3; if (TARGET_SH2) { /* We have a mul insn, so we can never take more than the mul and the read of the mac reg, but count more because of the latency and extra reg usage. */ if (TARGET_SMALLCODE) return 2; return 3; } /* If we're aiming at small code, then just count the number of insns in a multiply call sequence. */ if (TARGET_SMALLCODE) return 5; /* Otherwise count all the insns in the routine we'd be calling too. */ return 20;}/* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */static boolsh_rtx_costs (rtx x, int code, int outer_code, int *total){ switch (code) { case CONST_INT: if (TARGET_SHMEDIA) { if (INTVAL (x) == 0) *total = 0; else if (outer_code == AND && and_operand ((x), DImode)) *total = 0; else if ((outer_code == IOR || outer_code == XOR || outer_code == PLUS) && CONST_OK_FOR_I10 (INTVAL (x))) *total = 0; else if (CONST_OK_FOR_I16 (INTVAL (x))) *total = COSTS_N_INSNS (outer_code != SET); else if (CONST_OK_FOR_I16 (INTVAL (x) >> 16)) *total = COSTS_N_INSNS ((outer_code != SET) + 1); else if (CONST_OK_FOR_I16 ((INTVAL (x) >> 16) >> 16)) *total = COSTS_N_INSNS (3); else *total = COSTS_N_INSNS (4); return true; } if (CONST_OK_FOR_I08 (INTVAL (x))) *total = 0; else if ((outer_code == AND || outer_code == IOR || outer_code == XOR) && CONST_OK_FOR_K08 (INTVAL (x))) *total = 1; else *total = 8; return true; case CONST: case LABEL_REF: case SYMBOL_REF: if (TARGET_SHMEDIA64) *total = COSTS_N_INSNS (4); else if (TARGET_SHMEDIA32) *total = COSTS_N_INSNS (2); else *total = 5; return true; case CONST_DOUBLE: if (TARGET_SHMEDIA) *total = COSTS_N_INSNS (4); else *total = 10; return true; case CONST_VECTOR: if (x == CONST0_RTX (GET_MODE (x))) *total = 0; else if (sh_1el_vec (x, VOIDmode)) *total = outer_code != SET; if (sh_rep_vec (x, VOIDmode)) *total = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + 3) / 4 + (outer_code != SET)); *total = COSTS_N_INSNS (3) + (outer_code != SET); return true; case PLUS: case MINUS: *total = COSTS_N_INSNS (addsubcosts (x)); return true; case AND: *total = COSTS_N_INSNS (andcosts (x)); return true; case MULT: *total = COSTS_N_INSNS (multcosts (x)); return true; case ASHIFT: case ASHIFTRT: case LSHIFTRT: *total = COSTS_N_INSNS (shiftcosts (x)); return true; case DIV: case UDIV: case MOD: case UMOD: *total = COSTS_N_INSNS (20); return true; case PARALLEL: if (sh_1el_vec (x, VOIDmode)) *total = outer_code != SET; if (sh_rep_vec (x, VOIDmode)) *total = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + 3) / 4 + (outer_code != SET)); *total = COSTS_N_INSNS (3) + (outer_code != SET); return true; case FLOAT: case FIX: *total = 100; return true; default: return false; }}/* Compute
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -