📄 sh.c
字号:
#define TARGET_EXPAND_BUILTIN_SAVEREGS sh_builtin_saveregs#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS sh_setup_incoming_varargs#undef TARGET_STRICT_ARGUMENT_NAMING#define TARGET_STRICT_ARGUMENT_NAMING sh_strict_argument_naming#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED sh_pretend_outgoing_varargs_named#undef TARGET_MUST_PASS_IN_STACK#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE sh_pass_by_reference#undef TARGET_CALLEE_COPIES#define TARGET_CALLEE_COPIES sh_callee_copies#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES sh_arg_partial_bytes#undef TARGET_BUILD_BUILTIN_VA_LIST#define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list#undef TARGET_GIMPLIFY_VA_ARG_EXPR#define TARGET_GIMPLIFY_VA_ARG_EXPR sh_gimplify_va_arg_expr#undef TARGET_VECTOR_MODE_SUPPORTED_P#define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p#undef TARGET_PCH_VALID_P#define TARGET_PCH_VALID_P sh_pch_valid_p#undef TARGET_DWARF_CALLING_CONVENTION#define TARGET_DWARF_CALLING_CONVENTION sh_dwarf_calling_convention/* Return regmode weight for insn. */#define INSN_REGMODE_WEIGHT(INSN, MODE) regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)]/* Return current register pressure for regmode. */#define CURR_REGMODE_PRESSURE(MODE) curr_regmode_pressure[((MODE) == SImode) ? 0 : 1]#ifdef SYMBIAN#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO sh_symbian_encode_section_info#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING sh_symbian_strip_name_encoding#undef TARGET_CXX_IMPORT_EXPORT_CLASS#define TARGET_CXX_IMPORT_EXPORT_CLASS symbian_import_export_class#endif /* SYMBIAN */struct gcc_target targetm = TARGET_INITIALIZER;/* Print the operand address in x to the stream. */voidprint_operand_address (FILE *stream, rtx x){ switch (GET_CODE (x)) { case REG: case SUBREG: fprintf (stream, "@%s", reg_names[true_regnum (x)]); break; case PLUS: { rtx base = XEXP (x, 0); rtx index = XEXP (x, 1); switch (GET_CODE (index)) { case CONST_INT: fprintf (stream, "@(%d,%s)", (int) INTVAL (index), reg_names[true_regnum (base)]); break; case REG: case SUBREG: { int base_num = true_regnum (base); int index_num = true_regnum (index); fprintf (stream, "@(r0,%s)", reg_names[MAX (base_num, index_num)]); break; } default: debug_rtx (x); abort (); } } break; case PRE_DEC: fprintf (stream, "@-%s", reg_names[true_regnum (XEXP (x, 0))]); break; case POST_INC: fprintf (stream, "@%s+", reg_names[true_regnum (XEXP (x, 0))]); break; default: x = mark_constant_pool_use (x); output_addr_const (stream, x); break; }}/* Print operand x (an rtx) in assembler syntax to file stream according to modifier code. '.' print a .s if insn needs delay slot ',' print LOCAL_LABEL_PREFIX '@' print trap, rte or rts depending upon pragma interruptness '#' output a nop if there is nothing to put in the delay slot ''' print likelihood suffix (/u for unlikely). 'O' print a constant without the # 'R' print the LSW of a dp value - changes if in little endian 'S' print the MSW of a dp value - changes if in little endian 'T' print the next word of a dp value - same as 'R' in big endian mode. 'M' print an `x' if `m' will print `base,index'. 'N' print 'r63' if the operand is (const_int 0). 'd' print a V2SF reg as dN instead of fpN. 'm' print a pair `base,offset' or `base,index', for LD and ST. 'u' prints the lowest 16 bits of CONST_INT, as an unsigned value. 'o' output an operator. */voidprint_operand (FILE *stream, rtx x, int code){ switch (code) { case '.': if (final_sequence && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) && get_attr_length (XVECEXP (final_sequence, 0, 1))) fprintf (stream, ASSEMBLER_DIALECT ? "/s" : ".s"); break; case ',': fprintf (stream, "%s", LOCAL_LABEL_PREFIX); break; case '@': if (trap_exit) fprintf (stream, "trapa #%d", trap_exit); else if (sh_cfun_interrupt_handler_p ()) fprintf (stream, "rte"); else fprintf (stream, "rts"); break; case '#': /* Output a nop if there's nothing in the delay slot. */ if (dbr_sequence_length () == 0) fprintf (stream, "\n\tnop"); break; case '\'': { rtx note = find_reg_note (current_output_insn, REG_BR_PROB, 0); if (note && INTVAL (XEXP (note, 0)) * 2 < REG_BR_PROB_BASE) fputs ("/u", stream); break; } case 'O': x = mark_constant_pool_use (x); output_addr_const (stream, x); break; case 'R': fputs (reg_names[REGNO (x) + LSW], (stream)); break; case 'S': fputs (reg_names[REGNO (x) + MSW], (stream)); break; case 'T': /* Next word of a double. */ switch (GET_CODE (x)) { case REG: fputs (reg_names[REGNO (x) + 1], (stream)); break; case MEM: if (GET_CODE (XEXP (x, 0)) != PRE_DEC && GET_CODE (XEXP (x, 0)) != POST_INC) x = adjust_address (x, SImode, 4); print_operand_address (stream, XEXP (x, 0)); break; default: break; } break; case 'o': switch (GET_CODE (x)) { case PLUS: fputs ("add", stream); break; case MINUS: fputs ("sub", stream); break; case MULT: fputs ("mul", stream); break; case DIV: fputs ("div", stream); break; case EQ: fputs ("eq", stream); break; case NE: fputs ("ne", stream); break; case GT: case LT: fputs ("gt", stream); break; case GE: case LE: fputs ("ge", stream); break; case GTU: case LTU: fputs ("gtu", stream); break; case GEU: case LEU: fputs ("geu", stream); break; default: break; } break; case 'M': if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PLUS && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG)) fputc ('x', stream); break; case 'm': if (GET_CODE (x) != MEM) abort (); x = XEXP (x, 0); switch (GET_CODE (x)) { case REG: case SUBREG: print_operand (stream, x, 0); fputs (", 0", stream); break; case PLUS: print_operand (stream, XEXP (x, 0), 0); fputs (", ", stream); print_operand (stream, XEXP (x, 1), 0); break; default: abort (); } break; case 'd': if (GET_CODE (x) != REG || GET_MODE (x) != V2SFmode) abort (); fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1); break; case 'N': if (x == CONST0_RTX (GET_MODE (x))) { fprintf ((stream), "r63"); break; } goto default_output; case 'u': if (GET_CODE (x) == CONST_INT) { fprintf ((stream), "%u", (unsigned) INTVAL (x) & (0x10000 - 1)); break; } /* Fall through. */ default_output: default: switch (GET_CODE (x)) { /* FIXME: We need this on SHmedia32 because reload generates some sign-extended HI or QI loads into DImode registers but, because Pmode is SImode, the address ends up with a subreg:SI of the DImode register. Maybe reload should be fixed so as to apply alter_subreg to such loads? */ case SUBREG: if (SUBREG_BYTE (x) != 0 || GET_CODE (SUBREG_REG (x)) != REG) abort (); x = SUBREG_REG (x); /* Fall through. */ case REG: if (FP_REGISTER_P (REGNO (x)) && GET_MODE (x) == V16SFmode) fprintf ((stream), "mtrx%s", reg_names[REGNO (x)] + 2); else if (FP_REGISTER_P (REGNO (x)) && GET_MODE (x) == V4SFmode) fprintf ((stream), "fv%s", reg_names[REGNO (x)] + 2); else if (GET_CODE (x) == REG && GET_MODE (x) == V2SFmode) fprintf ((stream), "fp%s", reg_names[REGNO (x)] + 2); else if (FP_REGISTER_P (REGNO (x)) && GET_MODE_SIZE (GET_MODE (x)) > 4) fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1); else fputs (reg_names[REGNO (x)], (stream)); break; case MEM: output_address (XEXP (x, 0)); break; case CONST: if (TARGET_SHMEDIA && GET_CODE (XEXP (x, 0)) == SIGN_EXTEND && GET_MODE (XEXP (x, 0)) == DImode && GET_CODE (XEXP (XEXP (x, 0), 0)) == TRUNCATE && GET_MODE (XEXP (XEXP (x, 0), 0)) == HImode) { rtx val = XEXP (XEXP (XEXP (x, 0), 0), 0); fputc ('(', stream); if (GET_CODE (val) == ASHIFTRT) { fputc ('(', stream); if (GET_CODE (XEXP (val, 0)) == CONST) fputc ('(', stream); output_addr_const (stream, XEXP (val, 0)); if (GET_CODE (XEXP (val, 0)) == CONST) fputc (')', stream); fputs (" >> ", stream); output_addr_const (stream, XEXP (val, 1)); fputc (')', stream); } else { if (GET_CODE (val) == CONST) fputc ('(', stream); output_addr_const (stream, val); if (GET_CODE (val) == CONST) fputc (')', stream); } fputs (" & 65535)", stream); break; } /* Fall through. */ default: if (TARGET_SH1) fputc ('#', stream); output_addr_const (stream, x); break; } break; }}/* Like force_operand, but guarantees that VALUE ends up in TARGET. */static voidforce_into (rtx value, rtx target){ value = force_operand (value, target); if (! rtx_equal_p (value, target)) emit_insn (gen_move_insn (target, value));}/* Emit code to perform a block move. Choose the best method. OPERANDS[0] is the destination. OPERANDS[1] is the source. OPERANDS[2] is the size. OPERANDS[3] is the alignment safe to use. */intexpand_block_move (rtx *operands){ int align = INTVAL (operands[3]); int constp = (GET_CODE (operands[2]) == CONST_INT); int bytes = (constp ? INTVAL (operands[2]) : 0); if (! constp) return 0; /* If we could use mov.l to move words and dest is word-aligned, we can use movua.l for loads and still generate a relatively short and efficient sequence. */ if (TARGET_SH4A_ARCH && align < 4 && MEM_ALIGN (operands[0]) >= 32 && can_move_by_pieces (bytes, 32)) { rtx dest = copy_rtx (operands[0]); rtx src = copy_rtx (operands[1]); /* We could use different pseudos for each copied word, but since movua can only load into r0, it's kind of pointless. */ rtx temp = gen_reg_rtx (SImode); rtx src_addr = copy_addr_to_reg (XEXP (src, 0)); int copied = 0; while (copied + 4 <= bytes) { rtx to = adjust_address (dest, SImode, copied); rtx from = adjust_automodify_address (src, SImode, src_addr, copied); emit_insn (gen_movua (temp, from)); emit_move_insn (src_addr, plus_constant (src_addr, 4)); emit_move_insn (to, temp); copied += 4; } if (copied < bytes) move_by_pieces (adjust_address (dest, BLKmode, copied), adjust_automodify_address (src, BLKmode, src_addr, copied), bytes - copied, align, 0); return 1; } /* If it isn't a constant number of bytes, or if it doesn't have 4 byte alignment, or if it isn't a multiple of 4 bytes, then fail. */ if (align < 4 || (bytes % 4 != 0)) return 0; if (TARGET_HARD_SH4) { if (bytes < 12) return 0; else if (bytes == 12) { tree entry_name; rtx sym; rtx func_addr_rtx; rtx r4 = gen_rtx_REG (SImode, 4); rtx r5 = gen_rtx_REG (SImode, 5); entry_name = get_identifier ("__movmemSI12_i4"); sym = function_symbol (IDENTIFIER_POINTER (entry_name)); func_addr_rtx = copy_to_mode_reg (Pmode, sym); force_into (XEXP (operands[0], 0), r4); force_into (XEXP (operands[1], 0), r5); emit_insn (gen_block_move_real_i4 (func_addr_rtx)); return 1; } else if (! TARGET_SMALLCODE) { tree entry_name; rtx sym; rtx func_addr_rtx; int dwords; rtx r4 = gen_rtx_REG (SImode, 4);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -