diff options
Diffstat (limited to 'gcc/config/arc')
-rw-r--r-- | gcc/config/arc/arc-protos.h | 9 | ||||
-rw-r--r-- | gcc/config/arc/arc.c | 317 | ||||
-rw-r--r-- | gcc/config/arc/arc.h | 58 | ||||
-rw-r--r-- | gcc/config/arc/arc.md | 90 | ||||
-rw-r--r-- | gcc/config/arc/arc.opt | 6 | ||||
-rw-r--r-- | gcc/config/arc/constraints.md | 6 | ||||
-rw-r--r-- | gcc/config/arc/elf.h | 8 | ||||
-rw-r--r-- | gcc/config/arc/linux.h | 8 |
8 files changed, 271 insertions, 231 deletions
diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h index 93a64cfebac..8a9af46486e 100644 --- a/gcc/config/arc/arc-protos.h +++ b/gcc/config/arc/arc-protos.h @@ -45,13 +45,10 @@ extern void arc_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx); extern void arc_split_compare_and_swap (rtx *); extern void arc_expand_compare_and_swap (rtx *); extern bool compact_memory_operand_p (rtx, machine_mode, bool, bool); +extern int arc_return_address_register (unsigned int); +extern unsigned int arc_compute_function_type (struct function *); #endif /* RTX_CODE */ -#ifdef TREE_CODE -extern enum arc_function_type arc_compute_function_type (struct function *); -#endif /* TREE_CODE */ - - extern unsigned int arc_compute_frame_size (int); extern bool arc_ccfsm_branch_deleted_p (void); extern void arc_ccfsm_record_branch_deleted (void); @@ -64,10 +61,8 @@ extern rtx arc_return_addr_rtx (int , rtx); extern bool check_if_valid_regno_const (rtx *, int); extern bool check_if_valid_sleep_operand (rtx *, int); extern bool arc_legitimate_constant_p (machine_mode, rtx); -extern bool arc_legitimate_pc_offset_p (rtx); extern bool arc_legitimate_pic_addr_p (rtx); extern bool arc_raw_symbolic_reference_mentioned_p (rtx, bool); -extern bool arc_legitimate_pic_operand_p (rtx); extern bool arc_is_longcall_p (rtx); extern bool arc_is_shortcall_p (rtx); extern bool valid_brcc_with_delay_p (rtx *); diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index d9ad1390416..be5f1bd2003 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -211,6 +211,7 @@ static int rgf_banked_register_count; static int get_arc_condition_code (rtx); static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *); +static tree arc_handle_fndecl_attribute (tree *, tree, tree, int, bool *); /* Initialized arc_attribute_table to NULL since arc doesnot have any machine specific supported attributes. */ @@ -229,6 +230,9 @@ const struct attribute_spec arc_attribute_table[] = /* And these functions are always known to reside within the 21 bit addressing range of blcc. */ { "short_call", 0, 0, false, true, true, NULL, false }, + /* Function which are not having the prologue and epilogue generated + by the compiler. */ + { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; static int arc_comp_type_attributes (const_tree, const_tree); @@ -245,7 +249,6 @@ static rtx arc_expand_builtin (tree, rtx, rtx, machine_mode, int); static int branch_dest (rtx); static void arc_output_pic_addr_const (FILE *, rtx, int); -bool arc_legitimate_pic_operand_p (rtx); static bool arc_function_ok_for_sibcall (tree, tree); static rtx arc_function_value (const_tree, const_tree, bool); const char * output_shift (rtx *); @@ -276,8 +279,7 @@ const arc_cpu_t *arc_selected_cpu; register, an immediate or an long immediate. */ static bool -legitimate_offset_address_p (enum machine_mode mode, rtx x, bool index, - bool strict) +legitimate_offset_address_p (machine_mode mode, rtx x, bool index, bool strict) { if (GET_CODE (x) != PLUS) return false; @@ -513,6 +515,12 @@ static void arc_finalize_pic (void); #define TARGET_DIFFERENT_ADDR_DISPLACEMENT_P hook_bool_void_true #define TARGET_SPILL_CLASS arc_spill_class +#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS +#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS arc_allocate_stack_slots_for_args + +#undef TARGET_WARN_FUNC_RETURN +#define TARGET_WARN_FUNC_RETURN arc_warn_func_return + #include "target-def.h" #undef TARGET_ASM_ALIGNED_HI_OP @@ -1856,6 +1864,42 @@ arc_handle_interrupt_attribute (tree *, tree name, tree args, int, return NULL_TREE; } +static tree +arc_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Implement `TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS' */ + +static bool +arc_allocate_stack_slots_for_args (void) +{ + /* Naked functions should not allocate stack slots for arguments. */ + unsigned int fn_type = arc_compute_function_type (cfun); + + return !ARC_NAKED_P(fn_type); +} + +/* Implement `TARGET_WARN_FUNC_RETURN'. */ + +static bool +arc_warn_func_return (tree decl) +{ + struct function *func = DECL_STRUCT_FUNCTION (decl); + unsigned int fn_type = arc_compute_function_type (func); + + return !ARC_NAKED_P (fn_type); +} + /* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible, and two if they are nearly compatible (which causes a warning to be generated). */ @@ -2359,7 +2403,7 @@ struct GTY (()) arc_frame_info typedef struct GTY (()) machine_function { - enum arc_function_type fn_type; + unsigned int fn_type; struct arc_frame_info frame_info; /* To keep track of unalignment caused by short insns. */ int unalign; @@ -2377,43 +2421,40 @@ typedef struct GTY (()) machine_function The result is cached. To reset the cache at the end of a function, call with DECL = NULL_TREE. */ -enum arc_function_type +unsigned int arc_compute_function_type (struct function *fun) { - tree decl = fun->decl; - tree a; - enum arc_function_type fn_type = fun->machine->fn_type; + tree attr, decl = fun->decl; + unsigned int fn_type = fun->machine->fn_type; if (fn_type != ARC_FUNCTION_UNKNOWN) return fn_type; - /* Assume we have a normal function (not an interrupt handler). */ - fn_type = ARC_FUNCTION_NORMAL; + /* Check if it is a naked function. */ + if (lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) != NULL_TREE) + fn_type |= ARC_FUNCTION_NAKED; + else + fn_type |= ARC_FUNCTION_NORMAL; /* Now see if this is an interrupt handler. */ - for (a = DECL_ATTRIBUTES (decl); - a; - a = TREE_CHAIN (a)) - { - tree name = TREE_PURPOSE (a), args = TREE_VALUE (a); - - if (name == get_identifier ("interrupt") - && list_length (args) == 1 - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { - tree value = TREE_VALUE (args); - - if (!strcmp (TREE_STRING_POINTER (value), "ilink1") - || !strcmp (TREE_STRING_POINTER (value), "ilink")) - fn_type = ARC_FUNCTION_ILINK1; - else if (!strcmp (TREE_STRING_POINTER (value), "ilink2")) - fn_type = ARC_FUNCTION_ILINK2; - else if (!strcmp (TREE_STRING_POINTER (value), "firq")) - fn_type = ARC_FUNCTION_FIRQ; - else - gcc_unreachable (); - break; - } + attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl)); + if (attr != NULL_TREE) + { + tree value, args = TREE_VALUE (attr); + + gcc_assert (list_length (args) == 1); + value = TREE_VALUE (args); + gcc_assert (TREE_CODE (value) == STRING_CST); + + if (!strcmp (TREE_STRING_POINTER (value), "ilink1") + || !strcmp (TREE_STRING_POINTER (value), "ilink")) + fn_type |= ARC_FUNCTION_ILINK1; + else if (!strcmp (TREE_STRING_POINTER (value), "ilink2")) + fn_type |= ARC_FUNCTION_ILINK2; + else if (!strcmp (TREE_STRING_POINTER (value), "firq")) + fn_type |= ARC_FUNCTION_FIRQ; + else + gcc_unreachable (); } return fun->machine->fn_type = fn_type; @@ -2434,7 +2475,7 @@ arc_compute_function_type (struct function *fun) static bool arc_must_save_register (int regno, struct function *func) { - enum arc_function_type fn_type = arc_compute_function_type (func); + unsigned int fn_type = arc_compute_function_type (func); bool irq_auto_save_p = ((irq_ctrl_saved.irq_save_last_reg >= regno) && ARC_AUTO_IRQ_P (fn_type)); bool firq_auto_save_p = ARC_FAST_INTERRUPT_P (fn_type); @@ -2879,7 +2920,11 @@ arc_expand_prologue (void) Change the stack layout so that we rather store a high register with the PRE_MODIFY, thus enabling more short insn generation.) */ int first_offset = 0; - enum arc_function_type fn_type = arc_compute_function_type (cfun); + unsigned int fn_type = arc_compute_function_type (cfun); + + /* Naked functions don't have prologue. */ + if (ARC_NAKED_P (fn_type)) + return; size = ARC_STACK_ALIGN (size); @@ -2990,7 +3035,7 @@ void arc_expand_epilogue (int sibcall_p) { int size = get_frame_size (); - enum arc_function_type fn_type = arc_compute_function_type (cfun); + unsigned int fn_type = arc_compute_function_type (cfun); size = ARC_STACK_ALIGN (size); size = (!cfun->machine->frame_info.initialized @@ -3006,6 +3051,10 @@ arc_expand_epilogue (int sibcall_p) int millicode_p = cfun->machine->frame_info.millicode_end_reg > 0; rtx insn; + /* Naked functions don't have epilogue. */ + if (ARC_NAKED_P (fn_type)) + return; + size_to_deallocate = size; frame_size = size - (pretend_size + @@ -5005,57 +5054,6 @@ arc_rtx_costs (rtx x, machine_mode mode, int outer_code, } } -/* Helper used by arc_legitimate_pc_offset_p. */ - -static bool -arc_needs_pcl_p (rtx x) -{ - register const char *fmt; - register int i, j; - - if ((GET_CODE (x) == UNSPEC) - && (XVECLEN (x, 0) == 1) - && (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF)) - switch (XINT (x, 1)) - { - case ARC_UNSPEC_GOT: - case ARC_UNSPEC_GOTOFFPC: - case UNSPEC_TLS_GD: - case UNSPEC_TLS_IE: - return true; - default: - break; - } - - fmt = GET_RTX_FORMAT (GET_CODE (x)); - for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - if (arc_needs_pcl_p (XEXP (x, i))) - return true; - } - else if (fmt[i] == 'E') - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - if (arc_needs_pcl_p (XVECEXP (x, i, j))) - return true; - } - - return false; -} - -/* Return true if ADDR is an address that needs to be expressed as an - explicit sum of pcl + offset. */ - -bool -arc_legitimate_pc_offset_p (rtx addr) -{ - if (GET_CODE (addr) != CONST) - return false; - - return arc_needs_pcl_p (addr); -} - /* Return true if ADDR is a valid pic address. A valid pic address on arc should look like const (unspec (SYMBOL_REF/LABEL) (ARC_UNSPEC_GOTOFF/ARC_UNSPEC_GOT)) */ @@ -5063,8 +5061,6 @@ arc_legitimate_pc_offset_p (rtx addr) bool arc_legitimate_pic_addr_p (rtx addr) { - if (GET_CODE (addr) == LABEL_REF) - return true; if (GET_CODE (addr) != CONST) return false; @@ -5768,16 +5764,6 @@ arc_return_addr_rtx (int count, ATTRIBUTE_UNUSED rtx frame) return get_hard_reg_initial_val (Pmode , RETURN_ADDR_REGNUM); } -/* Nonzero if the constant value X is a legitimate general operand - when generating PIC code. It is given that flag_pic is on and - that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ - -bool -arc_legitimate_pic_operand_p (rtx x) -{ - return !arc_raw_symbolic_reference_mentioned_p (x, true); -} - /* Determine if a given RTX is a valid constant. We already know this satisfies CONSTANT_P. */ @@ -5793,40 +5779,12 @@ arc_legitimate_constant_p (machine_mode mode, rtx x) switch (GET_CODE (x)) { case CONST: - x = XEXP (x, 0); - - if (GET_CODE (x) == PLUS) + if (flag_pic) { - if (flag_pic - ? GET_CODE (XEXP (x, 1)) != CONST_INT - : !arc_legitimate_constant_p (mode, XEXP (x, 1))) - return false; - x = XEXP (x, 0); - } - - /* Only some unspecs are valid as "constants". */ - if (GET_CODE (x) == UNSPEC) - switch (XINT (x, 1)) - { - case ARC_UNSPEC_PLT: - case ARC_UNSPEC_GOTOFF: - case ARC_UNSPEC_GOTOFFPC: - case ARC_UNSPEC_GOT: - case UNSPEC_TLS_GD: - case UNSPEC_TLS_IE: - case UNSPEC_TLS_OFF: + if (arc_legitimate_pic_addr_p (x)) return true; - - default: - gcc_unreachable (); - } - - /* We must have drilled down to a symbol. */ - if (arc_raw_symbolic_reference_mentioned_p (x, false)) - return false; - - /* Return true. */ - break; + } + return arc_legitimate_constant_p (mode, XEXP (x, 0)); case SYMBOL_REF: if (SYMBOL_REF_TLS_MODEL (x)) @@ -5836,13 +5794,53 @@ arc_legitimate_constant_p (machine_mode mode, rtx x) if (flag_pic) return false; /* Fall through. */ + case CONST_INT: + case CONST_DOUBLE: + return true; + + case NEG: + return arc_legitimate_constant_p (mode, XEXP (x, 0)); + + case PLUS: + case MINUS: + { + bool t1 = arc_legitimate_constant_p (mode, XEXP (x, 0)); + bool t2 = arc_legitimate_constant_p (mode, XEXP (x, 1)); + + return (t1 && t2); + } + + case CONST_VECTOR: + switch (mode) + { + case V2HImode: + return TARGET_PLUS_DMPY; + case V2SImode: + case V4HImode: + return TARGET_PLUS_QMACW; + default: + return false; + } + + case UNSPEC: + switch (XINT (x, 1)) + { + case UNSPEC_TLS_GD: + case UNSPEC_TLS_OFF: + case UNSPEC_TLS_IE: + return true; + default: + /* Any other unspec ending here are pic related, hence the above + constant pic address checking returned false. */ + return false; + } + /* Fall through. */ default: - break; + fatal_insn ("unrecognized supposed constant", x); } - /* Otherwise we handle everything else in the move patterns. */ - return true; + gcc_unreachable (); } static bool @@ -5879,9 +5877,7 @@ arc_legitimate_address_p (machine_mode mode, rtx x, bool strict) if ((GET_MODE_SIZE (mode) != 16) && CONSTANT_P (x)) { - if (flag_pic ? arc_legitimate_pic_addr_p (x) - : arc_legitimate_constant_p (Pmode, x)) - return true; + return arc_legitimate_constant_p (mode, x); } if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == PRE_INC || GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC) @@ -9789,37 +9785,60 @@ arc_can_follow_jump (const rtx_insn *follower, const rtx_insn *followee) return true; } -int arc_return_address_regs[5] = - {0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM, ILINK1_REGNUM}; +/* Return the register number of the register holding the return address + for a function of type TYPE. */ -/* Implement EPILOGUE__USES. +int +arc_return_address_register (unsigned int fn_type) +{ + int regno = 0; + + if (ARC_INTERRUPT_P (fn_type)) + { + if (((fn_type & ARC_FUNCTION_ILINK1) | ARC_FUNCTION_FIRQ) != 0) + regno = ILINK1_REGNUM; + else if ((fn_type & ARC_FUNCTION_ILINK2) != 0) + regno = ILINK2_REGNUM; + else + gcc_unreachable (); + } + else if (ARC_NORMAL_P (fn_type) || ARC_NAKED_P (fn_type)) + regno = RETURN_ADDR_REGNUM; + + gcc_assert (regno != 0); + return regno; +} + +/* Implement EPILOGUE_USES. Return true if REGNO should be added to the deemed uses of the epilogue. - We use the return address - arc_return_address_regs[arc_compute_function_type (cfun)]. But - also, we have to make sure all the register restore instructions - are known to be live in interrupt functions, plus the blink - register if it is clobbered by the isr. */ + We have to make sure all the register restore instructions are + known to be live in interrupt functions, plus the blink register if + it is clobbered by the isr. */ bool arc_epilogue_uses (int regno) { + unsigned int fn_type; + if (regno == arc_tp_regno) return true; + + fn_type = arc_compute_function_type (cfun); if (reload_completed) { if (ARC_INTERRUPT_P (cfun->machine->fn_type)) { if (!fixed_regs[regno]) return true; - return ((regno == arc_return_address_regs[cfun->machine->fn_type]) + return ((regno == arc_return_address_register (fn_type)) || (regno == RETURN_ADDR_REGNUM)); } else return regno == RETURN_ADDR_REGNUM; } else - return regno == arc_return_address_regs[arc_compute_function_type (cfun)]; + return regno == arc_return_address_register (fn_type); } /* Helper for EH_USES macro. */ @@ -9980,10 +9999,8 @@ arc_post_atomic_barrier (enum memmodel model) static void emit_unlikely_jump (rtx insn) { - int very_unlikely = REG_BR_PROB_BASE / 100 - 1; - rtx_insn *jump = emit_jump_insn (insn); - add_int_reg_note (jump, REG_BR_PROB, very_unlikely); + add_reg_br_prob_note (jump, profile_probability::very_unlikely ()); } /* Expand code to perform a 8 or 16-bit compare and swap by doing diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h index 5627eb488cf..9216f9417e0 100644 --- a/gcc/config/arc/arc.h +++ b/gcc/config/arc/arc.h @@ -901,10 +901,10 @@ extern int arc_initial_elimination_offset(int from, int to); a special predicate for the memory operand of stores, like for the SH. */ /* Recognize any constant value that is a valid address. */ -#define CONSTANT_ADDRESS_P(X) \ -(flag_pic?arc_legitimate_pic_addr_p (X): \ -(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ - || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST)) +#define CONSTANT_ADDRESS_P(X) \ + (flag_pic ? (arc_legitimate_pic_addr_p (X) || LABEL_P (X)): \ + (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST)) /* Is the argument a const_int rtx, containing an exact power of 2 */ #define IS_POWEROF2_P(X) (! ( (X) & ((X) - 1)) && (X)) @@ -1083,7 +1083,8 @@ arc_select_cc_mode (OP, X, Y) check it either. You need not define this macro if all constants (including SYMBOL_REF) can be immediate operands when generating position independent code. */ -#define LEGITIMATE_PIC_OPERAND_P(X) (arc_legitimate_pic_operand_p(X)) +#define LEGITIMATE_PIC_OPERAND_P(X) \ + (!arc_raw_symbolic_reference_mentioned_p ((X), true)) /* PIC and small data don't mix on ARC because they use the same register. */ #define SDATA_BASE_REGNUM 26 @@ -1262,6 +1263,13 @@ extern char rname56[], rname57[], rname58[], rname59[]; "lp_start", "lp_end" \ } +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"ilink", 29}, \ + {"r29", 29}, \ + {"r30", 30} \ +} + /* Entry to the insn conditionalizer. */ #define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ arc_final_prescan_insn (INSN, OPVEC, NOPERANDS) @@ -1363,10 +1371,6 @@ do { \ #define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ arc_asm_output_aligned_decl_local (STREAM, DECL, NAME, SIZE, ALIGNMENT, 0) -/* To translate the return value of arc_function_type into a register number - to jump through for function return. */ -extern int arc_return_address_regs[5]; - /* Debugging information. */ /* Generate DBX and DWARF debugging information. */ @@ -1499,22 +1503,38 @@ extern struct rtx_def *arc_compare_op0, *arc_compare_op1; /* ARC function types. */ enum arc_function_type { - ARC_FUNCTION_UNKNOWN, ARC_FUNCTION_NORMAL, + /* No function should have the unknown type. This value is used to + indicate the that function type has not yet been computed. */ + ARC_FUNCTION_UNKNOWN = 0, + + /* The normal function type indicates that the function has the + standard prologue and epilogue. */ + ARC_FUNCTION_NORMAL = 1 << 0, /* These are interrupt handlers. The name corresponds to the register name that contains the return address. */ - ARC_FUNCTION_ILINK1, ARC_FUNCTION_ILINK2, + ARC_FUNCTION_ILINK1 = 1 << 1, + ARC_FUNCTION_ILINK2 = 1 << 2, /* Fast interrupt is only available on ARCv2 processors. */ - ARC_FUNCTION_FIRQ + ARC_FUNCTION_FIRQ = 1 << 3, + /* The naked function type indicates that the function does not have + prologue or epilogue, and that no stack frame is available. */ + ARC_FUNCTION_NAKED = 1 << 4 }; -#define ARC_INTERRUPT_P(TYPE) \ - (((TYPE) == ARC_FUNCTION_ILINK1) || ((TYPE) == ARC_FUNCTION_ILINK2) \ - || ((TYPE) == ARC_FUNCTION_FIRQ)) -#define ARC_FAST_INTERRUPT_P(TYPE) ((TYPE) == ARC_FUNCTION_FIRQ) +/* Check if a function is an interrupt function. */ +#define ARC_INTERRUPT_P(TYPE) \ + (((TYPE) & (ARC_FUNCTION_ILINK1 | ARC_FUNCTION_ILINK2 \ + | ARC_FUNCTION_FIRQ)) != 0) + +/* Check if a function is a fast interrupt function. */ +#define ARC_FAST_INTERRUPT_P(TYPE) (((TYPE) & ARC_FUNCTION_FIRQ) != 0) + +/* Check if a function is normal, that is, has standard prologue and + epilogue. */ +#define ARC_NORMAL_P(TYPE) (((TYPE) & ARC_FUNCTION_NORMAL) != 0) -/* Compute the type of a function from its DECL. Needed for EPILOGUE_USES. */ -struct function; -extern enum arc_function_type arc_compute_function_type (struct function *); +/* Check if a function is naked. */ +#define ARC_NAKED_P(TYPE) (((TYPE) & ARC_FUNCTION_NAKED) != 0) /* Called by crtstuff.c to make calls to function FUNCTION that are defined in SECTION_OP, and then to switch back to text section. */ diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md index 9aa9cd7ae29..6fb0f17cee1 100644 --- a/gcc/config/arc/arc.md +++ b/gcc/config/arc/arc.md @@ -505,8 +505,8 @@ (cond [(eq_attr "in_delay_slot" "false") (const_string "no") (match_test "regno_clobbered_p - (arc_return_address_regs - [arc_compute_function_type (cfun)], + (arc_return_address_register + (arc_compute_function_type (cfun)), insn, SImode, 1)") (const_string "no")] (const_string "yes"))) @@ -2649,30 +2649,7 @@ (match_operand:DI 2 "nonmemory_operand" ""))) (clobber (reg:CC CC_REG))])] "" -{ - if (TARGET_EXPAND_ADDDI) - { - rtx l0 = gen_lowpart (SImode, operands[0]); - rtx h0 = disi_highpart (operands[0]); - rtx l1 = gen_lowpart (SImode, operands[1]); - rtx h1 = disi_highpart (operands[1]); - rtx l2 = gen_lowpart (SImode, operands[2]); - rtx h2 = disi_highpart (operands[2]); - rtx cc_c = gen_rtx_REG (CC_Cmode, CC_REG); - - if (CONST_INT_P (h2) && INTVAL (h2) < 0 && SIGNED_INT12 (INTVAL (h2))) - { - emit_insn (gen_sub_f (l0, l1, gen_int_mode (-INTVAL (l2), SImode))); - emit_insn (gen_sbc (h0, h1, - gen_int_mode (-INTVAL (h2) - (l1 != 0), SImode), - cc_c)); - DONE; - } - emit_insn (gen_add_f (l0, l1, l2)); - emit_insn (gen_adc (h0, h1, h2)); - DONE; - } -}) +{}) ; This assumes that there can be no strictly partial overlap between ; operands[1] and operands[2]. @@ -2911,20 +2888,6 @@ { if (!register_operand (operands[2], DImode)) operands[1] = force_reg (DImode, operands[1]); - if (TARGET_EXPAND_ADDDI) - { - rtx l0 = gen_lowpart (SImode, operands[0]); - rtx h0 = disi_highpart (operands[0]); - rtx l1 = gen_lowpart (SImode, operands[1]); - rtx h1 = disi_highpart (operands[1]); - rtx l2 = gen_lowpart (SImode, operands[2]); - rtx h2 = disi_highpart (operands[2]); - rtx cc_c = gen_rtx_REG (CC_Cmode, CC_REG); - - emit_insn (gen_sub_f (l0, l1, l2)); - emit_insn (gen_sbc (h0, h1, h2, cc_c)); - DONE; - } }) (define_insn_and_split "subdi3_i" @@ -4533,9 +4496,21 @@ (set_attr "type" "two_cycle_core,two_cycle_core")]) (define_expand "clzsi2" - [(set (match_operand:SI 0 "dest_reg_operand" "") - (clz:SI (match_operand:SI 1 "register_operand" "")))] + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (clz:SI (match_operand:SI 1 "register_operand" ""))) + (clobber (match_dup 2))])] "TARGET_NORM" + "operands[2] = gen_rtx_REG (CC_ZNmode, CC_REG);") + +(define_insn_and_split "*arc_clzsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (clz:SI (match_operand:SI 1 "register_operand" "r"))) + (clobber (reg:CC_ZN CC_REG))] + "TARGET_NORM" + "#" + "reload_completed" + [(const_int 0)] { emit_insn (gen_norm_f (operands[0], operands[1])); emit_insn @@ -4552,9 +4527,23 @@ }) (define_expand "ctzsi2" - [(set (match_operand:SI 0 "register_operand" "") - (ctz:SI (match_operand:SI 1 "register_operand" "")))] + [(match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")] "TARGET_NORM" + " + emit_insn (gen_arc_ctzsi2 (operands[0], operands[1])); + DONE; +") + +(define_insn_and_split "arc_ctzsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (ctz:SI (match_operand:SI 1 "register_operand" "r"))) + (clobber (reg:CC_ZN CC_REG)) + (clobber (match_scratch:SI 2 "=&r"))] + "TARGET_NORM" + "#" + "reload_completed" + [(const_int 0)] { rtx temp = operands[0]; @@ -4562,10 +4551,10 @@ || (REGNO (temp) < FIRST_PSEUDO_REGISTER && !TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], REGNO (temp)))) - temp = gen_reg_rtx (SImode); + temp = operands[2]; emit_insn (gen_addsi3 (temp, operands[1], constm1_rtx)); emit_insn (gen_bic_f_zn (temp, temp, operands[1])); - emit_insn (gen_clrsbsi2 (temp, temp)); + emit_insn (gen_clrsbsi2 (operands[0], temp)); emit_insn (gen_rtx_COND_EXEC (VOIDmode, @@ -4575,7 +4564,8 @@ (gen_rtx_COND_EXEC (VOIDmode, gen_rtx_GE (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx), - gen_rtx_SET (operands[0], gen_rtx_MINUS (SImode, GEN_INT (31), temp)))); + gen_rtx_SET (operands[0], gen_rtx_MINUS (SImode, GEN_INT (31), + operands[0])))); DONE; }) @@ -4859,7 +4849,8 @@ { rtx reg = gen_rtx_REG (Pmode, - arc_return_address_regs[arc_compute_function_type (cfun)]); + arc_return_address_register (arc_compute_function_type + (cfun))); if (TARGET_V2 && ARC_INTERRUPT_P (arc_compute_function_type (cfun))) @@ -4908,7 +4899,8 @@ xop[0] = operands[0]; xop[1] = gen_rtx_REG (Pmode, - arc_return_address_regs[arc_compute_function_type (cfun)]); + arc_return_address_register (arc_compute_function_type + (cfun))); if (TARGET_PAD_RETURN) arc_pad_return (); diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt index f01a2ff0e58..ad2df2605e9 100644 --- a/gcc/config/arc/arc.opt +++ b/gcc/config/arc/arc.opt @@ -270,11 +270,11 @@ Target RejectNegative Var(arc_tune, TUNE_ARC700_4_2_XMAC) Tune for ARC700 R4.2 Cpu with XMAC block. mindexed-loads -Target Var(TARGET_INDEXED_LOADS) +Target Var(TARGET_INDEXED_LOADS) Init(TARGET_INDEXED_LOADS_DEFAULT) Enable the use of indexed loads. mauto-modify-reg -Target Var(TARGET_AUTO_MODIFY_REG) +Target Var(TARGET_AUTO_MODIFY_REG) Init(TARGET_AUTO_MODIFY_REG_DEFAULT) Enable the use of pre/post modify with register displacement. mmul32x16 @@ -328,7 +328,7 @@ Target Var(TARGET_Q_CLASS) Enable 'q' instruction alternatives. mexpand-adddi -Target Var(TARGET_EXPAND_ADDDI) +Target Warn(%qs is deprecated) Expand adddi3 and subdi3 at rtl generation time into add.f / adc etc. diff --git a/gcc/config/arc/constraints.md b/gcc/config/arc/constraints.md index edab41c3e67..6620daf18e3 100644 --- a/gcc/config/arc/constraints.md +++ b/gcc/config/arc/constraints.md @@ -403,7 +403,7 @@ (define_constraint "Cpc" "pc-relative constant" - (match_test "arc_legitimate_pc_offset_p (op)")) + (match_test "arc_legitimate_pic_addr_p (op)")) (define_constraint "Clb" "label" @@ -412,12 +412,12 @@ (define_constraint "Cal" "constant for arithmetic/logical operations" - (match_test "immediate_operand (op, VOIDmode) && !arc_legitimate_pc_offset_p (op)")) + (match_test "immediate_operand (op, VOIDmode) && !arc_legitimate_pic_addr_p (op)")) (define_constraint "C32" "32 bit constant for arithmetic/logical operations" (match_test "immediate_operand (op, VOIDmode) - && !arc_legitimate_pc_offset_p (op) + && !arc_legitimate_pic_addr_p (op) && !satisfies_constraint_I (op)")) ; Note that the 'cryptic' register constraints will not make reload use the diff --git a/gcc/config/arc/elf.h b/gcc/config/arc/elf.h index c5794f8f785..43f3408bc08 100644 --- a/gcc/config/arc/elf.h +++ b/gcc/config/arc/elf.h @@ -58,3 +58,11 @@ along with GCC; see the file COPYING3. If not see /* Bare-metal toolchains do not need a thread pointer register. */ #undef TARGET_ARC_TP_REGNO_DEFAULT #define TARGET_ARC_TP_REGNO_DEFAULT -1 + +/* Indexed loads are default. */ +#undef TARGET_INDEXED_LOADS_DEFAULT +#define TARGET_INDEXED_LOADS_DEFAULT 1 + +/* Pre/post modify with register displacement are default. */ +#undef TARGET_AUTO_MODIFY_REG_DEFAULT +#define TARGET_AUTO_MODIFY_REG_DEFAULT 1 diff --git a/gcc/config/arc/linux.h b/gcc/config/arc/linux.h index 83e5a1d61f2..d8e006307fc 100644 --- a/gcc/config/arc/linux.h +++ b/gcc/config/arc/linux.h @@ -83,3 +83,11 @@ along with GCC; see the file COPYING3. If not see #define SUBTARGET_CPP_SPEC "\ %{pthread:-D_REENTRANT} \ " + +/* Indexed loads are default off. */ +#undef TARGET_INDEXED_LOADS_DEFAULT +#define TARGET_INDEXED_LOADS_DEFAULT 0 + +/* Pre/post modify with register displacement are default off. */ +#undef TARGET_AUTO_MODIFY_REG_DEFAULT +#define TARGET_AUTO_MODIFY_REG_DEFAULT 0 |