gen_rtx (CONST_INT, VOIDmode, \
high_int << 16)), 0),\
gen_rtx (CONST_INT, VOIDmode, low_int)); \
+ goto WIN; \
} \
else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
&& GET_CODE (XEXP (X, 1)) != CONST_INT) \
- (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \
- force_operand (XEXP (X, 1), 0)); \
+ { \
+ (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \
+ force_reg (SImode, force_operand (XEXP (X, 1), 0))); \
+ goto WIN; \
+ } \
}
/* Go to LABEL if ADDR (a legitimate address expression)
#define PREDICATE_CODES \
{"short_cint_operand", {CONST_INT}}, \
{"u_short_cint_operand", {CONST_INT}}, \
+ {"non_short_cint_operand", {CONST_INT}}, \
{"gen_reg_operand", {SUBREG, REG}}, \
{"cc_reg_operand", {SUBREG, REG}}, \
{"reg_or_short_operand", {SUBREG, REG, CONST_INT}}, \
{"fp_reg_or_mem_operand", {SUBREG, MEM, REG}}, \
{"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}}, \
{"add_operand", {SUBREG, REG, CONST_INT}}, \
+ {"non_add_cint_operand", {CONST_INT}}, \
{"and_operand", {SUBREG, REG, CONST_INT}}, \
+ {"non_and_cint_operand", {CONST_INT}}, \
{"logical_operand", {SUBREG, REG, CONST_INT}}, \
+ {"non_logical_cint_operand", {CONST_INT}}, \
{"mask_operand", {CONST_INT}}, \
{"call_operand", {SYMBOL_REF, REG}}, \
{"input_operand", {SUBREG, MEM, REG, CONST_INT}}, \
[(set_attr "type" "compare")])
\f
;; Fixed-point arithmetic insns.
-(define_insn ""
+(define_insn "addsi3"
[(set (match_operand:SI 0 "gen_reg_operand" "=r,r")
(plus:SI (match_operand:SI 1 "gen_reg_operand" "%r,b")
(match_operand:SI 2 "add_operand" "rI,J")))]
"a%I2. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_expand "addsi3"
+;; Split an add that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine. Note that the low-order
+;; add should be last in case the result gets used in an address.
+
+(define_split
[(set (match_operand:SI 0 "gen_reg_operand" "")
(plus:SI (match_operand:SI 1 "gen_reg_operand" "")
- (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ (match_operand:SI 2 "non_add_cint_operand" "")))]
""
- "
+ [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
+"
{
- if (GET_CODE (operands[2]) == CONST_INT
- && (unsigned) (INTVAL (operands[2]) + 0x8000) >= 0x10000
- && (INTVAL (operands[2]) & 0xffff) != 0)
- {
- int low = INTVAL (operands[2]) & 0xffff;
- int high = (unsigned) INTVAL (operands[2]) >> 16;
+ int low = INTVAL (operands[2]) & 0xffff;
+ int high = (unsigned) INTVAL (operands[2]) >> 16;
- if (low & 0x8000)
- high++, low |= 0xffff0000;
+ if (low & 0x8000)
+ high++, low |= 0xffff0000;
- emit_insn (gen_addsi3 (operands[0], operands[1],
- gen_rtx (CONST_INT, VOIDmode, high << 16)));
- operands[1] = operands[0];
- operands[2] = gen_rtx (CONST_INT, VOIDmode, low);
- }
+ operands[3] = gen_rtx (CONST_INT, VOIDmode, high << 16);
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, low);
}")
(define_insn "one_cmplsi2"
rlinm. %0,%1,0,%m2,%M2"
[(set_attr "type" "compare,compare,compare,delayed_compare")])
-(define_insn ""
+;; Take a AND with a constant that cannot be done in a single insn and try to
+;; split it into two insns. This does not verify that the insns are valid
+;; since this need not be done as combine will do it.
+
+(define_split
+ [(set (match_operand:SI 0 "gen_reg_operand" "")
+ (and:SI (match_operand:SI 1 "gen_reg_operand" "")
+ (match_operand:SI 2 "non_and_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (and:SI (match_dup 0) (match_dup 4)))]
+ "
+{
+ int maskval = INTVAL (operands[2]);
+ int i, transitions, last_bit_value;
+ int orig = maskval, first_c = maskval, second_c;
+
+ /* We know that MASKVAL must have more than 2 bit-transitions. Start at
+ the low-order bit and count for the third transition. When we get there,
+ make a first mask that has everything to the left of that position
+ a one. Then make the second mask to turn off whatever else is needed. */
+
+ for (i = 1, transitions = 0, last_bit_value = maskval & 1; i < 32; i++)
+ {
+ if (((maskval >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+ if (transitions > 2)
+ {
+ first_c |= (~0) << i;
+ break;
+ }
+ }
+
+ second_c = orig | ~ first_c;
+
+ operands[3] = gen_rtx (CONST_INT, VOIDmode, first_c);
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, second_c);
+}")
+
+(define_insn "iorsi3"
[(set (match_operand:SI 0 "gen_reg_operand" "=r,r,r")
(ior:SI (match_operand:SI 1 "gen_reg_operand" "%r,r,r")
(match_operand:SI 2 "logical_operand" "r,K,J")))]
"or. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_expand "iorsi3"
+;; Split an IOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
[(set (match_operand:SI 0 "gen_reg_operand" "")
(ior:SI (match_operand:SI 1 "gen_reg_operand" "")
- (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ (match_operand:SI 2 "non_logical_cint_operand" "")))]
""
- "
+ [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 4)))]
+"
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! logical_operand (operands[2], SImode))
- {
- emit_insn (gen_iorsi3 (operands[0], operands[1],
- gen_rtx (CONST_INT, VOIDmode,
- INTVAL (operands[2]) & 0xffff0000)));
- operands[1] = operands[0];
- operands[2] = gen_rtx (CONST_INT, VOIDmode,
- INTVAL (operands[2]) & 0xffff);
- }
+ operands[3] = gen_rtx (CONST_INT, VOIDmode,
+ INTVAL (operands[2]) & 0xffff0000);
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0xffff);
}")
-(define_insn ""
+(define_insn "xorsi3"
[(set (match_operand:SI 0 "gen_reg_operand" "=r,r,r")
(xor:SI (match_operand:SI 1 "gen_reg_operand" "%r,r,r")
(match_operand:SI 2 "logical_operand" "r,K,J")))]
"xor. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_expand "xorsi3"
+;; Split an XOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
[(set (match_operand:SI 0 "gen_reg_operand" "")
(xor:SI (match_operand:SI 1 "gen_reg_operand" "")
- (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ (match_operand:SI 2 "non_logical_cint_operand" "")))]
""
- "
+ [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 4)))]
+"
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! logical_operand (operands[2], SImode))
- {
- emit_insn (gen_xorsi3 (operands[0], operands[1],
- gen_rtx (CONST_INT, VOIDmode,
- INTVAL (operands[2]) & 0xffff0000)));
- operands[1] = operands[0];
- operands[2] = gen_rtx (CONST_INT, VOIDmode,
- INTVAL (operands[2]) & 0xffff);
- }
+ operands[3] = gen_rtx (CONST_INT, VOIDmode,
+ INTVAL (operands[2]) & 0xffff0000);
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0xffff);
}")
(define_insn ""
"cmp%I2 %0,%1,%2"
[(set_attr "type" "compare")])
+;; If we are comparing a register for equality with a large constant,
+;; we can do this with an XOR followed by a compare. But we need a scratch
+;; register for the result of the XOR.
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_operand" "")
+ (compare:CC (match_operand:SI 1 "gen_reg_operand" "")
+ (match_operand:SI 2 "non_short_cint_operand" "")))
+ (clobber (match_operand:SI 3 "gen_reg_operand" ""))]
+ "find_single_use (operands[0], insn, 0)
+ && (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ
+ || GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)"
+ [(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4)))
+ (set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))]
+ "
+{
+ /* Get the constant we are comparing against, C, and see what it looks like
+ sign-extended to 16 bits. Then see what constant could be XOR'ed
+ with C to get the sign-extended value. */
+
+ int c = INTVAL (operands[2]);
+ int sextc = (c << 16) >> 16;
+ int xorv = c ^ sextc;
+
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, xorv);
+ operands[5] = gen_rtx (CONST_INT, VOIDmode, sextc);
+}")
+
(define_insn ""
[(set (match_operand:CCUNS 0 "cc_reg_operand" "=y")
(compare:CCUNS (match_operand:SI 1 "gen_reg_operand" "r")