aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/arc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/arc')
-rw-r--r--gcc/config/arc/arc-modes.def1
-rw-r--r--gcc/config/arc/arc-protos.h1
-rw-r--r--gcc/config/arc/arc.cc32
-rw-r--r--gcc/config/arc/arc.md163
-rw-r--r--gcc/config/arc/predicates.md9
5 files changed, 200 insertions, 6 deletions
diff --git a/gcc/config/arc/arc-modes.def b/gcc/config/arc/arc-modes.def
index cab46d7..7c7dff9 100644
--- a/gcc/config/arc/arc-modes.def
+++ b/gcc/config/arc/arc-modes.def
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
CC_MODE (CC_ZN);
CC_MODE (CC_Z);
+CC_MODE (CC_V);
CC_MODE (CC_C);
CC_MODE (CC_FP_GT);
CC_MODE (CC_FP_GE);
diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h
index cd82aa1..2db643c 100644
--- a/gcc/config/arc/arc-protos.h
+++ b/gcc/config/arc/arc-protos.h
@@ -55,6 +55,7 @@ extern bool arc_check_mov_const (HOST_WIDE_INT );
extern bool arc_split_mov_const (rtx *);
extern bool arc_can_use_return_insn (void);
extern bool arc_split_move_p (rtx *);
+extern void arc_gen_unlikely_cbranch (enum rtx_code, machine_mode, rtx);
#endif /* RTX_CODE */
diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc
index 3b4b038..bb5db97 100644
--- a/gcc/config/arc/arc.cc
+++ b/gcc/config/arc/arc.cc
@@ -1436,6 +1436,13 @@ get_arc_condition_code (rtx comparison)
case GEU : return ARC_CC_NC;
default : gcc_unreachable ();
}
+ case E_CC_Vmode:
+ switch (GET_CODE (comparison))
+ {
+ case EQ : return ARC_CC_NV;
+ case NE : return ARC_CC_V;
+ default : gcc_unreachable ();
+ }
case E_CC_FP_GTmode:
if (TARGET_ARGONAUT_SET && TARGET_SPFP)
switch (GET_CODE (comparison))
@@ -1546,6 +1553,13 @@ arc_select_cc_mode (enum rtx_code op, rtx x, rtx y)
machine_mode mode = GET_MODE (x);
rtx x1;
+ /* Matches all instructions which can do .f and clobbers only Z flag. */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && y == const0_rtx
+ && GET_CODE (x) == MULT
+ && (op == EQ || op == NE))
+ return CC_Zmode;
+
/* For an operation that sets the condition codes as a side-effect, the
C and V flags is not set as for cmp, so we can only use comparisons where
this doesn't matter. (For LT and GE we can use "mi" and "pl"
@@ -8218,8 +8232,7 @@ hwloop_optimize (hwloop_info loop)
insn = emit_insn (gen_arc_lp (loop->start_label,
loop->end_label));
- seq = get_insns ();
- end_sequence ();
+ seq = end_sequence ();
entry_after = BB_END (entry_bb);
if (!single_succ_p (entry_bb) || vec_safe_length (loop->incoming) > 1
@@ -11544,6 +11557,21 @@ arc_libm_function_max_error (unsigned cfn, machine_mode mode,
return default_libm_function_max_error (cfn, mode, boundary_p);
}
+void
+arc_gen_unlikely_cbranch (enum rtx_code cmp, machine_mode cc_mode, rtx label)
+{
+ rtx cc_reg, x;
+
+ cc_reg = gen_rtx_REG (cc_mode, CC_REG);
+ label = gen_rtx_LABEL_REF (VOIDmode, label);
+
+ x = gen_rtx_fmt_ee (cmp, VOIDmode, cc_reg, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx);
+
+ emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
+}
+
+
#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
#define TARGET_USE_ANCHORS_FOR_SYMBOL_P arc_use_anchors_for_symbol_p
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 1344d9c..d119464 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -842,6 +842,9 @@ archs4x, archs4xd"
; Optab prefix for sign/zero-extending operations
(define_code_attr su_optab [(sign_extend "") (zero_extend "u")])
+;; Code iterator for sign/zero extension
+(define_code_iterator ANY_EXTEND [sign_extend zero_extend])
+
(define_insn "*<SEZ_prefix>xt<SQH_postfix>_cmp0_noout"
[(set (match_operand 0 "cc_set_register" "")
(compare:CC_ZN (SEZ:SI (match_operand:SQH 1 "register_operand" "r"))
@@ -1068,11 +1071,67 @@ archs4x, archs4xd"
(set_attr "cond" "set_zn")
(set_attr "length" "*,4,4,4,8")])
-;; The next two patterns are for plos, ior, xor, and, and mult.
+(define_expand "<su_optab>mulvsi4"
+ [(ANY_EXTEND:DI (match_operand:SI 0 "register_operand"))
+ (ANY_EXTEND:DI (match_operand:SI 1 "register_operand"))
+ (ANY_EXTEND:DI (match_operand:SI 2 "register_operand"))
+ (label_ref (match_operand 3 "" ""))]
+ "TARGET_MPY"
+ {
+ emit_insn (gen_<su_optab>mulsi3_Vcmp (operands[0], operands[1],
+ operands[2]));
+ arc_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+ DONE;
+ })
+
+(define_insn "<su_optab>mulsi3_Vcmp"
+ [(parallel
+ [(set
+ (reg:CC_V CC_REG)
+ (compare:CC_V
+ (mult:DI
+ (ANY_EXTEND:DI (match_operand:SI 1 "register_operand" "%0,r,r,r"))
+ (ANY_EXTEND:DI (match_operand:SI 2 "nonmemory_operand" "I,L,r,C32")))
+ (ANY_EXTEND:DI (mult:SI (match_dup 1) (match_dup 2)))))
+ (set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (mult:SI (match_dup 1) (match_dup 2)))])]
+ "register_operand (operands[1], SImode)
+ || register_operand (operands[2], SImode)"
+ "mpy<su_optab>.f\\t%0,%1,%2"
+ [(set_attr "length" "4,4,4,8")
+ (set_attr "type" "multi")])
+
+(define_insn "*mulsi3_cmp0"
+ [(set (reg:CC_Z CC_REG)
+ (compare:CC_Z
+ (mult:SI
+ (match_operand:SI 1 "register_operand" "%r,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "rL,I,i"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (mult:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_MPY"
+ "mpy%?.f\\t%0,%1,%2"
+ [(set_attr "length" "4,4,8")
+ (set_attr "type" "multi")])
+
+(define_insn "*mulsi3_cmp0_noout"
+ [(set (reg:CC_Z CC_REG)
+ (compare:CC_Z
+ (mult:SI
+ (match_operand:SI 0 "register_operand" "%r,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "rL,I,i"))
+ (const_int 0)))]
+ "TARGET_MPY"
+ "mpy%?.f\\t0,%0,%1"
+ [(set_attr "length" "4,4,8")
+ (set_attr "type" "multi")])
+
+;; The next two patterns are for plus, ior, xor, and.
(define_insn "*commutative_binary_cmp0_noout"
[(set (match_operand 0 "cc_set_register" "")
(match_operator 4 "zn_compare_operator"
- [(match_operator:SI 3 "commutative_operator"
+ [(match_operator:SI 3 "commutative_operator_sans_mult"
[(match_operand:SI 1 "register_operand" "%r,r")
(match_operand:SI 2 "nonmemory_operand" "rL,Cal")])
(const_int 0)]))]
@@ -1085,7 +1144,7 @@ archs4x, archs4xd"
(define_insn "*commutative_binary_cmp0"
[(set (match_operand 3 "cc_set_register" "")
(match_operator 5 "zn_compare_operator"
- [(match_operator:SI 4 "commutative_operator"
+ [(match_operator:SI 4 "commutative_operator_sans_mult"
[(match_operand:SI 1 "register_operand" "%0, 0,r,r")
(match_operand:SI 2 "nonmemory_operand" "rL,rI,r,Cal")])
(const_int 0)]))
@@ -2734,6 +2793,56 @@ archs4x, archs4xd"
}
[(set_attr "length" "8")])
+(define_insn "addsi3_v"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r, r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r,r,0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,L,I,C32")))
+ (set (reg:CC_V CC_REG)
+ (compare:CC_V (sign_extend:DI (plus:SI (match_dup 1)
+ (match_dup 2)))
+ (plus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))))]
+ ""
+ "add.f\\t%0,%1,%2"
+ [(set_attr "cond" "set")
+ (set_attr "type" "compare")
+ (set_attr "length" "4,4,4,8")])
+
+(define_expand "addvsi4"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")
+ (label_ref (match_operand 3 "" ""))]
+ ""
+ "emit_insn (gen_addsi3_v (operands[0], operands[1], operands[2]));
+ arc_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+ DONE;")
+
+(define_insn "addsi3_c"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r, r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r,r,0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,L,I,C32")))
+ (set (reg:CC_C CC_REG)
+ (compare:CC_C (plus:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 1)))]
+ ""
+ "add.f\\t%0,%1,%2"
+ [(set_attr "cond" "set")
+ (set_attr "type" "compare")
+ (set_attr "length" "4,4,4,8")])
+
+(define_expand "uaddvsi4"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")
+ (label_ref (match_operand 3 "" ""))]
+ ""
+ "emit_insn (gen_addsi3_c (operands[0], operands[1], operands[2]));
+ arc_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]);
+ DONE;")
+
+
(define_insn "add_f"
[(set (reg:CC_C CC_REG)
(compare:CC_C
@@ -2914,6 +3023,54 @@ archs4x, archs4xd"
(set_attr "cpu_facility" "*,cd,*,*,*,*,*,*,*,*")
])
+(define_insn "subsi3_v"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r, r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r,r,0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,L,I,C32")))
+ (set (reg:CC_V CC_REG)
+ (compare:CC_V (sign_extend:DI (minus:SI (match_dup 1)
+ (match_dup 2)))
+ (minus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))))]
+ ""
+ "sub.f\\t%0,%1,%2"
+ [(set_attr "cond" "set")
+ (set_attr "type" "compare")
+ (set_attr "length" "4,4,4,8")])
+
+(define_expand "subvsi4"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")
+ (label_ref (match_operand 3 "" ""))]
+ ""
+ "emit_insn (gen_subsi3_v (operands[0], operands[1], operands[2]));
+ arc_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+ DONE;")
+
+(define_insn "subsi3_c"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r, r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r,r,0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,L,I,C32")))
+ (set (reg:CC_C CC_REG)
+ (compare:CC_C (match_dup 1)
+ (match_dup 2)))]
+ ""
+ "sub.f\\t%0,%1,%2"
+ [(set_attr "cond" "set")
+ (set_attr "type" "compare")
+ (set_attr "length" "4,4,4,8")])
+
+(define_expand "usubvsi4"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")
+ (label_ref (match_operand 3 "" ""))]
+ ""
+ "emit_insn (gen_subsi3_c (operands[0], operands[1], operands[2]));
+ arc_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]);
+ DONE;")
+
(define_expand "subdi3"
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md
index 209cda9..f506cee 100644
--- a/gcc/config/arc/predicates.md
+++ b/gcc/config/arc/predicates.md
@@ -419,6 +419,8 @@
return code == EQ || code == NE;
case E_CC_Cmode:
return code == LTU || code == GEU;
+ case E_CC_Vmode:
+ return code == EQ || code == NE;
case E_CC_FP_GTmode:
return code == GT || code == UNLE;
case E_CC_FP_GEmode:
@@ -451,7 +453,12 @@
})
(define_predicate "equality_comparison_operator"
- (match_code "eq, ne"))
+ (match_code "eq, ne")
+ {
+ machine_mode opmode = GET_MODE (XEXP (op, 0));
+ return opmode != CC_Vmode;
+ }
+)
(define_predicate "ge_lt_comparison_operator"
(match_code "ge, lt"))