summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorolegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-15 22:08:07 +0000
committerolegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-15 22:08:07 +0000
commit99af687ad58b1f317067ddab2d693f7bc38846cc (patch)
tree4345633a0ae1c37863cf324ef3c7e80f33d28125
parent8b6f9b966e685e50bd27c8669cbb22033ca61371 (diff)
downloadgcc-99af687ad58b1f317067ddab2d693f7bc38846cc.tar.gz
PR target/51244
* config/sh/sh-protos.h (set_of_reg): New struct. (sh_find_set_of_reg, sh_is_logical_t_store_expr, sh_try_omit_signzero_extend): Declare... * config/sh/sh.c (sh_find_set_of_reg, sh_is_logical_t_store_expr, sh_try_omit_signzero_extend): ...these new functions. * config/sh/sh.md (*logical_op_t): New insn_and_split. (*zero_extend<mode>si2_compact): Use sh_try_omit_signzero_extend in splitter. (*extend<mode>si2_compact_reg): Convert to insn_and_split. Use sh_try_omit_signzero_extend in splitter. (*mov<mode>_reg_reg): Disallow t_reg_operand as operand 1. (*cbranch_t): Rewrite combine part in splitter using new sh_find_set_of_reg function. PR target/51244 * gcc.target/sh/pr51244-17.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192481 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/config/sh/sh-protos.h19
-rw-r--r--gcc/config/sh/sh.c110
-rw-r--r--gcc/config/sh/sh.md168
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/sh/pr51244-17.c297
6 files changed, 526 insertions, 90 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 78ea62237ce..3a2af81f424 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
+ PR target/51244
+ * config/sh/sh-protos.h (set_of_reg): New struct.
+ (sh_find_set_of_reg, sh_is_logical_t_store_expr,
+ sh_try_omit_signzero_extend): Declare...
+ * config/sh/sh.c (sh_find_set_of_reg, sh_is_logical_t_store_expr,
+ sh_try_omit_signzero_extend): ...these new functions.
+ * config/sh/sh.md (*logical_op_t): New insn_and_split.
+ (*zero_extend<mode>si2_compact): Use sh_try_omit_signzero_extend
+ in splitter.
+ (*extend<mode>si2_compact_reg): Convert to insn_and_split.
+ Use sh_try_omit_signzero_extend in splitter.
+ (*mov<mode>_reg_reg): Disallow t_reg_operand as operand 1.
+ (*cbranch_t): Rewrite combine part in splitter using new
+ sh_find_set_of_reg function.
+
+2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
+
PR target/54760
* config/sh/sh.c (sh_find_base_reg_disp): Stop searching insns when
hitting a call insn if GBR is marked as call used.
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index f3c037cb611..d4e97db8902 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -163,6 +163,25 @@ 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);
+
+/* Result value of sh_find_set_of_reg. */
+struct set_of_reg
+{
+ /* The insn where sh_find_set_of_reg stopped looking.
+ Can be NULL_RTX if the end of the insn list was reached. */
+ rtx insn;
+
+ /* The set rtx of the specified reg if found, NULL_RTX otherwise. */
+ const_rtx set_rtx;
+
+ /* The set source rtx of the specified reg if found, NULL_RTX otherwise.
+ Usually, this is the most interesting return value. */
+ rtx set_src;
+};
+
+extern set_of_reg sh_find_set_of_reg (rtx reg, rtx insn, rtx(*stepfunc)(rtx));
+extern bool sh_is_logical_t_store_expr (rtx op, rtx insn);
+extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx insn);
#endif /* RTX_CODE */
extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 763ee9d8ad1..df5b4e519b3 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -13466,4 +13466,114 @@ sh_find_equiv_gbr_addr (rtx insn, rtx mem)
return NULL_RTX;
}
+/*------------------------------------------------------------------------------
+ Manual insn combine support code.
+*/
+
+/* Given a reg rtx and a start insn, try to find the insn that sets the
+ specified reg by using the specified insn stepping function, such as
+ 'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx
+ of the reg set. */
+set_of_reg
+sh_find_set_of_reg (rtx reg, rtx insn, rtx(*stepfunc)(rtx))
+{
+ set_of_reg result;
+ result.insn = insn;
+ result.set_rtx = NULL_RTX;
+ result.set_src = NULL_RTX;
+
+ if (!REG_P (reg) || insn == NULL_RTX)
+ return result;
+
+ for (result.insn = stepfunc (insn); result.insn != NULL_RTX;
+ result.insn = stepfunc (result.insn))
+ {
+ if (LABEL_P (result.insn) || BARRIER_P (result.insn))
+ return result;
+ if (!NONJUMP_INSN_P (result.insn))
+ continue;
+ if (reg_set_p (reg, result.insn))
+ {
+ result.set_rtx = set_of (reg, result.insn);
+
+ if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
+ return result;
+
+ result.set_src = XEXP (result.set_rtx, 1);
+ return result;
+ }
+ }
+
+ return result;
+}
+
+/* Given an op rtx and an insn, try to find out whether the result of the
+ specified op consists only of logical operations on T bit stores. */
+bool
+sh_is_logical_t_store_expr (rtx op, rtx insn)
+{
+ if (!logical_operator (op, SImode))
+ return false;
+
+ rtx ops[2] = { XEXP (op, 0), XEXP (op, 1) };
+ int op_is_t_count = 0;
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (t_reg_operand (ops[i], VOIDmode)
+ || negt_reg_operand (ops[i], VOIDmode))
+ op_is_t_count++;
+
+ else
+ {
+ set_of_reg op_set = sh_find_set_of_reg (ops[i], insn,
+ prev_nonnote_insn_bb);
+ if (op_set.set_src == NULL_RTX)
+ continue;
+
+ if (t_reg_operand (op_set.set_src, VOIDmode)
+ || negt_reg_operand (op_set.set_src, VOIDmode)
+ || sh_is_logical_t_store_expr (op_set.set_src, op_set.insn))
+ op_is_t_count++;
+ }
+ }
+
+ return op_is_t_count == 2;
+}
+
+/* Given the operand that is extended in a sign/zero extend insn, and the
+ insn, try to figure out whether the sign/zero extension can be replaced
+ by a simple reg-reg copy. If so, the replacement reg rtx is returned,
+ NULL_RTX otherwise. */
+rtx
+sh_try_omit_signzero_extend (rtx extended_op, rtx insn)
+{
+ if (REG_P (extended_op))
+ extended_op = extended_op;
+ else if (GET_CODE (extended_op) == SUBREG && REG_P (SUBREG_REG (extended_op)))
+ extended_op = SUBREG_REG (extended_op);
+ else
+ return NULL_RTX;
+
+ /* Reg moves must be of the same mode. */
+ if (GET_MODE (extended_op) != SImode)
+ return NULL_RTX;
+
+ set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_insn_bb);
+ if (s.set_src == NULL_RTX)
+ return NULL_RTX;
+
+ if (t_reg_operand (s.set_src, VOIDmode)
+ || negt_reg_operand (s.set_src, VOIDmode))
+ return extended_op;
+
+ /* If the zero extended reg was formed by a logical operation, check the
+ operands of the logical operation. If both originated from T bit
+ stores the zero extension can be eliminated. */
+ else if (sh_is_logical_t_store_expr (s.set_src, s.insn))
+ return extended_op;
+
+ return NULL_RTX;
+}
+
#include "gt-sh.h"
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 95afd9b3996..6e6394504f6 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -3708,6 +3708,26 @@ label:
"xor %2,%0"
[(set_attr "type" "arith")])
+;; The *logical_op_t pattern helps combine eliminating sign/zero extensions
+;; of results where one of the inputs is a T bit store. Notice that this
+;; pattern must not match during reload. If reload picks this pattern it
+;; will be impossible to split it afterwards.
+(define_insn_and_split "*logical_op_t"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (match_operator:SI 3 "logical_operator"
+ [(match_operand:SI 1 "arith_reg_operand")
+ (match_operand:SI 2 "t_reg_operand")]))]
+ "TARGET_SH1 && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (match_dup 4) (reg:SI T_REG))
+ (set (match_dup 0) (match_dup 3))]
+{
+ operands[4] = gen_reg_rtx (SImode);
+ operands[3] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode,
+ operands[1], operands[4]);
+})
+
(define_insn "*xorsi3_media"
[(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
(xor:SI (match_operand:SI 1 "logical_reg_operand" "%r,r")
@@ -5590,39 +5610,7 @@ label:
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;
- }
- }
-
+ operands[2] = sh_try_omit_signzero_extend (operands[1], curr_insn);
if (operands[2] == NULL_RTX)
FAIL;
}
@@ -5850,11 +5838,23 @@ label:
subreg_lowpart_offset (SImode, GET_MODE (op1)));
})
-(define_insn "*extend<mode>si2_compact_reg"
+(define_insn_and_split "*extend<mode>si2_compact_reg"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(sign_extend:SI (match_operand:QIHI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"exts.<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 sign 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 sign extension with a reg move, which will be
+ eliminated. */
+ operands[2] = sh_try_omit_signzero_extend (operands[1], curr_insn);
+ if (operands[2] == NULL_RTX)
+ FAIL;
+}
[(set_attr "type" "arith")])
;; FIXME: Fold non-SH2A and SH2A alternatives with "enabled" attribute.
@@ -6629,10 +6629,19 @@ label:
;; picked to load/store regs. If the regs regs are on the stack reload will
;; try other insns and not stick to movqi_reg_reg.
;; The same applies to the movhi variants.
+;;
+;; Notice, that T bit is not allowed as a mov src operand here. This is to
+;; avoid things like (set (reg:QI) (subreg:QI (reg:SI T_REG) 0)), which
+;; introduces zero extensions after T bit stores and redundant reg copies.
+;;
+;; FIXME: We can't use 'arith_reg_operand' (which disallows T_REG) as a
+;; predicate for the mov src operand because reload will have trouble
+;; reloading MAC subregs otherwise. For that probably special patterns
+;; would be required.
(define_insn "*mov<mode>_reg_reg"
[(set (match_operand:QIHI 0 "arith_reg_dest" "=r")
(match_operand:QIHI 1 "register_operand" "r"))]
- "TARGET_SH1"
+ "TARGET_SH1 && !t_reg_operand (operands[1], VOIDmode)"
"mov %1,%0"
[(set_attr "type" "move")])
@@ -8178,28 +8187,17 @@ label:
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))
+ set_of_reg s0 = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
+ prev_nonnote_insn_bb);
+ if (s0.set_src != NULL_RTX
+ && GET_CODE (s0.set_src) == EQ
+ && REG_P (XEXP (s0.set_src, 0))
+ && satisfies_constraint_Z (XEXP (s0.set_src, 1)))
{
- 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;
- }
+ testing_insn = s0.insn;
+ tested_reg = XEXP (s0.set_src, 0);
}
-
- if (testing_insn == NULL_RTX)
+ else
FAIL;
/* Continue scanning the insns backwards and try to find the insn that
@@ -8213,47 +8211,37 @@ label:
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))
+ while (true)
{
- if (LABEL_P (i) || BARRIER_P (i))
+ set_of_reg s1 = sh_find_set_of_reg (tested_reg, s0.insn,
+ prev_nonnote_insn_bb);
+ if (s1.set_src == NULL_RTX)
break;
- if (!NONJUMP_INSN_P (i))
- continue;
- if (reg_set_p (tested_reg, i))
+ if (t_reg_operand (s1.set_src, VOIDmode))
+ operands[2] = GEN_INT (treg_value ^ 1);
+ else if (negt_reg_operand (s1.set_src, VOIDmode))
+ operands[2] = GEN_INT (treg_value);
+ else if (REG_P (s1.set_src))
{
- 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;
- }
+ /* 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 = s1.set_src;
+ s0.insn = s1.insn;
+ 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;
+ /* 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 (), s1.insn, testing_insn)
+ || modified_in_p (get_t_reg_rtx (), s1.insn))
+ operands[2] = NULL_RTX;
- break;
- }
- }
+ break;
+ }
if (operands[2] == NULL_RTX)
FAIL;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a155a531cd7..31292eab9be 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
+ PR target/51244
+ * gcc.target/sh/pr51244-17.c: New.
+
+2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
+
PR target/54760
* gcc.target/sh/pr54760-2.c: Add long long and unsigned long long test
functions.
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-17.c b/gcc/testsuite/gcc.target/sh/pr51244-17.c
new file mode 100644
index 00000000000..e7d1ddd2ad0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr51244-17.c
@@ -0,0 +1,297 @@
+/* Check that no unnecessary zero extensions are done on values that are
+ results of arithmetic with T bit inputs. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "extu|exts" } } */
+
+int
+test00 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x == y;
+}
+
+int
+test01 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == d;
+ return x == y;
+}
+
+int
+test02 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c == d;
+ return x == y;
+}
+
+int
+test03 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != d;
+ return x == y;
+}
+
+int
+test04 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != d;
+ return x == y;
+}
+
+int
+test05 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x != y;
+}
+
+int
+test06 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x ^ y;
+}
+
+int
+test07 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x | y;
+}
+
+int
+test08 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x & y;
+}
+
+int
+test09 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == d;
+ return x != y;
+}
+
+int
+test10 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c == d;
+ return x != y;
+}
+
+int
+test11 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != d;
+ return x != y;
+}
+
+int
+test12 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != d;
+ return x != y;
+}
+
+int
+test13 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a == b;
+ int y = c == 0;
+ int z = d == e;
+ return x == y || x == z;
+}
+
+int
+test14 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a == b;
+ int y = c == 0;
+ int z = d == e;
+ return x == y && x == z;
+}
+
+int
+test15 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a != b;
+ int y = c == 0;
+ int z = d == e;
+ return x == y || x == z;
+}
+
+int
+test16 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a != b;
+ int y = c == 0;
+ int z = d == e;
+ return x == y && x == z;
+}
+
+int
+test17 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a != b;
+ int y = c != 0;
+ int z = d == e;
+ return x == y || x == z;
+}
+
+int
+test18 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a != b;
+ int y = c != 0;
+ int z = d == e;
+ return x == y && x == z;
+}
+
+int
+test19 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a != b;
+ int y = c != 0;
+ int z = d == e;
+ return x == y || x == z;
+}
+
+int
+test20 (int a, int b, int c, int d, int e, int f)
+{
+ int x = a != b;
+ int y = c != 0;
+ int z = d != e;
+ return x == y && x == z;
+}
+
+int
+test21 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x + y;
+}
+
+int
+test22 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c == 0;
+ return x + y;
+}
+
+int
+test23 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != 0;
+ return x + y;
+}
+
+int
+test24 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x - y;
+}
+
+int
+test25 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c == 0;
+ return x - y;
+}
+
+int
+test26 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != 0;
+ return x - y;
+}
+
+int
+test27 (int a, int b, int c, int d)
+{
+ int x = a == b;
+ int y = c == 0;
+ return x * y;
+}
+
+int
+test28 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c == 0;
+ return x * y;
+}
+
+int
+test29 (int a, int b, int c, int d)
+{
+ int x = a != b;
+ int y = c != 0;
+ return x * y;
+}
+
+int
+test30 (int a, int b)
+{
+ return ((a & 0x7F) == 1)
+ | ((a & 0xFF00) == 0x0200)
+ | ((a & 0xFF0000) == 0x030000);
+}
+
+int
+test31 (int a, int b)
+{
+ return ((a & 0x7F) == 1)
+ | ((a & 0xFF00) == 0x0200)
+ | ((a & 0xFF0000) == 0x030000)
+ | ((a & 0xFF000000) == 0x04000000);
+}
+
+int
+test32 (int* a, int b, int c, volatile char* d)
+{
+ d[1] = a[0] != 0;
+ return b;
+}
+
+int
+test33 (int* a, int b, int c, volatile char* d)
+{
+ d[1] = a[0] == 0;
+ return b;
+}
+
+char
+test34 (int a, int* b)
+{
+ return (b[4] & b[0] & a) == a;
+}
+
+unsigned char
+test35 (int a, int* b)
+{
+ return (b[4] & b[0] & a) == a;
+}