===================================================================
@@ -2059,7 +2059,7 @@
void
expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
{
- rtx (*branch_expander) (rtx, rtx) = gen_branch_true;
+ rtx (*branch_expander) (rtx) = gen_branch_true;
comparison = prepare_cbranch_operands (operands, SImode, comparison);
switch (comparison)
{
@@ -2071,7 +2071,7 @@
emit_insn (gen_rtx_SET (VOIDmode, get_t_reg_rtx (),
gen_rtx_fmt_ee (comparison, SImode,
operands[1], operands[2])));
- rtx jump = emit_jump_insn (branch_expander (operands[3], get_t_reg_rtx ()));
+ rtx jump = emit_jump_insn (branch_expander (operands[3]));
if (probability >= 0)
add_reg_note (jump, REG_BR_PROB, GEN_INT (probability));
}
@@ -2123,7 +2123,7 @@
if (TARGET_CMPEQDI_T)
{
emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
- emit_jump_insn (gen_branch_true (operands[3], get_t_reg_rtx ()));
+ emit_jump_insn (gen_branch_true (operands[3]));
return true;
}
msw_skip = NE;
@@ -2150,7 +2150,7 @@
if (TARGET_CMPEQDI_T)
{
emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
- emit_jump_insn (gen_branch_false (operands[3], get_t_reg_rtx ()));
+ emit_jump_insn (gen_branch_false (operands[3]));
return true;
}
msw_taken = NE;
@@ -2281,6 +2281,43 @@
return true;
}
+/* Given an operand, return 1 if the evaluated operand plugged into an
+ if_then_else will result in a branch_true, 0 if branch_false, or
+ -1 if neither nor applies. The truth table goes like this:
+
+ op | cmpval | code | result
+ ---------+--------+---------+--------------------
+ T (0) | 0 | EQ (1) | 0 = 0 ^ (0 == 1)
+ T (0) | 1 | EQ (1) | 1 = 0 ^ (1 == 1)
+ T (0) | 0 | NE (0) | 1 = 0 ^ (0 == 0)
+ T (0) | 1 | NE (0) | 0 = 0 ^ (1 == 0)
+ !T (1) | 0 | EQ (1) | 1 = 1 ^ (0 == 1)
+ !T (1) | 1 | EQ (1) | 0 = 1 ^ (1 == 1)
+ !T (1) | 0 | NE (0) | 0 = 1 ^ (0 == 0)
+ !T (1) | 1 | NE (0) | 1 = 1 ^ (1 == 0) */
+int
+sh_eval_treg_value (rtx op)
+{
+ enum rtx_code code = GET_CODE (op);
+ if ((code != EQ && code != NE) || !CONST_INT_P (XEXP (op, 1)))
+ return -1;
+
+ int cmpop = code == EQ ? 1 : 0;
+ int cmpval = INTVAL (XEXP (op, 1));
+ if (cmpval != 0 && cmpval != 1)
+ return -1;
+
+ int t;
+ if (t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))))
+ t = 0;
+ else if (negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))))
+ t = 1;
+ else
+ return -1;
+
+ return t ^ (cmpval == cmpop);
+}
+
/* Emit INSN, possibly in a PARALLEL with an USE of fpscr for SH4. */
static void
@@ -2485,9 +2522,9 @@
sh_emit_set_t_insn (gen_ieee_ccmpeqsf_t (op0, op1), mode);
if (branch_code == code)
- emit_jump_insn (gen_branch_true (operands[3], get_t_reg_rtx ()));
+ emit_jump_insn (gen_branch_true (operands[3]));
else
- emit_jump_insn (gen_branch_false (operands[3], get_t_reg_rtx ()));
+ emit_jump_insn (gen_branch_false (operands[3]));
}
void
@@ -2521,7 +2558,7 @@
{
lab = gen_label_rtx ();
sh_emit_scc_to_t (EQ, op0, op1);
- emit_jump_insn (gen_branch_true (lab, get_t_reg_rtx ()));
+ emit_jump_insn (gen_branch_true (lab));
code = GT;
}
else
===================================================================
@@ -5322,8 +5322,8 @@
emit_insn (gen_movsi (operands[0], operands[1]));
emit_jump_insn (INTVAL (operands[3])
- ? gen_branch_true (skip_neg_label, get_t_reg_rtx ())
- : gen_branch_false (skip_neg_label, get_t_reg_rtx ()));
+ ? gen_branch_true (skip_neg_label)
+ : gen_branch_false (skip_neg_label));
emit_label_after (skip_neg_label,
emit_insn (gen_negsi2 (operands[0], operands[1])));
@@ -5391,8 +5391,8 @@
emit_insn (gen_movsi (high_dst, high_src));
emit_jump_insn (INTVAL (operands[3])
- ? gen_branch_true (skip_neg_label, get_t_reg_rtx ())
- : gen_branch_false (skip_neg_label, get_t_reg_rtx ()));
+ ? gen_branch_true (skip_neg_label)
+ : gen_branch_false (skip_neg_label));
if (!INTVAL (operands[3]))
emit_insn (gen_clrt ());
@@ -5575,11 +5575,57 @@
[(set (match_operand:SI 0 "arith_reg_dest")
(zero_extend:SI (match_operand:QIHI 1 "zero_extend_operand")))])
-(define_insn "*zero_extend<mode>si2_compact"
+(define_insn_and_split "*zero_extend<mode>si2_compact"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(zero_extend:SI (match_operand:QIHI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"extu.<bw> %1,%0"
+ "&& can_create_pseudo_p ()"
+ [(set (match_dup 0) (match_dup 2))]
+{
+ /* Sometimes combine fails to combine a T bit or negated T bit store to a
+ reg with a following zero extension. In the split pass after combine,
+ try to figure the extended reg was set. If it originated from the T
+ bit we can replace the zero extension with a reg move, which will be
+ eliminated. Notice that this also helps the *cbranch_t splitter when
+ it tries to post-combine tests and conditional branches, as it does not
+ check for zero extensions. */
+ rtx ext_reg;
+ if (REG_P (operands[1]))
+ ext_reg = operands[1];
+ else if (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1])))
+ ext_reg = SUBREG_REG (operands[1]);
+ else
+ FAIL;
+
+ /* Reg moves must be of the same mode. */
+ if (GET_MODE (ext_reg) != SImode)
+ FAIL;
+
+ operands[2] = NULL_RTX;
+ for (rtx i = prev_nonnote_insn_bb (curr_insn); i != NULL_RTX;
+ i = prev_nonnote_insn_bb (i))
+ {
+ if (LABEL_P (i) || BARRIER_P (i))
+ break;
+ if (!NONJUMP_INSN_P (i))
+ continue;
+
+ if (reg_set_p (ext_reg, i))
+ {
+ rtx set_op = XEXP (set_of (ext_reg, i), 1);
+ if (set_op == NULL_RTX)
+ break;
+ if (t_reg_operand (set_op, VOIDmode)
+ || negt_reg_operand (set_op, VOIDmode))
+ operands[2] = ext_reg;
+ break;
+ }
+ }
+
+ if (operands[2] == NULL_RTX)
+ FAIL;
+}
[(set_attr "type" "arith")])
(define_insn "*zero_extendhisi2_media"
@@ -8108,47 +8154,126 @@
;; Define the real conditional branch instructions.
;; ------------------------------------------------------------------------
-(define_insn "branch_true"
- [(set (pc) (if_then_else (ne (match_operand 1 "t_reg_operand" "")
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
+(define_expand "branch_true"
+ [(set (pc) (if_then_else (ne (reg:SI T_REG) (const_int 0))
+ (label_ref (match_operand 0))
(pc)))]
- "TARGET_SH1"
-{
- return output_branch (1, insn, operands);
-}
- [(set_attr "type" "cbranch")])
+ "TARGET_SH1")
-(define_insn "*branch_true_eq"
- [(set (pc) (if_then_else (eq (match_operand 1 "t_reg_operand" "")
- (const_int 1))
- (label_ref (match_operand 0 "" ""))
+(define_expand "branch_false"
+ [(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_operand 0))
(pc)))]
- "TARGET_SH1"
-{
- return output_branch (1, insn, operands);
-}
- [(set_attr "type" "cbranch")])
+ "TARGET_SH1")
-(define_insn "branch_false"
- [(set (pc) (if_then_else (eq (match_operand 1 "t_reg_operand" "")
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
+(define_insn_and_split "*cbranch_t"
+ [(set (pc) (if_then_else (match_operand 1 "cbranch_treg_value")
+ (label_ref (match_operand 0))
(pc)))]
"TARGET_SH1"
{
- return output_branch (0, insn, operands);
+ return output_branch (sh_eval_treg_value (operands[1]), insn, operands);
}
- [(set_attr "type" "cbranch")])
-
-(define_insn "*branch_false_ne"
- [(set (pc) (if_then_else (ne (match_operand 1 "t_reg_operand" "")
- (const_int 1))
- (label_ref (match_operand 0 "" ""))
+ "&& can_create_pseudo_p ()"
+ [(set (pc) (if_then_else (eq (reg:SI T_REG) (match_dup 2))
+ (label_ref (match_dup 0))
(pc)))]
- "TARGET_SH1"
{
- return output_branch (0, insn, operands);
+ /* Try to find missed test and branch combine opportunities which result
+ in redundant T bit tests before conditional branches.
+ FIXME: Probably this would not be needed if CCmode was used
+ together with TARGET_FIXED_CONDITION_CODE_REGS. */
+
+ const int treg_value = sh_eval_treg_value (operands[1]);
+ operands[2] = NULL_RTX;
+
+ /* Scan the insns backwards for an insn that sets the T bit by testing a
+ reg against zero like:
+ (set (reg T_REG) (eq (reg) (const_int 0))) */
+ rtx testing_insn = NULL_RTX;
+ rtx tested_reg = NULL_RTX;
+
+ for (rtx i = prev_nonnote_insn_bb (curr_insn); i != NULL_RTX;
+ i = prev_nonnote_insn_bb (i))
+ {
+ if (LABEL_P (i) || BARRIER_P (i))
+ break;
+ if (!NONJUMP_INSN_P (i))
+ continue;
+
+ rtx p = PATTERN (i);
+ if (p != NULL_RTX
+ && GET_CODE (p) == SET && t_reg_operand (XEXP (p, 0), VOIDmode)
+ && GET_CODE (XEXP (p, 1)) == EQ
+ && REG_P (XEXP (XEXP (p, 1), 0))
+ && satisfies_constraint_Z (XEXP (XEXP (p, 1), 1)))
+ {
+ testing_insn = i;
+ tested_reg = XEXP (XEXP (p, 1), 0);
+ break;
+ }
+ }
+
+ if (testing_insn == NULL_RTX)
+ FAIL;
+
+ /* Continue scanning the insns backwards and try to find the insn that
+ sets the tested reg which we found above. If the reg is set by storing
+ the T bit or the negated T bit we can eliminate the test insn before
+ the branch. Notice that the branch condition has to be inverted if the
+ test is eliminated. */
+
+ /* If the T bit is used between the testing insn and the brach insn
+ leave it alone. */
+ if (reg_used_between_p (get_t_reg_rtx (), testing_insn, curr_insn))
+ FAIL;
+
+ for (rtx i = prev_nonnote_insn_bb (testing_insn); i != NULL_RTX;
+ i = prev_nonnote_insn_bb (i))
+ {
+ if (LABEL_P (i) || BARRIER_P (i))
+ break;
+ if (!NONJUMP_INSN_P (i))
+ continue;
+
+ if (reg_set_p (tested_reg, i))
+ {
+ const_rtx tested_reg_set = set_of (tested_reg, i);
+
+ /* It could also be a clobber... */
+ if (tested_reg_set == NULL_RTX || GET_CODE (tested_reg_set) != SET)
+ break;
+
+ rtx set_op1 = XEXP (tested_reg_set, 1);
+ if (t_reg_operand (set_op1, VOIDmode))
+ operands[2] = GEN_INT (treg_value ^ 1);
+ else if (negt_reg_operand (set_op1, VOIDmode))
+ operands[2] = GEN_INT (treg_value);
+ else if (REG_P (set_op1))
+ {
+ /* If it's a reg-reg copy follow the copied reg. This can
+ happen e.g. when T bit store zero-extensions are
+ eliminated. */
+ tested_reg = set_op1;
+ continue;
+ }
+
+ /* It's only safe to remove the testing insn if the T bit is not
+ modified between the testing insn and the insn that stores the
+ T bit. Notice that some T bit stores such as negc also modify
+ the T bit. */
+ if (modified_between_p (get_t_reg_rtx (), i, testing_insn)
+ || modified_in_p (get_t_reg_rtx (), i))
+ operands[2] = NULL_RTX;
+
+ break;
+ }
+ }
+
+ if (operands[2] == NULL_RTX)
+ FAIL;
+
+ set_insn_deleted (testing_insn);
}
[(set_attr "type" "cbranch")])
@@ -10960,26 +11085,54 @@
(set (reg:SI T_REG) (const_int 1))
(use (match_dup 2))])])
-;; In some cases the zero extension does not get combined away and a
-;; sequence like the following might remain:
-;; mov #-1,r2
-;; tst r1,r1
-;; negc r2,r1
-;; extu.b r1,r1
-(define_peephole2
- [(parallel
- [(set (match_operand:SI 0 "arith_reg_dest" "")
- (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
- (set (reg:SI T_REG) (const_int 1))
- (use (match_operand:SI 2 "arith_reg_operand" ""))])
- (set (match_dup 0)
- (zero_extend:SI (match_operand 3 "arith_reg_operand" "")))]
- "TARGET_SH1 && REGNO (operands[0]) == REGNO (operands[3])"
- [(parallel
- [(set (match_dup 0) (xor:SI (match_dup 1) (const_int 1)))
- (set (reg:SI T_REG) (const_int 1))
- (use (match_dup 2))])])
+;; Store the negated T bit in a reg using r0 and xor. This one doesn't
+;; clobber the T bit, which is useful when storing the T bit and the
+;; negated T bit in parallel. On SH2A the movrt insn can be used for that.
+;; Usually we don't want this insn to be matched, except for cases where the
+;; T bit clobber is really not appreciated. Hence the extra use on T_REG.
+(define_insn_and_split "movrt_xor"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=z")
+ (xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
+ (use (reg:SI T_REG))]
+ "TARGET_SH1 && !TARGET_SH2A"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (reg:SI T_REG))
+ (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))])
+;; Store the T bit and the negated T bit in two regs in parallel. There is
+;; no real insn to do that, but specifying this pattern will give combine
+;; some opportunities.
+(define_insn_and_split "*movt_movrt"
+ [(parallel [(set (match_operand:SI 0 "arith_reg_dest")
+ (match_operand:SI 1 "negt_reg_operand"))
+ (set (match_operand:SI 2 "arith_reg_dest")
+ (match_operand:SI 3 "t_reg_operand"))])]
+ "TARGET_SH1"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+{
+ rtx i = TARGET_SH2A
+ ? gen_movrt (operands[0], get_t_reg_rtx ())
+ : gen_movrt_xor (operands[0], get_t_reg_rtx ());
+
+ emit_insn (i);
+ emit_insn (gen_movt (operands[2], get_t_reg_rtx ()));
+ DONE;
+})
+
+(define_insn_and_split "*movt_movrt"
+ [(parallel [(set (match_operand:SI 0 "arith_reg_dest")
+ (match_operand:SI 1 "t_reg_operand"))
+ (set (match_operand:SI 2 "arith_reg_dest")
+ (match_operand:SI 3 "negt_reg_operand"))])]
+ "TARGET_SH1"
+ "#"
+ "&& 1"
+ [(parallel [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 0) (match_dup 1))])])
+
;; Use negc to store the T bit in a MSB of a reg in the following way:
;; T = 1: 0x80000000 -> reg
;; T = 0: 0x7FFFFFFF -> reg
@@ -15165,7 +15318,7 @@
else
{
emit_insn (gen_stack_protect_test_si (operands[0], operands[1]));
- emit_jump_insn (gen_branch_true (operands[2], get_t_reg_rtx ()));
+ emit_jump_insn (gen_branch_true (operands[2]));
}
DONE;
===================================================================
@@ -1048,6 +1048,14 @@
}
})
+;; A predicate that returns true if OP is a valid construct around the T bit
+;; that can be used as an operand for conditional branches.
+(define_predicate "cbranch_treg_value"
+ (match_code "eq,ne,reg,subreg,xor,sign_extend,zero_extend")
+{
+ return sh_eval_treg_value (op) >= 0;
+})
+
;; Returns true of OP is arith_reg_operand or t_reg_operand.
(define_predicate "arith_reg_or_t_reg_operand"
(ior (match_operand 0 "arith_reg_operand")
===================================================================
@@ -162,6 +162,7 @@
extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
enum machine_mode mode = VOIDmode);
extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
+extern int sh_eval_treg_value (rtx op);
#endif /* RTX_CODE */
extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
===================================================================
@@ -0,0 +1,107 @@
+/* This is a case extracted from CSiBE which would sometimes contain the
+ following sequence:
+ cmp/eq r12,r13
+ movt r0
+ xor #1,r0
+ extu.b r0,r0
+ movt r3
+ tst r0,r0
+ bf/s .L35
+ where the negated T bit store did not combine properly. Since there are
+ other movt insns we only check for the xor and the extu. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "xor|extu" } } */
+
+typedef struct transaction_s transaction_t;
+
+struct journal_head
+{
+ transaction_t * b_transaction;
+ struct journal_head *b_cpnext, *b_cpprev;
+};
+
+struct transaction_s
+{
+ struct journal_head * t_checkpoint_list;
+ transaction_t *t_cpnext, *t_cpprev;
+};
+
+struct journal_s
+{
+ transaction_t * j_checkpoint_transactions;
+ unsigned long j_first, j_last;
+};
+
+typedef struct journal_s journal_t;
+
+extern int __try_to_free_cp_buf (struct journal_head *jh);
+extern int __cleanup_transaction (journal_t *journal, transaction_t *transaction);
+extern void __flush_batch (void **bhs, int *batch_count);
+extern void* jh2bh (void*);
+
+static int
+__flush_buffer (journal_t *journal, struct journal_head *jh,
+ void **bhs, int *batch_count, int *drop_count)
+{
+ void *bh = jh2bh (jh);
+ int ret = 0;
+ if (bh)
+ {
+ bhs[*batch_count] = bh;
+ (*batch_count)++;
+ if (*batch_count == 64)
+ ret = 1;
+ }
+ else
+ {
+ int last_buffer = 0;
+ if (jh->b_cpnext == jh)
+ last_buffer = 1;
+ if (__try_to_free_cp_buf (jh))
+ {
+ (*drop_count)++;
+ ret = last_buffer;
+ }
+ }
+ return ret;
+}
+
+int
+log_do_checkpoint (journal_t *journal, int nblocks)
+{
+ transaction_t *transaction, *last_transaction, *next_transaction;
+ int batch_count = 0;
+ void *bhs[64];
+
+repeat:
+ transaction = journal->j_checkpoint_transactions;
+ if (transaction == ((void *)0))
+ return 0;
+ last_transaction = transaction->t_cpprev;
+ next_transaction = transaction;
+ do
+ {
+ struct journal_head *jh, *last_jh, *next_jh;
+ int drop_count = 0;
+ int cleanup_ret, retry = 0;
+ transaction = next_transaction;
+ next_transaction = transaction->t_cpnext;
+ jh = transaction->t_checkpoint_list;
+ last_jh = jh->b_cpprev;
+ next_jh = jh;
+ do
+ {
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+ retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count);
+ } while (jh != last_jh && !retry);
+
+ if (retry)
+ goto repeat;
+
+ cleanup_ret = __cleanup_transaction(journal, transaction);
+ goto repeat;
+ } while (transaction != last_transaction);
+}
===================================================================
@@ -0,0 +1,11 @@
+/* Check that the redundant test removal code in the *cbranch_t split works
+ as expected on SH2A targets. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
+/* { dg-final { scan-assembler-times "tst" 6 } } */
+/* { dg-final { scan-assembler-times "movt" 3 } } */
+/* { dg-final { scan-assembler-times "movrt" 3 } } */
+/* { dg-final { scan-assembler-not "extu|exts|negc" } } */
+
+#include "pr51244-15.c"
===================================================================
@@ -0,0 +1,85 @@
+/* This is a case extracted from CSiBE which contained the following
+ sequence:
+ shll r0
+ movt r0
+ tst r0,r0
+ bf .L11
+ where the 'tst r0,r0' before the branch can be omitted by inverting the
+ branch condition. The tested function contains two other tst insns. If
+ everything goes as expected we will be seeing only those other two tst
+ insns. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-times "tst" 2 } } */
+
+static __inline__ int
+__test_bit (unsigned long nr, volatile void * addr)
+{
+ /* This is on purpose. */
+ int oldbit;
+ return oldbit & 1;
+}
+
+static __inline__ int
+__constant_test_bit (unsigned long nr, volatile void * addr)
+{
+ return (((volatile char *) addr)[(nr>>3)^7] & (1<<(nr&7))) != 0;
+}
+
+struct list_head
+{
+ struct list_head *next, *prev;
+};
+
+static inline void
+__list_del (struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void
+list_del (struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = 0;
+ entry->prev = 0;
+}
+
+extern int nr_active_pages;
+extern int nr_inactive_pages;
+extern struct list_head active_list;
+
+typedef struct page
+{
+ unsigned long flags;
+ struct list_head lru;
+} mem_map_t;
+
+void
+activate_page_nolock (struct page * page)
+{
+ if ((__builtin_constant_p((6))
+ ? __constant_test_bit((6),(&(page)->flags))
+ : __test_bit((6),(&(page)->flags)) )
+ && !(__builtin_constant_p((7))
+ ? __constant_test_bit((7),(&(page)->flags))
+ : __test_bit((7),(&(page)->flags)) ))
+ {
+ list_del(&(page)->lru);
+ nr_inactive_pages--;
+ if (!(__builtin_constant_p(6) ? __constant_test_bit((6),(&(page)->flags))
+ : __test_bit((6),(&(page)->flags))))
+ printk("", "", 43);
+
+ if ((__builtin_constant_p(7) ? __constant_test_bit((7),(&(page)->flags))
+ : __test_bit((7),(&(page)->flags))))
+ printk("", "", 43);
+
+ (__builtin_constant_p(7) ? __constant_set_bit((7),(&(page)->flags))
+ : __set_bit((7),(&(page)->flags)) );
+ list_add(&(page)->lru, &active_list);
+ nr_active_pages++;
+ }
+}
===================================================================
@@ -0,0 +1,71 @@
+/* Check that the redundant test removal code in the *cbranch_t split works
+ as expected on non-SH2A targets. Because on SH2A the movrt instruction
+ is used, this test is re-used and checked differently in pr51244-16.c. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } } */
+/* { dg-final { scan-assembler-times "tst" 6 } } */
+/* { dg-final { scan-assembler-times "movt" 6 } } */
+/* { dg-final { scan-assembler-times "xor" 3 } } */
+/* { dg-final { scan-assembler-not "extu|exts|negc" } } */
+
+typedef char bool;
+
+int
+test_0 (int a, int b, int c, int* d)
+{
+ /* non SH2A: 1x tst, 1x movt, 1x xor
+ SH2A: 1x tst, 1x movrt */
+ bool x = a == 0;
+ d[2] = !x;
+ return x ? b : c;
+}
+
+int
+test_1 (int a, int b, int c, int* d)
+{
+ /* 1x tst, 1x movt */
+ bool x = a != 0;
+ d[2] = !x;
+ return x ? b : c;
+}
+
+int
+test_2 (int a, int b, int c, char* d)
+{
+ /* Check that there is no sign/zero-extension before the store.
+ non SH2A: 1x tst, 1x movt, 1x xor
+ SH2A: 1x tst, 1x movrt */
+ bool x = a == 0;
+ d[2] = !x;
+ return x ? b : c;
+}
+
+int
+test_3 (int a, int b, int c, char* d)
+{
+ /* Check that there is no sign/zero-extension before the store.
+ 1x tst, 1x movt */
+ bool x = a != 0;
+ d[2] = !x;
+ return x ? b : c;
+}
+
+int
+test_4 (int a, int b, int c, char* d)
+{
+ /* 1x tst, 1x movt */
+ bool x = a != 0;
+ d[2] = !x;
+ return !x ? b : c;
+}
+
+int
+test_5 (int a, int b, int c, char* d)
+{
+ /* non SH2A: 1x tst, 1x movt, 1x xor
+ SH2A: 1x tst, 1x movrt */
+ bool x = a == 0;
+ d[2] = !x;
+ return !x ? b : c;
+}