📄 500-avr32.patch
字号:
++ return true;+ }++ return default_assemble_integer (x, size, aligned_p);+}++/*+ * This target hook describes the relative costs of RTL expressions.+ *+ * The cost may depend on the precise form of the expression, which is+ * available for examination in x, and the rtx code of the expression+ * in which it is contained, found in outer_code. code is the+ * expression code--redundant, since it can be obtained with GET_CODE+ * (x).+ *+ * In implementing this hook, you can use the construct COSTS_N_INSNS+ * (n) to specify a cost equal to n fast instructions.+ *+ * On entry to the hook, *total contains a default estimate for the+ * cost of the expression. The hook should modify this value as+ * necessary. Traditionally, the default costs are COSTS_N_INSNS (5)+ * for multiplications, COSTS_N_INSNS (7) for division and modulus+ * operations, and COSTS_N_INSNS (1) for all other operations.+ *+ * When optimizing for code size, i.e. when optimize_size is non-zero,+ * this target hook should be used to estimate the relative size cost+ * of an expression, again relative to COSTS_N_INSNS.+ *+ * The hook returns true when all subexpressions of x have been+ * processed, and false when rtx_cost should recurse.+ */++/* Worker routine for avr32_rtx_costs. */+static inline int+avr32_rtx_costs_1 (rtx x, enum rtx_code code ATTRIBUTE_UNUSED,+ enum rtx_code outer ATTRIBUTE_UNUSED)+{+ enum machine_mode mode = GET_MODE (x);++ switch (GET_CODE (x))+ {+ case MEM:+ /* Using pre decrement / post increment memory operations on the+ avr32_uc architecture means that two writebacks must be performed+ and hence two cycles are needed. */+ if (!optimize_size+ && GET_MODE_SIZE (mode) <= 2 * UNITS_PER_WORD+ && avr32_arch->arch_type == ARCH_TYPE_AVR32_UC+ && (GET_CODE (XEXP (x, 0)) == PRE_DEC+ || GET_CODE (XEXP (x, 0)) == POST_INC))+ return COSTS_N_INSNS (4);++ /* Memory costs quite a lot for the first word, but subsequent words+ load at the equivalent of a single insn each. */+ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)+ return COSTS_N_INSNS (2 + (GET_MODE_SIZE (mode) / UNITS_PER_WORD));++ return COSTS_N_INSNS (3);+ case SYMBOL_REF:+ case CONST:+ /* These are valid for the pseudo insns: lda.w and call which operates+ on direct addresses. We assume that the cost of a lda.w is the same+ as the cost of a ld.w insn. */+ return (outer == SET) ? COSTS_N_INSNS (3) : COSTS_N_INSNS (1);+ case DIV:+ case MOD:+ case UDIV:+ case UMOD:+ return optimize_size ? COSTS_N_INSNS (1) : COSTS_N_INSNS (16);++ case ROTATE:+ case ROTATERT:+ if (mode == TImode)+ return COSTS_N_INSNS (100);++ if (mode == DImode)+ return COSTS_N_INSNS (10);+ return COSTS_N_INSNS (4);+ case ASHIFT:+ case LSHIFTRT:+ case ASHIFTRT:+ case NOT:+ if (mode == TImode)+ return COSTS_N_INSNS (10);++ if (mode == DImode)+ return COSTS_N_INSNS (4);+ return COSTS_N_INSNS (1);+ case PLUS:+ case MINUS:+ case NEG:+ case COMPARE:+ case ABS:+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)+ return COSTS_N_INSNS (100);++ if (mode == TImode)+ return COSTS_N_INSNS (50);++ if (mode == DImode)+ return COSTS_N_INSNS (2);+ return COSTS_N_INSNS (1);++ case MULT:+ {+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)+ return COSTS_N_INSNS (300);++ if (mode == TImode)+ return COSTS_N_INSNS (16);++ if (mode == DImode)+ return COSTS_N_INSNS (4);++ if (mode == HImode)+ return COSTS_N_INSNS (2);++ return COSTS_N_INSNS (3);+ }+ case IF_THEN_ELSE:+ if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)+ return COSTS_N_INSNS (4);+ return COSTS_N_INSNS (1);+ case SIGN_EXTEND:+ case ZERO_EXTEND:+ /* Sign/Zero extensions of registers cost quite much since these+ instrcutions only take one register operand which means that gcc+ often must insert some move instrcutions */+ if (mode == QImode || mode == HImode)+ return (COSTS_N_INSNS (GET_CODE (XEXP (x, 0)) == MEM ? 0 : 1));+ return COSTS_N_INSNS (4);+ case UNSPEC:+ /* divmod operations */+ if (XINT (x, 1) == UNSPEC_UDIVMODSI4_INTERNAL+ || XINT (x, 1) == UNSPEC_DIVMODSI4_INTERNAL)+ {+ return optimize_size ? COSTS_N_INSNS (1) : COSTS_N_INSNS (16);+ }+ /* Fallthrough */+ default:+ return COSTS_N_INSNS (1);+ }+}++static bool+avr32_rtx_costs (rtx x, int code, int outer_code, int *total)+{+ *total = avr32_rtx_costs_1 (x, code, outer_code);+ return true;+}+++bool+avr32_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)+{+ /* Do not want symbols in the constant pool when compiling pic or if using+ address pseudo instructions. */+ return ((flag_pic || TARGET_HAS_ASM_ADDR_PSEUDOS)+ && avr32_find_symbol (x) != NULL_RTX);+}+++/* Table of machine attributes. */+const struct attribute_spec avr32_attribute_table[] = {+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */+ /* Interrupt Service Routines have special prologue and epilogue+ requirements. */+ {"isr", 0, 1, false, false, false, avr32_handle_isr_attribute},+ {"interrupt", 0, 1, false, false, false, avr32_handle_isr_attribute},+ {"acall", 0, 1, false, true, true, avr32_handle_acall_attribute},+ {"naked", 0, 0, true, false, false, avr32_handle_fndecl_attribute},+ {NULL, 0, 0, false, false, false, NULL}+};+++typedef struct+{+ const char *const arg;+ const unsigned long return_value;+}+isr_attribute_arg;++static const isr_attribute_arg isr_attribute_args[] = {+ {"FULL", AVR32_FT_ISR_FULL},+ {"full", AVR32_FT_ISR_FULL},+ {"HALF", AVR32_FT_ISR_HALF},+ {"half", AVR32_FT_ISR_HALF},+ {"NONE", AVR32_FT_ISR_NONE},+ {"none", AVR32_FT_ISR_NONE},+ {"UNDEF", AVR32_FT_ISR_NONE},+ {"undef", AVR32_FT_ISR_NONE},+ {"SWI", AVR32_FT_ISR_NONE},+ {"swi", AVR32_FT_ISR_NONE},+ {NULL, AVR32_FT_ISR_NONE}+};++/* Returns the (interrupt) function type of the current+ function, or AVR32_FT_UNKNOWN if the type cannot be determined. */++static unsigned long+avr32_isr_value (tree argument)+{+ const isr_attribute_arg *ptr;+ const char *arg;++ /* No argument - default to ISR_NONE. */+ if (argument == NULL_TREE)+ return AVR32_FT_ISR_NONE;++ /* Get the value of the argument. */+ if (TREE_VALUE (argument) == NULL_TREE+ || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)+ return AVR32_FT_UNKNOWN;++ arg = TREE_STRING_POINTER (TREE_VALUE (argument));++ /* Check it against the list of known arguments. */+ for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)+ if (streq (arg, ptr->arg))+ return ptr->return_value;++ /* An unrecognized interrupt type. */+ return AVR32_FT_UNKNOWN;+}++++/*+These hooks specify assembly directives for creating certain kinds+of integer object. The TARGET_ASM_BYTE_OP directive creates a+byte-sized object, the TARGET_ASM_ALIGNED_HI_OP one creates an+aligned two-byte object, and so on. Any of the hooks may be+NULL, indicating that no suitable directive is available.++The compiler will print these strings at the start of a new line,+followed immediately by the object's initial value. In most cases,+the string should contain a tab, a pseudo-op, and then another tab.+*/+#undef TARGET_ASM_BYTE_OP+#define TARGET_ASM_BYTE_OP "\t.byte\t"+#undef TARGET_ASM_ALIGNED_HI_OP+#define TARGET_ASM_ALIGNED_HI_OP "\t.align 1\n\t.short\t"+#undef TARGET_ASM_ALIGNED_SI_OP+#define TARGET_ASM_ALIGNED_SI_OP "\t.align 2\n\t.int\t"+#undef TARGET_ASM_ALIGNED_DI_OP+#define TARGET_ASM_ALIGNED_DI_OP NULL+#undef TARGET_ASM_ALIGNED_TI_OP+#define TARGET_ASM_ALIGNED_TI_OP NULL+#undef TARGET_ASM_UNALIGNED_HI_OP+#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"+#undef TARGET_ASM_UNALIGNED_SI_OP+#define TARGET_ASM_UNALIGNED_SI_OP "\t.int\t"+#undef TARGET_ASM_UNALIGNED_DI_OP+#define TARGET_ASM_UNALIGNED_DI_OP NULL+#undef TARGET_ASM_UNALIGNED_TI_OP+#define TARGET_ASM_UNALIGNED_TI_OP NULL++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE avr32_sched_use_dfa_pipeline_interface++#undef TARGET_ASM_OUTPUT_MI_THUNK+#define TARGET_ASM_OUTPUT_MI_THUNK avr32_output_mi_thunk+++static void+avr32_output_mi_thunk (FILE * file,+ tree thunk ATTRIBUTE_UNUSED,+ HOST_WIDE_INT delta,+ HOST_WIDE_INT vcall_offset, tree function)+{+ int mi_delta = delta;+ int this_regno =+ (avr32_return_in_memory (DECL_RESULT (function), TREE_TYPE (function)) ?+ INTERNAL_REGNUM (11) : INTERNAL_REGNUM (12));+++ if (!avr32_const_ok_for_constraint_p (mi_delta, 'I', "Is21")+ || vcall_offset)+ {+ fprintf (file, "\tpushm\tr10\n");+ }+++ if (mi_delta != 0)+ {+ if (avr32_const_ok_for_constraint_p (mi_delta, 'I', "Is21"))+ {+ fprintf (file, "\tsub\t%s, -0x%x\n", reg_names[this_regno],+ mi_delta);+ }+ else+ {+ /* Immediate is larger than k21 we must make us a temp register by+ pushing a register to the stack. */+ fprintf (file, "\tmov\tr10, lo(%x)\n", mi_delta);+ fprintf (file, "\torh\tr10, hi(%x)\n", mi_delta);+ fprintf (file, "\tadd\t%s, r10\n", reg_names[this_regno]);+ }+ }+++ if (vcall_offset != 0)+ {+ fprintf (file, "\tld.w\tr10, %s[0]\n", reg_names[this_regno]);+ fprintf (file, "\tld.w\tr10, r10[%i]\n", (int) vcall_offset);+ fprintf (file, "\tadd\t%s, r10\n", reg_names[this_regno]);+ }+++ if (!avr32_const_ok_for_constraint_p (mi_delta, 'I', "Is21")+ || vcall_offset)+ {+ fprintf (file, "\tpopm\tr10\n");+ }++ if (flag_pic)+ {+ /* Don't know how we should do this!!! For now we'll just use an+ extended branch instruction and hope that the function will be+ reached. */+ fprintf (file, "\tbral\t");+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));+ fputc ('\n', file);+ }+ else+ {+ fprintf (file, "\tlddpc\tpc, 0f\n");+ fprintf (file, "\t.align 2\n");+ fputs ("0:\t.long\t", file);+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));+ fputc ('\n', file);+ }+}++/* Implements target hook vector_mode_supported. */+bool+avr32_vector_mode_supported (enum machine_mode mode)+{+ if ((mode == V2HImode) || (mode == V4QImode))+ return true;++ return false;+}+++#undef TARGET_INIT_LIBFUNCS+#define TARGET_INIT_LIBFUNCS avr32_init_libfuncs++#undef TARGET_INIT_BUILTINS+#define TARGET_INIT_BUILTINS avr32_init_builtins++#undef TARGET_EXPAND_BUILTIN+#define TARGET_EXPAND_BUILTIN avr32_expand_builtin++tree int_ftype_int, int_ftype_void, short_ftype_short, void_ftype_int_int,+ void_ftype_ptr_int;+tree void_ftype_int, void_ftype_void, int_ftype_ptr_int;+tree short_ftype_short, int_ftype_int_short, int_ftype_short_short,+ short_ftype_short_short;+tree int_ftype_int_int, longlong_ftype_int_short, longlong_ftype_short_short;+tree void_ftype_int_int_int_int_int, void_ftype_int_int_int;+tree longlong_ftype_int_int, void_ftype_int_int_longlong;+tree int_ftype_int_int_int, longlong_ftype_longlong_int_short;+tree longlong_ftype_longlong_short_short, int_ftype_int_short_short;++#define def_builtin(NAME, TYPE, CODE) \+ lang_hooks.builtin_function ((NAME), (TYPE), (CODE), \+ BUILT_IN_MD, NULL, NULL_TREE)++#define def_mbuiltin(MASK, NAME, TYPE, CODE) \+ do \+ { \+ if ((MASK)) \+ lang_hooks.builtin_function ((NAME), (TYPE), (CODE), \+ BUILT_IN_MD, NULL, NULL_TREE); \+ } \+ while (0)++struct builtin_description+{+ const unsigned int mask;+ const enum insn_code icode;+ const char *const name;+ const int code;+ const enum rtx_code comparison;+ const unsigned int flag;+ const tree *ftype;+};++static const struct builtin_description bdesc_2arg[] = {+#define DSP_BUILTIN(code, builtin, ftype) \+ { 1, CODE_FOR_##code, "__builtin_" #code , \+ AVR32_BUILTIN_##builtin, 0, 0, ftype }++ DSP_BUILTIN (mulsathh_h, MULSATHH_H, &short_ftype_short_short),+ DSP_BUILTIN (mulsathh_w, MULSATHH_W, &int_ftype_short_short),+ DSP_BUILTIN (mulsatrndhh_h, MULSATRNDHH_H, &short_ftype_short_short),+ DSP_BUILTIN (mulsatrndwh_w, MULSATRNDWH_W, &int_ftype_int_short),+ DSP_BUILTIN (mulsatwh_w, MULSATWH_W, &int_ftype_int_short),+ DSP_BUILTIN (satadd_h, SATADD_H, &short_ftype_short_short),+ DSP_BUILTIN (satsub_h, SATSUB_H, &short_ftype_short_short),+ DSP_BUILTIN (satadd_w, SATADD_W, &int_ftype_int_int),+ DSP_BUILTIN (satsub_w, SATSUB_W, &int_ftype_int_int),+ DSP_BUILTIN (mulwh_d, MULWH_D, &longlong_ftype_int_short),+ DSP_BUILTIN (mulnwh_d, MULNWH_D, &longlong_ftype_int_short)+};+++void+avr32_init_builtins (void)+{+ unsigned int i;+ const struct builtin_description *d;+ tree endlink = void_list_node;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -