return priority;
}
+/* For ARC base register + offset addressing, the validity of the
+ address is mode-dependent for most of the offset range, as the
+ offset can be scaled by the access size.
+ We don't expose these as mode-dependent addresses in the
+ mode_dependent_address_p target hook, because that would disable
+ lots of optimizations, and most uses of these addresses are for 32
+ or 64 bit accesses anyways, which are fine.
+ However, that leaves some addresses for 8 / 16 bit values not
+ properly reloaded by the generic code, which is why we have to
+ schedule secondary reloads for these. */
+
static reg_class_t
-arc_secondary_reload (bool in_p, rtx x, reg_class_t cl, machine_mode,
- secondary_reload_info *)
+arc_secondary_reload (bool in_p,
+ rtx x,
+ reg_class_t cl,
+ machine_mode mode,
+ secondary_reload_info *sri)
{
+ enum rtx_code code = GET_CODE (x);
+
if (cl == DOUBLE_REGS)
return GENERAL_REGS;
if ((cl == LPCOUNT_REG || cl == WRITABLE_CORE_REGS)
&& in_p && MEM_P (x))
return GENERAL_REGS;
+
+ /* If we have a subreg (reg), where reg is a pseudo (that will end in
+ a memory location), then we may need a scratch register to handle
+ the fp/sp+largeoffset address. */
+ if (code == SUBREG)
+ {
+ rtx addr = NULL_RTX;
+ x = SUBREG_REG (x);
+
+ if (REG_P (x))
+ {
+ int regno = REGNO (x);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ regno = reg_renumber[regno];
+
+ if (regno != -1)
+ return NO_REGS;
+
+ /* It is a pseudo that ends in a stack location. */
+ if (reg_equiv_mem (REGNO (x)))
+ {
+ /* Get the equivalent address and check the range of the
+ offset. */
+ rtx mem = reg_equiv_mem (REGNO (x));
+ addr = find_replacement (&XEXP (mem, 0));
+ }
+ }
+ else
+ {
+ gcc_assert (MEM_P (x));
+ addr = XEXP (x, 0);
+ addr = simplify_rtx (addr);
+ }
+ if (addr && GET_CODE (addr) == PLUS
+ && CONST_INT_P (XEXP (addr, 1))
+ && (!RTX_OK_FOR_OFFSET_P (mode, XEXP (addr, 1))))
+ {
+ switch (mode)
+ {
+ case QImode:
+ sri->icode =
+ in_p ? CODE_FOR_reload_qi_load : CODE_FOR_reload_qi_store;
+ break;
+ case HImode:
+ sri->icode =
+ in_p ? CODE_FOR_reload_hi_load : CODE_FOR_reload_hi_store;
+ break;
+ default:
+ break;
+ }
+ }
+ }
return NO_REGS;
}
+/* Convert reloads using offsets that are too large to use indirect
+ addressing. */
+
+void
+arc_secondary_reload_conv (rtx reg, rtx mem, rtx scratch, bool store_p)
+{
+ rtx addr;
+
+ gcc_assert (GET_CODE (mem) == MEM);
+ addr = XEXP (mem, 0);
+
+ /* Large offset: use a move. FIXME: ld ops accepts limms as
+ offsets. Hence, the following move insn is not required. */
+ emit_move_insn (scratch, addr);
+ mem = replace_equiv_address_nv (mem, scratch);
+
+ /* Now create the move. */
+ if (store_p)
+ emit_insn (gen_rtx_SET (mem, reg));
+ else
+ emit_insn (gen_rtx_SET (reg, mem));
+
+ return;
+}
+
static unsigned arc_ifcvt (void);
namespace {
{
enum attr_tune tune_dflt = TUNE_NONE;
- if (TARGET_ARC600)
+ switch (arc_cpu)
{
+ case PROCESSOR_ARC600:
arc_cpu_string = "ARC600";
tune_dflt = TUNE_ARC600;
- }
- else if (TARGET_ARC601)
- {
+ break;
+
+ case PROCESSOR_ARC601:
arc_cpu_string = "ARC601";
tune_dflt = TUNE_ARC600;
- }
- else if (TARGET_ARC700)
- {
+ break;
+
+ case PROCESSOR_ARC700:
arc_cpu_string = "ARC700";
tune_dflt = TUNE_ARC700_4_2_STD;
+ break;
+
+ case PROCESSOR_ARCEM:
+ arc_cpu_string = "EM";
+ break;
+
+ case PROCESSOR_ARCHS:
+ arc_cpu_string = "HS";
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else
- gcc_unreachable ();
+
if (arc_tune == TUNE_NONE)
arc_tune = tune_dflt;
/* Note: arc_multcost is only used in rtx_cost if speed is true. */
}
/* Support mul64 generation only for ARC600. */
- if (TARGET_MUL64_SET && TARGET_ARC700)
- error ("-mmul64 not supported for ARC700");
+ if (TARGET_MUL64_SET && (!TARGET_ARC600_FAMILY))
+ error ("-mmul64 not supported for ARC700 or ARCv2");
- /* MPY instructions valid only for ARC700. */
- if (TARGET_NOMPY_SET && !TARGET_ARC700)
- error ("-mno-mpy supported only for ARC700");
+ /* MPY instructions valid only for ARC700 or ARCv2. */
+ if (TARGET_NOMPY_SET && TARGET_ARC600_FAMILY)
+ error ("-mno-mpy supported only for ARC700 or ARCv2");
/* mul/mac instructions only for ARC600. */
- if (TARGET_MULMAC_32BY16_SET && !(TARGET_ARC600 || TARGET_ARC601))
+ if (TARGET_MULMAC_32BY16_SET && (!TARGET_ARC600_FAMILY))
error ("-mmul32x16 supported only for ARC600 or ARC601");
if (!TARGET_DPFP && TARGET_DPFP_DISABLE_LRSR)
error ("FPX fast and compact options cannot be specified together");
/* FPX-2. No fast-spfp for arc600 or arc601. */
- if (TARGET_SPFP_FAST_SET && (TARGET_ARC600 || TARGET_ARC601))
+ if (TARGET_SPFP_FAST_SET && TARGET_ARC600_FAMILY)
error ("-mspfp_fast not available on ARC600 or ARC601");
/* FPX-3. No FPX extensions on pre-ARC600 cores. */
if ((TARGET_DPFP || TARGET_SPFP)
- && !(TARGET_ARC600 || TARGET_ARC601 || TARGET_ARC700))
+ && !TARGET_ARCOMPACT_FAMILY)
error ("FPX extensions not available on pre-ARC600 cores");
+ /* Only selected multiplier configurations are available for HS. */
+ if (TARGET_HS && ((arc_mpy_option > 2 && arc_mpy_option < 7)
+ || (arc_mpy_option == 1)))
+ error ("This multiplier configuration is not available for HS cores");
+
/* Warn for unimplemented PIC in pre-ARC700 cores, and disable flag_pic. */
- if (flag_pic && !TARGET_ARC700)
+ if (flag_pic && TARGET_ARC600_FAMILY)
{
- warning (DK_WARNING, "PIC is not supported for %s. Generating non-PIC code only..", arc_cpu_string);
+ warning (DK_WARNING,
+ "PIC is not supported for %s. Generating non-PIC code only..",
+ arc_cpu_string);
flag_pic = 0;
}
arc_punct_chars['!'] = 1;
arc_punct_chars['^'] = 1;
arc_punct_chars['&'] = 1;
+ arc_punct_chars['+'] = 1;
+ arc_punct_chars['_'] = 1;
if (optimize > 1 && !TARGET_NO_COND_EXEC)
{
if (flag_no_common == 255)
flag_no_common = !TARGET_NO_SDATA_SET;
- /* TARGET_COMPACT_CASESI needs the "q" register class. */ \
+ /* TARGET_COMPACT_CASESI needs the "q" register class. */
if (TARGET_MIXED_CODE)
TARGET_Q_CLASS = 1;
if (!TARGET_Q_CLASS)
char rname57[5] = "r57";
char rname58[5] = "r58";
char rname59[5] = "r59";
+ char rname29[7] = "ilink1";
+ char rname30[7] = "ilink2";
static void
arc_conditional_register_usage (void)
int i;
int fix_start = 60, fix_end = 55;
+ if (TARGET_V2)
+ {
+ /* For ARCv2 the core register set is changed. */
+ strcpy (rname29, "ilink");
+ strcpy (rname30, "r30");
+ fixed_regs[30] = call_used_regs[30] = 1;
+ }
+
if (TARGET_MUL64_SET)
{
fix_start = 57;
machine_dependent_reorg. */
if (TARGET_ARC600)
CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], LP_COUNT);
- else if (!TARGET_ARC700)
+ else if (!TARGET_LP_WR_INTERLOCK)
fixed_regs[LP_COUNT] = 1;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (!call_used_regs[regno])
for (regno = 32; regno < 60; regno++)
if (!fixed_regs[regno])
SET_HARD_REG_BIT (reg_class_contents[WRITABLE_CORE_REGS], regno);
- if (TARGET_ARC700)
+ if (!TARGET_ARC600_FAMILY)
{
for (regno = 32; regno <= 60; regno++)
CLEAR_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], regno);
= (fixed_regs[i]
? (TEST_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], i)
? CHEAP_CORE_REGS : ALL_CORE_REGS)
- : ((TARGET_ARC700
+ : (((!TARGET_ARC600_FAMILY)
&& TEST_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], i))
? CHEAP_CORE_REGS : WRITABLE_CORE_REGS));
else
/* Handle Special Registers. */
arc_regno_reg_class[29] = LINK_REGS; /* ilink1 register. */
- arc_regno_reg_class[30] = LINK_REGS; /* ilink2 register. */
+ if (!TARGET_V2)
+ arc_regno_reg_class[30] = LINK_REGS; /* ilink2 register. */
arc_regno_reg_class[31] = LINK_REGS; /* blink register. */
arc_regno_reg_class[60] = LPCOUNT_REG;
arc_regno_reg_class[61] = NO_REGS; /* CC_REG: must be NO_REGS. */
*no_add_attrs = true;
}
else if (strcmp (TREE_STRING_POINTER (value), "ilink1")
- && strcmp (TREE_STRING_POINTER (value), "ilink2"))
+ && strcmp (TREE_STRING_POINTER (value), "ilink2")
+ && !TARGET_V2)
{
warning (OPT_Wattributes,
"argument of %qE attribute is not \"ilink1\" or \"ilink2\"",
name);
*no_add_attrs = true;
}
+ else if (TARGET_V2
+ && strcmp (TREE_STRING_POINTER (value), "ilink"))
+ {
+ warning (OPT_Wattributes,
+ "argument of %qE attribute is not \"ilink\"",
+ name);
+ *no_add_attrs = true;
+ }
+
return NULL_TREE;
}
{
tree value = TREE_VALUE (args);
- if (!strcmp (TREE_STRING_POINTER (value), "ilink1"))
+ 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;
if (TARGET_ANNOTATE_ALIGN && cfun->machine->size_reason)
fprintf (file, "; unalign: %d", cfun->machine->unalign);
return;
+ case '+':
+ if (TARGET_V2)
+ fputs ("m", file);
+ else
+ fputs ("h", file);
+ return;
+ case '_':
+ if (TARGET_V2)
+ fputs ("h", file);
+ else
+ fputs ("w", file);
+ return;
default :
/* Unknown flag. */
output_operand_lossage ("invalid operand output code");
*total= arc_multcost;
/* We do not want synth_mult sequences when optimizing
for size. */
- else if (TARGET_MUL64_SET || (TARGET_ARC700 && !TARGET_NOMPY_SET))
+ else if (TARGET_MUL64_SET || TARGET_ARC700_MPY)
*total = COSTS_N_INSNS (1);
else
*total = COSTS_N_INSNS (2);
else
{
HOST_WIDE_INT size = int_size_in_bytes (type);
- return (size == -1 || size > 8);
+ return (size == -1 || size > (TARGET_V2 ? 16 : 8));
}
}
return NULL;
}
+/* The same functionality as arc_hazard. It is called in machine
+ reorg before any other optimization. Hence, the NOP size is taken
+ into account when doing branch shortening. */
+
+static void
+workaround_arc_anomaly (void)
+{
+ rtx_insn *insn, *succ0;
+
+ /* For any architecture: call arc_hazard here. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ succ0 = next_real_insn (insn);
+ if (arc_hazard (insn, succ0))
+ {
+ emit_insn_before (gen_nopv (), succ0);
+ }
+ }
+}
+
static int arc_reorg_in_progress = 0;
/* ARC's machince specific reorg function. */
long offset;
int changed;
+ workaround_arc_anomaly ();
+
cfun->machine->arc_reorg_started = 1;
arc_reorg_in_progress = 1;
return 0;
}
+/* Given a rtx, check if it is an assembly instruction or not. */
+
+static int
+arc_asm_insn_p (rtx x)
+{
+ int i, j;
+
+ if (x == 0)
+ return 0;
+
+ switch (GET_CODE (x))
+ {
+ case ASM_OPERANDS:
+ case ASM_INPUT:
+ return 1;
+
+ case SET:
+ return arc_asm_insn_p (SET_SRC (x));
+
+ case PARALLEL:
+ j = 0;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ j += arc_asm_insn_p (XVECEXP (x, 0, i));
+ if ( j > 0)
+ return 1;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* We might have a CALL to a non-returning function before a loop end.
+ ??? Although the manual says that's OK (the target is outside the
+ loop, and the loop counter unused there), the assembler barfs on
+ this for ARC600, so we must insert a nop before such a call too.
+ For ARC700, and ARCv2 is not allowed to have the last ZOL
+ instruction a jump to a location where lp_count is modified. */
+
+static bool
+arc_loop_hazard (rtx_insn *pred, rtx_insn *succ)
+{
+ rtx_insn *jump = NULL;
+ rtx_insn *label = NULL;
+ basic_block succ_bb;
+
+ if (recog_memoized (succ) != CODE_FOR_doloop_end_i)
+ return false;
+
+ /* Phase 1: ARC600 and ARCv2HS doesn't allow any control instruction
+ (i.e., jump/call) as the last instruction of a ZOL. */
+ if (TARGET_ARC600 || TARGET_HS)
+ if (JUMP_P (pred) || CALL_P (pred)
+ || arc_asm_insn_p (PATTERN (pred))
+ || GET_CODE (PATTERN (pred)) == SEQUENCE)
+ return true;
+
+ /* Phase 2: Any architecture, it is not allowed to have the last ZOL
+ instruction a jump to a location where lp_count is modified. */
+
+ /* Phase 2a: Dig for the jump instruction. */
+ if (JUMP_P (pred))
+ jump = pred;
+ else if (GET_CODE (PATTERN (pred)) == SEQUENCE
+ && JUMP_P (XVECEXP (PATTERN (pred), 0, 0)))
+ jump = as_a <rtx_insn *> XVECEXP (PATTERN (pred), 0, 0);
+ else
+ return false;
+
+ label = JUMP_LABEL_AS_INSN (jump);
+ if (!label)
+ return false;
+
+ /* Phase 2b: Make sure is not a millicode jump. */
+ if ((GET_CODE (PATTERN (jump)) == PARALLEL)
+ && (XVECEXP (PATTERN (jump), 0, 0) == ret_rtx))
+ return false;
+
+ /* Phase 2c: Make sure is not a simple_return. */
+ if ((GET_CODE (PATTERN (jump)) == SIMPLE_RETURN)
+ || (GET_CODE (label) == SIMPLE_RETURN))
+ return false;
+
+ /* Pahse 2d: Go to the target of the jump and check for aliveness of
+ LP_COUNT register. */
+ succ_bb = BLOCK_FOR_INSN (label);
+ if (!succ_bb)
+ {
+ gcc_assert (NEXT_INSN (label));
+ if (NOTE_INSN_BASIC_BLOCK_P (NEXT_INSN (label)))
+ succ_bb = NOTE_BASIC_BLOCK (NEXT_INSN (label));
+ else
+ succ_bb = BLOCK_FOR_INSN (NEXT_INSN (label));
+ }
+
+ if (succ_bb && REGNO_REG_SET_P (df_get_live_out (succ_bb), LP_COUNT))
+ return true;
+
+ return false;
+}
+
/* For ARC600:
A write to a core reg greater or equal to 32 must not be immediately
followed by a use. Anticipate the length requirement to insert a nop
int
arc_hazard (rtx_insn *pred, rtx_insn *succ)
{
- if (!TARGET_ARC600)
- return 0;
if (!pred || !INSN_P (pred) || !succ || !INSN_P (succ))
return 0;
- /* We might have a CALL to a non-returning function before a loop end.
- ??? Although the manual says that's OK (the target is outside the loop,
- and the loop counter unused there), the assembler barfs on this, so we
- must instert a nop before such a call too. */
- if (recog_memoized (succ) == CODE_FOR_doloop_end_i
- && (JUMP_P (pred) || CALL_P (pred)
- || GET_CODE (PATTERN (pred)) == SEQUENCE))
+
+ if (arc_loop_hazard (pred, succ))
return 4;
- return arc600_corereg_hazard (pred, succ);
+
+ if (TARGET_ARC600)
+ return arc600_corereg_hazard (pred, succ);
+
+ return 0;
}
/* Return length adjustment for INSN. */
;; Include DFA scheduluers
(include ("arc600.md"))
(include ("arc700.md"))
+(include ("arcEM.md"))
+(include ("arcHS.md"))
;; Predicates
(VUNSPEC_SR 26) ; blockage insn for writing to an auxiliary register
(VUNSPEC_TRAP_S 27) ; blockage insn for trap_s generation
(VUNSPEC_UNIMP_S 28) ; blockage insn for unimp_s generation
+ (VUNSPEC_NOP 29) ; volatile NOP
(R0_REG 0)
(R1_REG 1)
simd_varith_with_acc, simd_vlogic, simd_vlogic_with_acc,
simd_vcompare, simd_vpermute, simd_vpack, simd_vpack_with_acc,
simd_valign, simd_valign_with_acc, simd_vcontrol,
- simd_vspecial_3cycle, simd_vspecial_4cycle, simd_dma"
+ simd_vspecial_3cycle, simd_vspecial_4cycle, simd_dma, mul16_em, div_rem"
(cond [(eq_attr "is_sfunc" "yes")
(cond [(match_test "!TARGET_LONG_CALLS_SET && (!TARGET_MEDIUM_CALLS || GET_CODE (PATTERN (insn)) != COND_EXEC)") (const_string "call")
(match_test "flag_pic") (const_string "sfunc")]
;; Attribute describing the processor
-(define_attr "cpu" "none,ARC600,ARC700"
+(define_attr "cpu" "none,ARC600,ARC700,ARCEM,ARCHS"
(const (symbol_ref "arc_cpu_attr")))
;; true for compact instructions (those with _s suffix)
(symbol_ref "get_attr_length (NEXT_INSN (PREV_INSN (insn)))
- get_attr_length (insn)")))
+; for ARCv2 we need to disable/enable different instruction alternatives
+(define_attr "cpu_facility" "std,av1,av2"
+ (const_string "std"))
-(define_attr "enabled" "no,yes" (const_string "yes"))
+; We should consider all the instructions enabled until otherwise
+(define_attr "enabled" "no,yes"
+ (cond [(and (eq_attr "cpu_facility" "av1")
+ (match_test "TARGET_V2"))
+ (const_string "no")
+
+ (and (eq_attr "cpu_facility" "av2")
+ (not (match_test "TARGET_V2")))
+ (const_string "no")
+ ]
+ (const_string "yes")))
(define_attr "predicable" "no,yes" (const_string "no"))
;; if 'predicable' were not so brain-dead, we would specify:
stb%U0%V0 %1,%0"
[(set_attr "type" "move,move,move,move,move,move,move,load,store,load,load,store,store")
(set_attr "iscompact" "maybe,maybe,maybe,false,false,false,false,true,true,true,false,false,false")
- (set_attr "predicable" "yes,no,yes,yes,no,yes,yes,no,no,no,no,no,no")])
+ (set_attr "predicable" "yes,no,yes,yes,no,yes,yes,no,no,no,no,no,no")
+ (set_attr "cpu_facility" "*,*,av1,*,*,*,*,*,*,*,*,*,*")])
(define_expand "movhi"
[(set (match_operand:HI 0 "move_dest_operand" "")
mov%? %0,%1
mov%? %0,%S1%&
mov%? %0,%S1
- ldw%? %0,%1%&
- stw%? %1,%0%&
- ldw%U1%V1 %0,%1
- stw%U0%V0 %1,%0
- stw%U0%V0 %1,%0
- stw%U0%V0 %S1,%0"
+ ld%_%? %0,%1%&
+ st%_%? %1,%0%&
+ ld%_%U1%V1 %0,%1
+ st%_%U0%V0 %1,%0
+ st%_%U0%V0 %1,%0
+ st%_%U0%V0 %S1,%0"
[(set_attr "type" "move,move,move,move,move,move,move,move,load,store,load,store,store,store")
(set_attr "iscompact" "maybe,maybe,maybe,false,false,false,maybe_limm,false,true,true,false,false,false,false")
- (set_attr "predicable" "yes,no,yes,yes,no,yes,yes,yes,no,no,no,no,no,no")])
+ (set_attr "predicable" "yes,no,yes,yes,no,yes,yes,yes,no,no,no,no,no,no")
+ (set_attr "cpu_facility" "*,*,av1,*,*,*,*,*,*,*,*,*,*,*")])
(define_expand "movsi"
[(set (match_operand:SI 0 "move_dest_operand" "")
; Use default length for iscompact to allow for COND_EXEC. But set length
; of Crr to 4.
(set_attr "length" "*,*,*,4,4,4,4,8,8,*,8,*,*,*,*,*,*,*,*,8")
- (set_attr "predicable" "yes,no,yes,yes,no,no,yes,no,no,yes,yes,no,no,no,no,no,no,no,no,no")])
+ (set_attr "predicable" "yes,no,yes,yes,no,no,yes,no,no,yes,yes,no,no,no,no,no,no,no,no,no")
+ (set_attr "cpu_facility" "*,*,av1,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")])
;; Sometimes generated by the epilogue code. We don't want to
;; recognize these addresses in general, because the limm is costly,
(define_insn_and_split "*movsi_set_cc_insn"
[(set (match_operand:CC_ZN 2 "cc_set_register" "")
- (match_operator 3 "zn_compare_operator"
+ (match_operator:CC_ZN 3 "zn_compare_operator"
[(match_operand:SI 1 "nonmemory_operand" "cI,cL,Cal") (const_int 0)]))
(set (match_operand:SI 0 "register_operand" "=w,w,w")
(match_dup 1))]
(define_insn "unary_comparison"
[(set (match_operand:CC_ZN 0 "cc_set_register" "")
- (match_operator 3 "zn_compare_operator"
+ (match_operator:CC_ZN 3 "zn_compare_operator"
[(match_operator:SI 2 "unary_operator"
[(match_operand:SI 1 "register_operand" "c")])
(const_int 0)]))]
(define_insn "*commutative_binary_comparison"
[(set (match_operand:CC_ZN 0 "cc_set_register" "")
- (match_operator 5 "zn_compare_operator"
+ (match_operator:CC_ZN 5 "zn_compare_operator"
[(match_operator:SI 4 "commutative_operator"
[(match_operand:SI 1 "register_operand" "%c,c,c")
(match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")])
; Make sure to use the W class to not touch LP_COUNT.
(set (match_operand:SI 0 "register_operand" "=W,W,W")
(match_dup 4))]
- "TARGET_ARC700"
+ "!TARGET_ARC600_FAMILY"
"%O4.f %0,%1,%2 ; mult commutative"
[(set_attr "type" "compare,compare,compare")
(set_attr "cond" "set_zn,set_zn,set_zn")
(define_insn "*noncommutative_binary_comparison"
[(set (match_operand:CC_ZN 0 "cc_set_register" "")
- (match_operator 5 "zn_compare_operator"
+ (match_operator:CC_ZN 5 "zn_compare_operator"
[(match_operator:SI 4 "noncommutative_operator"
[(match_operand:SI 1 "register_operand" "c,c,c")
(match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")])
(set (match_operand:SI 0 "dest_reg_operand" "=w,w")
(plus:SI (match_dup 1) (match_dup 2)))]
""
- "ldw.a%V4 %3,[%0,%S2]"
+ "ld%_.a%V4 %3,[%0,%S2]"
[(set_attr "type" "load,load")
(set_attr "length" "4,8")])
(set (match_operand:SI 0 "dest_reg_operand" "=r,r")
(plus:SI (match_dup 1) (match_dup 2)))]
""
- "ldw.a%V4 %3,[%0,%S2]"
+ "ld%_.a%V4 %3,[%0,%S2]"
[(set_attr "type" "load,load")
(set_attr "length" "4,8")])
(set (match_operand:SI 0 "dest_reg_operand" "=w,w")
(plus:SI (match_dup 1) (match_dup 2)))]
""
- "ldw.x.a%V4 %3,[%0,%S2]"
+ "ld%_.x.a%V4 %3,[%0,%S2]"
[(set_attr "type" "load,load")
(set_attr "length" "4,8")])
(set (match_operand:SI 0 "dest_reg_operand" "=w")
(plus:SI (match_dup 1) (match_dup 2)))]
""
- "stw.a%V4 %3,[%0,%2]"
+ "st%_.a%V4 %3,[%0,%2]"
[(set_attr "type" "store")
(set_attr "length" "4")])
&& satisfies_constraint_Rcq (operands[0]))
return "sub%?.ne %0,%0,%0";
/* ??? might be good for speed on ARC600 too, *if* properly scheduled. */
- if ((TARGET_ARC700 || optimize_size)
+ if ((optimize_size && (!TARGET_ARC600_FAMILY))
&& rtx_equal_p (operands[1], constm1_rtx)
&& GET_CODE (operands[3]) == LTU)
return "sbc.cs %0,%0,%0";
(zero_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "0,q,0,c,Usd,Usd,m")))]
""
"@
- extw%? %0,%1%&
- extw%? %0,%1%&
+ ext%_%? %0,%1%&
+ ext%_%? %0,%1%&
bmsk%? %0,%1,15
- extw %0,%1
- ldw%? %0,%1%&
- ldw%U1 %0,%1
- ldw%U1%V1 %0,%1"
+ ext%_ %0,%1
+ ld%_%? %0,%1%&
+ ld%_%U1 %0,%1
+ ld%_%U1%V1 %0,%1"
[(set_attr "type" "unary,unary,unary,unary,load,load,load")
(set_attr "iscompact" "maybe,true,false,false,true,false,false")
(set_attr "predicable" "no,no,yes,no,no,no,no")])
(sign_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "Rcqq,c,m")))]
""
"@
- sexw%? %0,%1%&
- sexw %0,%1
- ldw.x%U1%V1 %0,%1"
+ sex%_%? %0,%1%&
+ sex%_ %0,%1
+ ld%_.x%U1%V1 %0,%1"
[(set_attr "type" "unary,unary,load")
(set_attr "iscompact" "true,false,false")])
(set_attr "cond" "canuse,canuse,canuse,canuse,canuse,canuse,nocond,canuse,nocond,nocond,nocond,nocond,canuse_limm,canuse_limm,canuse,canuse,nocond")
])
-;; ARC700/ARC600 multiply
+;; ARCv2 MPYW and MPYUW
+(define_expand "mulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" ""))
+ (sign_extend:SI (match_operand:HI 2 "nonmemory_operand" ""))))]
+ "TARGET_MPYW"
+ "{
+ if (CONSTANT_P (operands[2]))
+ {
+ emit_insn (gen_mulhisi3_imm (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "mulhisi3_imm"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r, r, r")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "0,r,0, 0, r"))
+ (match_operand:HI 2 "short_const_int_operand" "L,L,I,C16,C16")))]
+ "TARGET_MPYW"
+ "mpyw%? %0,%1,%2"
+ [(set_attr "length" "4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "mul16_em")
+ (set_attr "predicable" "yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse_limm,nocond")
+ ])
+
+(define_insn "mulhisi3_reg"
+ [(set (match_operand:SI 0 "register_operand" "=Rcqq,r,r")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" " 0,0,r"))
+ (sign_extend:SI (match_operand:HI 2 "nonmemory_operand" "Rcqq,r,r"))))]
+ "TARGET_MPYW"
+ "mpyw%? %0,%1,%2"
+ [(set_attr "length" "*,4,4")
+ (set_attr "iscompact" "maybe,false,false")
+ (set_attr "type" "mul16_em")
+ (set_attr "predicable" "yes,yes,no")
+ (set_attr "cond" "canuse,canuse,nocond")
+ ])
+
+(define_expand "umulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" ""))
+ (zero_extend:SI (match_operand:HI 2 "nonmemory_operand" ""))))]
+ "TARGET_MPYW"
+ "{
+ if (CONSTANT_P (operands[2]))
+ {
+ emit_insn (gen_umulhisi3_imm (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "umulhisi3_imm"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r, r, r")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" " 0, r,0, 0, r"))
+ (match_operand:HI 2 "short_const_int_operand" " L, L,I,C16,C16")))]
+ "TARGET_MPYW"
+ "mpyuw%? %0,%1,%2"
+ [(set_attr "length" "4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "mul16_em")
+ (set_attr "predicable" "yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse_limm,nocond")
+ ])
+
+(define_insn "umulhisi3_reg"
+ [(set (match_operand:SI 0 "register_operand" "=Rcqq, r, r")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" " 0, 0, r"))
+ (zero_extend:SI (match_operand:HI 2 "register_operand" " Rcqq, r, r"))))]
+ "TARGET_MPYW"
+ "mpyuw%? %0,%1,%2"
+ [(set_attr "length" "*,4,4")
+ (set_attr "iscompact" "maybe,false,false")
+ (set_attr "type" "mul16_em")
+ (set_attr "predicable" "yes,yes,no")
+ (set_attr "cond" "canuse,canuse,nocond")
+ ])
+
+;; ARC700/ARC600/V2 multiply
;; SI <- SI * SI
(define_expand "mulsi3"
(match_operand:SI 2 "nonmemory_operand" "")))]
""
{
- if (TARGET_ARC700 && !TARGET_NOMPY_SET)
+ if (TARGET_MPY)
{
if (!register_operand (operands[0], SImode))
{
(clobber (reg:SI LP_START))
(clobber (reg:SI LP_END))
(clobber (reg:CC CC_REG))]
- "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET
- && (!TARGET_ARC700 || TARGET_NOMPY_SET)
+ "!TARGET_ANY_MPY
&& SFUNC_CHECK_PREDICABLE"
"*return arc_output_libcall (\"__mulsi3\");"
[(set_attr "is_sfunc" "yes")
[(set (match_operand:SI 0 "mpy_dest_reg_operand" "=Rcr,r,r,Rcr,r")
(mult:SI (match_operand:SI 1 "register_operand" " 0,c,0,0,c")
(match_operand:SI 2 "nonmemory_operand" "cL,cL,I,Cal,Cal")))]
-"TARGET_ARC700 && !TARGET_NOMPY_SET"
+ "TARGET_ARC700_MPY"
"mpyu%? %0,%1,%2"
[(set_attr "length" "4,4,4,8,8")
(set_attr "type" "umulti")
(set_attr "predicable" "yes,no,no,yes,no")
(set_attr "cond" "canuse,nocond,canuse_limm,canuse,nocond")])
+; ARCv2 has no penalties between mpy and mpyu. So, we use mpy because of its
+; short variant. LP_COUNT constraints are still valid.
+(define_insn "mulsi3_v2"
+ [(set (match_operand:SI 0 "mpy_dest_reg_operand" "=Rcqq,Rcr, r,r,Rcr, r")
+ (mult:SI (match_operand:SI 1 "register_operand" "%0, 0, c,0, 0, c")
+ (match_operand:SI 2 "nonmemory_operand" " Rcqq, cL,cL,I,Cal,Cal")))]
+ "TARGET_MULTI"
+ "mpy%? %0,%1,%2"
+ [(set_attr "length" "*,4,4,4,8,8")
+ (set_attr "iscompact" "maybe,false,false,false,false,false")
+ (set_attr "type" "umulti")
+ (set_attr "predicable" "no,yes,no,no,yes,no")
+ (set_attr "cond" "nocond,canuse,nocond,canuse_limm,canuse,nocond")])
+
(define_expand "mulsidi3"
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(mult:DI (sign_extend:DI(match_operand:SI 1 "register_operand" ""))
(sign_extend:DI(match_operand:SI 2 "nonmemory_operand" ""))))]
- "(TARGET_ARC700 && !TARGET_NOMPY_SET)
- || TARGET_MUL64_SET
- || TARGET_MULMAC_32BY16_SET"
+ "TARGET_ANY_MPY"
"
{
- if (TARGET_ARC700 && !TARGET_NOMPY_SET)
+ if (TARGET_MPY)
{
operands[2] = force_reg (SImode, operands[2]);
if (!register_operand (operands[0], DImode))
[(set (match_operand:DI 0 "register_operand" "=&r")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%c"))
(sign_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET"
+ "TARGET_MPY"
"#"
"&& reload_completed"
[(const_int 0)]
rtx l0 = simplify_gen_subreg (word_mode, operands[0], DImode, lo);
rtx h0 = simplify_gen_subreg (word_mode, operands[0], DImode, hi);
emit_insn (gen_mulsi3_highpart (h0, operands[1], operands[2]));
- emit_insn (gen_mulsi3_700 (l0, operands[1], operands[2]));
+ emit_insn (gen_mulsi3 (l0, operands[1], operands[2]));
DONE;
}
[(set_attr "type" "multi")
(sign_extend:DI (match_operand:SI 1 "register_operand" "%0,c, 0,c"))
(sign_extend:DI (match_operand:SI 2 "extend_operand" "c,c, i,i")))
(const_int 32))))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET"
- "mpyh%? %0,%1,%2"
+ "TARGET_MPY"
+ "mpy%+%? %0,%1,%2"
[(set_attr "length" "4,4,8,8")
(set_attr "type" "multi")
(set_attr "predicable" "yes,no,yes,no")
(zero_extend:DI (match_operand:SI 1 "register_operand" "%0,c, 0,c"))
(zero_extend:DI (match_operand:SI 2 "extend_operand" "c,c, i,i")))
(const_int 32))))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET"
- "mpyhu%? %0,%1,%2"
+ "TARGET_MPY"
+ "mpy%+u%? %0,%1,%2"
[(set_attr "length" "4,4,8,8")
(set_attr "type" "multi")
(set_attr "predicable" "yes,no,yes,no")
(clobber (reg:DI MUL64_OUT_REG))
(clobber (reg:CC CC_REG))]
"!TARGET_BIG_ENDIAN
- && !TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET
- && (!TARGET_ARC700 || TARGET_NOMPY_SET)
+ && !TARGET_ANY_MPY
&& SFUNC_CHECK_PREDICABLE"
"*return arc_output_libcall (\"__umulsi3_highpart\");"
[(set_attr "is_sfunc" "yes")
(clobber (reg:DI MUL64_OUT_REG))
(clobber (reg:CC CC_REG))]
"TARGET_BIG_ENDIAN
- && !TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET
- && (!TARGET_ARC700 || TARGET_NOMPY_SET)
+ && !TARGET_ANY_MPY
&& SFUNC_CHECK_PREDICABLE"
"*return arc_output_libcall (\"__umulsi3_highpart\");"
[(set_attr "is_sfunc" "yes")
(zero_extend:DI (match_operand:SI 1 "register_operand" " 0, c, 0, 0, c"))
(match_operand:DI 2 "immediate_usidi_operand" "L, L, I, Cal, Cal"))
(const_int 32))))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET"
- "mpyhu%? %0,%1,%2"
+ "TARGET_MPY"
+ "mpy%+u%? %0,%1,%2"
[(set_attr "length" "4,4,4,8,8")
(set_attr "type" "multi")
(set_attr "predicable" "yes,no,no,yes,no")
(zero_extend:DI (match_operand:SI 1 "register_operand" ""))
(zero_extend:DI (match_operand:SI 2 "nonmemory_operand" "")))
(const_int 32))))]
- "TARGET_ARC700 || (!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET)"
+ "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET"
"
{
rtx target = operands[0];
- if (!TARGET_ARC700 || TARGET_NOMPY_SET)
+ if (!TARGET_MPY)
{
emit_move_insn (gen_rtx_REG (SImode, 0), operands[1]);
emit_move_insn (gen_rtx_REG (SImode, 1), operands[2]);
(zero_extend:DI(match_operand:SI 2 "nonmemory_operand" ""))))]
""
{
- if (TARGET_ARC700 && !TARGET_NOMPY_SET)
+ if (TARGET_MPY)
{
operands[2] = force_reg (SImode, operands[2]);
if (!register_operand (operands[0], DImode))
[(set (match_operand:DI 0 "dest_reg_operand" "=&r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%c"))
(zero_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET"
+ "TARGET_MPY"
"#"
"reload_completed"
[(const_int 0)]
rtx l0 = operand_subword (operands[0], lo, 0, DImode);
rtx h0 = operand_subword (operands[0], hi, 0, DImode);
emit_insn (gen_umulsi3_highpart (h0, operands[1], operands[2]));
- emit_insn (gen_mulsi3_700 (l0, operands[1], operands[2]));
+ emit_insn (gen_mulsi3 (l0, operands[1], operands[2]));
DONE;
}
[(set_attr "type" "umulti")
(clobber (reg:SI R12_REG))
(clobber (reg:DI MUL64_OUT_REG))
(clobber (reg:CC CC_REG))]
- "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET
- && (!TARGET_ARC700 || TARGET_NOMPY_SET)
+ "!TARGET_ANY_MPY
&& SFUNC_CHECK_PREDICABLE"
"*return arc_output_libcall (\"__umulsidi3\");"
[(set_attr "is_sfunc" "yes")
(clobber (reg:SI R12_REG))
(clobber (reg:DI MUL64_OUT_REG))
(clobber (reg:CC CC_REG))])]
- "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET
- && (!TARGET_ARC700 || TARGET_NOMPY_SET)
+ "!TARGET_ANY_MPY
&& peep2_regno_dead_p (1, TARGET_BIG_ENDIAN ? R1_REG : R0_REG)"
[(pc)]
{
adc %0,%1,%2"
; if we have a bad schedule after sched2, split.
"reload_completed
- && !optimize_size && TARGET_ARC700
+ && !optimize_size && (!TARGET_ARC600_FAMILY)
&& arc_scheduling_not_expected ()
&& arc_sets_cc_p (prev_nonnote_insn (insn))
/* If next comes a return or other insn that needs a delay slot,
sbc %0,%1,%2"
; if we have a bad schedule after sched2, split.
"reload_completed
- && !optimize_size && TARGET_ARC700
+ && !optimize_size && (!TARGET_ARC600_FAMILY)
&& arc_scheduling_not_expected ()
&& arc_sets_cc_p (prev_nonnote_insn (insn))
/* If next comes a return or other insn that needs a delay slot,
return \"bclr%? %0,%1,%M2%&\";
case 4:
return (INTVAL (operands[2]) == 0xff
- ? \"extb%? %0,%1%&\" : \"extw%? %0,%1%&\");
+ ? \"extb%? %0,%1%&\" : \"ext%_%? %0,%1%&\");
case 9: case 14: return \"bic%? %0,%1,%n2-1\";
case 18:
if (TARGET_BIG_ENDIAN)
xop[1] = adjust_address (operands[1], QImode,
INTVAL (operands[2]) == 0xff ? 3 : 2);
output_asm_insn (INTVAL (operands[2]) == 0xff
- ? \"ldb %0,%1\" : \"ldw %0,%1\",
+ ? \"ldb %0,%1\" : \"ld%_ %0,%1\",
xop);
return \"\";
}
- return INTVAL (operands[2]) == 0xff ? \"ldb %0,%1\" : \"ldw %0,%1\";
+ return INTVAL (operands[2]) == 0xff ? \"ldb %0,%1\" : \"ld%_ %0,%1\";
default:
gcc_unreachable ();
}
;; Next come the scc insns.
(define_expand "cstoresi4"
- [(set (reg:CC CC_REG)
- (compare:CC (match_operand:SI 2 "nonmemory_operand" "")
- (match_operand:SI 3 "nonmemory_operand" "")))
- (set (match_operand:SI 0 "dest_reg_operand" "")
- (match_operator:SI 1 "ordered_comparison_operator" [(reg CC_REG)
- (const_int 0)]))]
+ [(set (match_operand:SI 0 "dest_reg_operand" "")
+ (match_operator:SI 1 "ordered_comparison_operator" [(match_operand:SI 2 "nonmemory_operand" "")
+ (match_operand:SI 3 "nonmemory_operand" "")]))]
""
{
- gcc_assert (XEXP (operands[1], 0) == operands[2]);
- gcc_assert (XEXP (operands[1], 1) == operands[3]);
- operands[1] = gen_compare_reg (operands[1], SImode);
- emit_insn (gen_scc_insn (operands[0], operands[1]));
- DONE;
+ if (!TARGET_CODE_DENSITY)
+ {
+ gcc_assert (XEXP (operands[1], 0) == operands[2]);
+ gcc_assert (XEXP (operands[1], 1) == operands[3]);
+ operands[1] = gen_compare_reg (operands[1], SImode);
+ emit_insn (gen_scc_insn (operands[0], operands[1]));
+ DONE;
+ }
})
(define_mode_iterator SDF [SF DF])
return \"ld.as %0,[%1,%2]%&\";
case HImode:
if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned)
- return \"ldw.as %0,[%1,%2]\";
- return \"ldw.x.as %0,[%1,%2]\";
+ return \"ld%_.as %0,[%1,%2]\";
+ return \"ld%_.x.as %0,[%1,%2]\";
case QImode:
if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned)
return \"ldb%? %0,[%1,%2]%&\";
2 of these are for alignment, and are anticipated in the length
of the ADDR_DIFF_VEC. */
if (unalign && !satisfies_constraint_Rcq (xop[0]))
- s = \"add2 %2,pcl,%0\n\tld_s%2,[%2,12]\";
+ s = \"add2 %2,pcl,%0\n\tld_s %2,[%2,12]\";
else if (unalign)
s = \"add_s %2,%0,2\n\tld.as %2,[pcl,%2]\";
else
{
if (satisfies_constraint_Rcq (xop[0]))
{
- s = \"add_s %2,%0,%1\n\tldw.as %2,[pcl,%2]\";
+ s = \"add_s %2,%0,%1\n\tld%_.as %2,[pcl,%2]\";
xop[1] = GEN_INT ((10 - unalign) / 2U);
}
else
{
- s = \"add1 %2,pcl,%0\n\tldw_s %2,[%2,%1]\";
+ s = \"add1 %2,pcl,%0\n\tld%__s %2,[%2,%1]\";
xop[1] = GEN_INT (10 + unalign);
}
}
{
if (satisfies_constraint_Rcq (xop[0]))
{
- s = \"add_s %2,%0,%1\n\tldw.x.as %2,[pcl,%2]\";
+ s = \"add_s %2,%0,%1\n\tld%_.x.as %2,[pcl,%2]\";
xop[1] = GEN_INT ((10 - unalign) / 2U);
}
else
{
- s = \"add1 %2,pcl,%0\n\tldw_s.x %2,[%2,%1]\";
+ s = \"add1 %2,pcl,%0\n\tld%__s.x %2,[%2,%1]\";
xop[1] = GEN_INT (10 + unalign);
}
}
(set_attr "cond" "canuse")
(set_attr "length" "2")])
+(define_insn "nopv"
+ [(unspec_volatile [(const_int 0)] VUNSPEC_NOP)]
+ ""
+ "nop%?"
+ [(set_attr "type" "misc")
+ (set_attr "iscompact" "true")
+ (set_attr "length" "2")])
+
;; Special pattern to flush the icache.
;; ??? Not sure what to do here. Some ARC's are known to support this.
(set (match_operand:SI 4 "register_operand" "")
(mult:SI (match_operand:SI 2 "register_operand")
(match_operand:SI 3 "nonmemory_operand" "")))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET
+ "TARGET_ARC700_MPY
&& (rtx_equal_p (operands[0], operands[2])
|| rtx_equal_p (operands[0], operands[3]))
&& peep2_regno_dead_p (0, CC_REG)
(set (match_operand:SI 4 "register_operand" "")
(mult:SI (match_operand:SI 2 "register_operand")
(match_operand:SI 3 "nonmemory_operand" "")))]
- "TARGET_ARC700 && !TARGET_NOMPY_SET
+ "TARGET_ARC700_MPY
&& (rtx_equal_p (operands[0], operands[2])
|| rtx_equal_p (operands[0], operands[3]))
&& peep2_regno_dead_p (2, CC_REG)"
(clrsb:HI (match_operand:HI 1 "general_operand" "cL,Cal"))))]
"TARGET_NORM"
"@
- normw \t%0, %1
- normw \t%0, %S1"
+ norm%_ \t%0, %1
+ norm%_ \t%0, %S1"
[(set_attr "length" "4,8")
(set_attr "type" "two_cycle_core,two_cycle_core")])
= gen_rtx_REG (Pmode,
arc_return_address_regs[arc_compute_function_type (cfun)]);
+ if (arc_compute_function_type (cfun) == ARC_FUNCTION_ILINK1
+ && TARGET_V2)
+ {
+ return \"rtie\";
+ }
if (TARGET_PAD_RETURN)
arc_pad_return ();
output_asm_insn (\"j%!%* [%0]%&\", ®);
[(set_attr "type" "return")
; predicable won't help here since the canonical rtl looks different
; for branches.
- (set_attr "cond" "canuse")
- (set (attr "iscompact")
+ (set (attr "cond")
+ (cond [(and (eq (symbol_ref "arc_compute_function_type (cfun)")
+ (symbol_ref "ARC_FUNCTION_ILINK1"))
+ (match_test "TARGET_V2"))
+ (const_string "nocond")]
+ (const_string "canuse")))
+ (set (attr "iscompact")
(cond [(eq (symbol_ref "arc_compute_function_type (cfun)")
(symbol_ref "ARC_FUNCTION_NORMAL"))
(const_string "maybe")]
(if_then_else (match_operator 0 "proper_comparison_operator"
[(reg CC_REG) (const_int 0)])
(simple_return) (pc)))]
- "reload_completed"
+ "reload_completed
+ && !(TARGET_V2
+ && arc_compute_function_type (cfun) == ARC_FUNCTION_ILINK1)"
{
rtx xop[2];
xop[0] = operands[0];
(define_expand "doloop_end"
[(use (match_operand 0 "register_operand" ""))
(use (label_ref (match_operand 1 "" "")))]
- "TARGET_ARC600 || TARGET_ARC700"
+ "!TARGET_ARC601"
{
/* We could do smaller bivs with biv widening, and wider bivs by having
a high-word counter in an outer loop - but punt on this for now. */
;; this would not work right for -0. OTOH optabs.c has already code
;; to synthesyze negate by flipping the sign bit.
+;;V2 instructions
+(define_insn "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand" "= r,r")
+ (bswap:SI (match_operand:SI 1 "nonmemory_operand" "rL,Cal")))]
+ "TARGET_V2 && TARGET_SWAP"
+ "swape %0, %1"
+ [(set_attr "length" "4,8")
+ (set_attr "type" "two_cycle_core")])
+
+(define_expand "prefetch"
+ [(prefetch (match_operand:SI 0 "address_operand" "")
+ (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))]
+ "TARGET_HS"
+ "")
+
+(define_insn "prefetch_1"
+ [(prefetch (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "const_int_operand" "n")
+ (match_operand:SI 2 "const_int_operand" "n"))]
+ "TARGET_HS"
+ {
+ if (INTVAL (operands[1]))
+ return "prefetchw [%0]";
+ else
+ return "prefetch [%0]";
+ }
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn "prefetch_2"
+ [(prefetch (plus:SI (match_operand:SI 0 "register_operand" "r,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,Cm2,Cal"))
+ (match_operand:SI 2 "const_int_operand" "n,n,n")
+ (match_operand:SI 3 "const_int_operand" "n,n,n"))]
+ "TARGET_HS"
+ {
+ if (INTVAL (operands[2]))
+ return "prefetchw [%0, %1]";
+ else
+ return "prefetch [%0, %1]";
+ }
+ [(set_attr "type" "load")
+ (set_attr "length" "4,4,8")])
+
+(define_insn "prefetch_3"
+ [(prefetch (match_operand:SI 0 "address_operand" "p")
+ (match_operand:SI 1 "const_int_operand" "n")
+ (match_operand:SI 2 "const_int_operand" "n"))]
+ "TARGET_HS"
+ {
+ operands[0] = gen_rtx_MEM (SImode, operands[0]);
+ if (INTVAL (operands[1]))
+ return "prefetchw%U0 %0";
+ else
+ return "prefetch%U0 %0";
+ }
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r, r, r")
+ (div:SI (match_operand:SI 1 "nonmemory_operand" "0,r,Cal,0,r,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r, r,L,L,I,Cal,Cal")))]
+ "TARGET_DIVREM"
+ "div%? %0, %1, %2"
+ [(set_attr "length" "4,4,8,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "div_rem")
+ (set_attr "predicable" "yes,no,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r, r, r")
+ (udiv:SI (match_operand:SI 1 "nonmemory_operand" "0,r,Cal,0,r,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r, r,L,L,I,Cal,Cal")))]
+ "TARGET_DIVREM"
+ "divu%? %0, %1, %2"
+ [(set_attr "length" "4,4,8,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "div_rem")
+ (set_attr "predicable" "yes,no,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+(define_insn "modsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r, r, r")
+ (mod:SI (match_operand:SI 1 "nonmemory_operand" "0,r,Cal,0,r,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r, r,L,L,I,Cal,Cal")))]
+ "TARGET_DIVREM"
+ "rem%? %0, %1, %2"
+ [(set_attr "length" "4,4,8,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "div_rem")
+ (set_attr "predicable" "yes,no,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+(define_insn "umodsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r, r, r")
+ (umod:SI (match_operand:SI 1 "nonmemory_operand" "0,r,Cal,0,r,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r, r,L,L,I,Cal,Cal")))]
+ "TARGET_DIVREM"
+ "remu%? %0, %1, %2"
+ [(set_attr "length" "4,4,8,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "div_rem")
+ (set_attr "predicable" "yes,no,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+;; SETcc instructions
+(define_code_iterator arcCC_cond [eq ne gt lt ge le])
+
+(define_insn "arcset<code>"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
+ (arcCC_cond:SI (match_operand:SI 1 "nonmemory_operand" "0,r,0,r,0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r,L,L,I,n,n")))]
+ "TARGET_V2 && TARGET_CODE_DENSITY"
+ "set<code>%? %0, %1, %2"
+ [(set_attr "length" "4,4,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "compare")
+ (set_attr "predicable" "yes,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+(define_insn "arcsetltu"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r, r, r")
+ (ltu:SI (match_operand:SI 1 "nonmemory_operand" "0,r,0,r,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r,L,L,I, n, n")))]
+ "TARGET_V2 && TARGET_CODE_DENSITY"
+ "setlo%? %0, %1, %2"
+ [(set_attr "length" "4,4,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "compare")
+ (set_attr "predicable" "yes,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+(define_insn "arcsetgeu"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r, r, r")
+ (geu:SI (match_operand:SI 1 "nonmemory_operand" "0,r,0,r,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,r,L,L,I, n, n")))]
+ "TARGET_V2 && TARGET_CODE_DENSITY"
+ "seths%? %0, %1, %2"
+ [(set_attr "length" "4,4,4,4,4,8,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "compare")
+ (set_attr "predicable" "yes,no,yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,canuse,nocond,nocond,canuse,nocond")
+ ])
+
+;; Special cases of SETCC
+(define_insn_and_split "arcsethi"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r,r")
+ (gtu:SI (match_operand:SI 1 "nonmemory_operand" "r,r, r,r")
+ (match_operand:SI 2 "nonmemory_operand" "0,r,C62,n")))]
+ "TARGET_V2 && TARGET_CODE_DENSITY"
+ "setlo%? %0, %2, %1"
+ "reload_completed
+ && CONST_INT_P (operands[2])
+ && satisfies_constraint_C62 (operands[2])"
+ [(const_int 0)]
+ "{
+ /* sethi a,b,u6 => seths a,b,u6 + 1. */
+ operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
+ emit_insn (gen_arcsetgeu (operands[0], operands[1], operands[2]));
+ DONE;
+ }"
+ [(set_attr "length" "4,4,4,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "compare")
+ (set_attr "predicable" "yes,no,no,no")
+ (set_attr "cond" "canuse,nocond,nocond,nocond")]
+)
+
+(define_insn_and_split "arcsetls"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r,r")
+ (leu:SI (match_operand:SI 1 "nonmemory_operand" "r,r, r,r")
+ (match_operand:SI 2 "nonmemory_operand" "0,r,C62,n")))]
+ "TARGET_V2 && TARGET_CODE_DENSITY"
+ "seths%? %0, %2, %1"
+ "reload_completed
+ && CONST_INT_P (operands[2])
+ && satisfies_constraint_C62 (operands[2])"
+ [(const_int 0)]
+ "{
+ /* setls a,b,u6 => setlo a,b,u6 + 1. */
+ operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
+ emit_insn (gen_arcsetltu (operands[0], operands[1], operands[2]));
+ DONE;
+ }"
+ [(set_attr "length" "4,4,4,8")
+ (set_attr "iscompact" "false")
+ (set_attr "type" "compare")
+ (set_attr "predicable" "yes,no,no,no")
+ (set_attr "cond" "canuse,nocond,nocond,nocond")]
+)
+
+; Any mode that needs to be solved by secondary reload
+(define_mode_iterator SRI [QI HI])
+
+(define_expand "reload_<mode>_load"
+ [(parallel [(match_operand:SRI 0 "register_operand" "=r")
+ (match_operand:SRI 1 "memory_operand" "m")
+ (match_operand:SI 2 "register_operand" "=&r")])]
+ ""
+{
+ arc_secondary_reload_conv (operands[0], operands[1], operands[2], false);
+ DONE;
+})
+
+(define_expand "reload_<mode>_store"
+ [(parallel [(match_operand:SRI 0 "memory_operand" "=m")
+ (match_operand:SRI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "=&r")])]
+ ""
+{
+ arc_secondary_reload_conv (operands[1], operands[0], operands[2], true);
+ DONE;
+})
+
+
+(define_insn "extzvsi"
+ [(set (match_operand:SI 0 "register_operand" "=r , r , r, r, r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "0 , r , 0, 0, r")
+ (match_operand:SI 2 "const_int_operand" "C3p, C3p, i, i, i")
+ (match_operand:SI 3 "const_int_operand" "i , i , i, i, i")))]
+ "TARGET_HS && TARGET_BARREL_SHIFTER"
+ {
+ int assemble_op2 = (((INTVAL (operands[2]) - 1) & 0x1f) << 5) | (INTVAL (operands[3]) & 0x1f);
+ operands[2] = GEN_INT (assemble_op2);
+ return "xbfu%? %0,%1,%2";
+ }
+ [(set_attr "type" "shift")
+ (set_attr "iscompact" "false")
+ (set_attr "length" "4,4,4,8,8")
+ (set_attr "predicable" "yes,no,no,yes,no")
+ (set_attr "cond" "canuse,nocond,nocond,canuse,nocond")])
;; include the arc-FPX instructions
(include "fpx.md")