summaryrefslogtreecommitdiff
path: root/gcc/config/arc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/arc')
-rw-r--r--gcc/config/arc/arc-protos.h9
-rw-r--r--gcc/config/arc/arc.c317
-rw-r--r--gcc/config/arc/arc.h58
-rw-r--r--gcc/config/arc/arc.md90
-rw-r--r--gcc/config/arc/arc.opt6
-rw-r--r--gcc/config/arc/constraints.md6
-rw-r--r--gcc/config/arc/elf.h8
-rw-r--r--gcc/config/arc/linux.h8
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