* config/h8300/h8300.c (ok_for_bclr): Take a HOST_WIDE_INT.
(small_power_of_two): Likewise; use exact_log2.
(adds_subs_operand, one_insn_adds_subs_operand): Remove.
(output_adds_subs): Remove.
(two_insn_adds_subs_operand): New.
(split_adds_subs): New.
* config/h8300/h8300-protos.h: Update.
* config/h8300/h8300.h (CONST_OK_FOR_J): Cast to uns HOST_WIDE_INT.
(CONST_OK_FOR_L): Match strict adds operands.
(CONST_OK_FOR_N): Match struct subs operands.
* config/h8300/h8300.md (adds_subs insns): Remove.
(addhi patterns): Output adds/subs directly.
(addsi_h8300h): Likewise.
(addhi/addsi splitters): New. Decompose two_insn_adds_subs_operand.
From-SVN: r33985
+2000-05-18 Richard Henderson <rth@cygnus.com>
+
+ * config/h8300/h8300.c (ok_for_bclr): Take a HOST_WIDE_INT.
+ (small_power_of_two): Likewise; use exact_log2.
+ (adds_subs_operand, one_insn_adds_subs_operand): Remove.
+ (output_adds_subs): Remove.
+ (two_insn_adds_subs_operand): New.
+ (split_adds_subs): New.
+ * config/h8300/h8300-protos.h: Update.
+ * config/h8300/h8300.h (CONST_OK_FOR_J): Cast to uns HOST_WIDE_INT.
+ (CONST_OK_FOR_L): Match strict adds operands.
+ (CONST_OK_FOR_N): Match struct subs operands.
+ * config/h8300/h8300.md (adds_subs insns): Remove.
+ (addhi patterns): Output adds/subs directly.
+ (addsi_h8300h): Likewise.
+ (addhi/addsi splitters): New. Decompose two_insn_adds_subs_operand.
+
2000-05-18 Zack Weinberg <zack@wolery.cumb.org>
* cppexp.c (parse_assertion): New.
extern int expand_a_shift PARAMS ((enum machine_mode, int, rtx[]));
extern int fix_bit_operand PARAMS ((rtx *, int, enum rtx_code));
extern int h8300_adjust_insn_length PARAMS ((rtx, int));
+extern void split_adds_subs PARAMS ((enum machine_mode, rtx[]));
extern int general_operand_src PARAMS ((rtx, enum machine_mode));
extern int general_operand_dst PARAMS ((rtx, enum machine_mode));
extern int o_operand PARAMS ((rtx, enum machine_mode));
extern int p_operand PARAMS ((rtx, enum machine_mode));
extern int call_insn_operand PARAMS ((rtx, enum machine_mode));
-extern int adds_subs_operand PARAMS ((rtx, enum machine_mode));
-extern int one_insn_adds_subs_operand PARAMS ((rtx, enum machine_mode));
+extern int two_insn_adds_subs_operand PARAMS ((rtx, enum machine_mode));
extern int small_call_insn_operand PARAMS ((rtx, enum machine_mode));
extern int jump_address_operand PARAMS ((rtx, enum machine_mode));
extern int bit_operand PARAMS ((rtx, enum machine_mode));
extern void function_epilogue PARAMS ((FILE *, int));
extern void asm_file_start PARAMS ((FILE *));
extern void asm_file_end PARAMS ((FILE *));
-extern int ok_for_bclr PARAMS ((int));
-extern int small_power_of_two PARAMS ((int));
+extern int ok_for_bclr PARAMS ((HOST_WIDE_INT));
+extern int small_power_of_two PARAMS ((HOST_WIDE_INT));
extern int initial_offset PARAMS ((int, int));
int
small_power_of_two (value)
- int value;
+ HOST_WIDE_INT value;
{
- switch (value)
- {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- case 32:
- case 64:
- case 128:
- case 256:
- case 512:
- case 1024:
- case 2048:
- case 4096:
- case 8192:
- case 16384:
- case 32768:
- return 1;
- }
- return 0;
+ int power = exact_log2 (value);
+ return power >= 0 && power <= 15;
}
/* Return true if VALUE is a valid constant for constraint 'O', which
int
ok_for_bclr (value)
- int value;
+ HOST_WIDE_INT value;
{
return small_power_of_two ((~value) & 0xff);
}
}
int
-adds_subs_operand (op, mode)
+two_insn_adds_subs_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == CONST_INT)
{
- if (INTVAL (op) <= 4 && INTVAL (op) >= 0)
- return 1;
- if (INTVAL (op) >= -4 && INTVAL (op) <= 0)
- return 1;
- if ((TARGET_H8300H || TARGET_H8300S)
- && INTVAL (op) != 7
- && (INTVAL (op) <= 8 && INTVAL (op) >= 0))
- return 1;
- if ((TARGET_H8300H || TARGET_H8300S)
- && INTVAL (op) != -7
- && (INTVAL (op) >= -8 && INTVAL (op) <= 0))
- return 1;
- }
- return 0;
-}
+ HOST_WIDE_INT value = INTVAL (op);
-/* Return nonzero if op is an adds/subs operand which only requires
- one insn to implement. It is assumed that OP is already an adds/subs
- operand. */
-int
-one_insn_adds_subs_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
-{
- int val = INTVAL (op);
+ if (TARGET_H8300H || TARGET_H8300S)
+ {
+ if (value >= -8 && value < -4 && value != -7)
+ return 1;
+ if (value > 4 && value <= 8 && value != 7)
+ return 1;
+ }
+ else
+ {
+ if (value == -4 || value == -3 || value == 3 || value == 4)
+ return 1;
+ }
+ }
- if (val == 1 || val == -1
- || val == 2 || val == -2
- || ((TARGET_H8300H || TARGET_H8300S)
- && (val == 4 || val == -4)))
- return 1;
return 0;
}
-const char *
-output_adds_subs (operands)
+/* Split an add of a small constant into two adds/subs insns. */
+
+void
+split_adds_subs (mode, operands)
+ enum machine_mode mode;
rtx *operands;
{
- int val = INTVAL (operands[2]);
+ HOST_WIDE_INT val = INTVAL (operands[1]);
+ rtx reg = operands[0];
+ rtx tmp;
- /* First get the value into the range -4..4 inclusive.
-
- The only way it can be out of this range is when TARGET_H8300H
- or TARGET_H8300S is true, thus it is safe to use adds #4 and subs #4. */
- if (val > 4)
+ /* Take care of +/- 4 for H8300H and H8300S. */
+ if (TARGET_H8300H || TARGET_H8300S)
{
- output_asm_insn ("adds #4,%A0", operands);
- val -= 4;
- }
+ /* Get the value in range of +/- 4. */
+ if (val > 4)
+ {
+ tmp = gen_rtx_PLUS (mode, reg, GEN_INT (4));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, tmp));
+ val -= 4;
+ }
+ else if (val < -4)
+ {
+ tmp = gen_rtx_PLUS (mode, reg, GEN_INT (-4));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, tmp));
+ val += 4;
+ }
- if (val < -4)
- {
- output_asm_insn ("subs #4,%A0", operands);
- val += 4;
+ if (val == 4 || val == -4)
+ {
+ tmp = gen_rtx_PLUS (mode, reg, GEN_INT (val));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, tmp));
+ return;
+ }
}
- /* Handle case were val == 4 or val == -4 and we're compiling
- for TARGET_H8300H or TARGET_H8300S. */
- if ((TARGET_H8300H || TARGET_H8300S)
- && val == 4)
- return "adds #4,%A0";
-
- if ((TARGET_H8300H || TARGET_H8300S)
- && val == -4)
- return "subs #4,%A0";
-
+ /* Get the value in range of +/- 2. */
if (val > 2)
{
- output_asm_insn ("adds #2,%A0", operands);
+ tmp = gen_rtx_PLUS (mode, reg, GEN_INT (2));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, tmp));
val -= 2;
}
-
- if (val < -2)
+ else if (val < -2)
{
- output_asm_insn ("subs #2,%A0", operands);
+ tmp = gen_rtx_PLUS (mode, reg, GEN_INT (-2));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, tmp));
val += 2;
}
- /* val should be one or two now. */
- if (val == 2)
- return "adds #2,%A0";
-
- if (val == -2)
- return "subs #2,%A0";
-
- /* val should be one now. */
- if (val == 1)
- return "adds #1,%A0";
-
- if (val == -1)
- return "subs #1,%A0";
-
/* If not optimizing, we might be asked to add 0. */
if (val == 0)
- return "";
+ return;
+
+ /* We should have one or two now. */
+ if (val >= -2 && val <= 2)
+ {
+ tmp = gen_rtx_PLUS (mode, reg, GEN_INT (val));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, tmp));
+ return;
+ }
/* In theory, this can't happen. */
abort ();
Return 1 if VALUE is in the range specified by C. */
#define CONST_OK_FOR_I(VALUE) ((VALUE) == 0)
-#define CONST_OK_FOR_J(VALUE) ((unsigned) (VALUE) < 256)
-#define CONST_OK_FOR_K(VALUE) (((VALUE) == 1) || (VALUE) == 2)
-#define CONST_OK_FOR_L(VALUE) (((VALUE) == -1) || (VALUE) == -2)
-#define CONST_OK_FOR_M(VALUE) (((VALUE) == 3) || (VALUE) == 4)
-#define CONST_OK_FOR_N(VALUE) (((VALUE) == -3) || (VALUE) == -4)
+#define CONST_OK_FOR_J(VALUE) ((unsigned HOST_WIDE_INT) (VALUE) < 256)
+#define CONST_OK_FOR_K(VALUE) ((VALUE) == 1 || (VALUE) == 2)
+#define CONST_OK_FOR_L(VALUE) \
+ (TARGET_H8300H || TARGET_H8300S \
+ ? (VALUE) == 1 || (VALUE) == 2 || (VALUE) == 4 \
+ : (VALUE) == 1 || (VALUE) == 2)
+#define CONST_OK_FOR_M(VALUE) ((VALUE) == 3 || (VALUE) == 4)
+#define CONST_OK_FOR_N(VALUE) \
+ (TARGET_H8300H || TARGET_H8300S \
+ ? (VALUE) == -1 || (VALUE) == -2 || (VALUE) == -4 \
+ : (VALUE) == -1 || (VALUE) == -2)
#define CONST_OK_FOR_O(VALUE) (ok_for_bclr (VALUE))
#define CONST_OK_FOR_P(VALUE) (small_power_of_two (VALUE))
(C) == 'M' ? CONST_OK_FOR_M (VALUE) : \
(C) == 'N' ? CONST_OK_FOR_N (VALUE) : \
(C) == 'O' ? CONST_OK_FOR_O (VALUE) : \
- (C) == 'P' ? CONST_OK_FOR_P(VALUE) : \
+ (C) == 'P' ? CONST_OK_FOR_P (VALUE) : \
0)
/* Similar, but for floating constants, and defining letters G and H.
""
"")
-;; Specialized version using adds/subs. This must come before
-;; the more general patterns below.
(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r")
- (plus:HI (match_operand:HI 1 "register_operand" "%0")
- (match_operand:HI 2 "adds_subs_operand" "n")))]
- ""
- "* return output_adds_subs (operands);"
- [(set_attr "cc" "none_0hit")
- (set (attr "length")
- (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
- (const_int 0))
- (const_int 2)
- (const_int 4)))])
-
-(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=&r,r,&r")
- (plus:HI (match_operand:HI 1 "register_operand" "%0,0,g")
- (match_operand:HI 2 "nonmemory_operand" "n,r,r")))]
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,&r")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,g")
+ (match_operand:HI 2 "nonmemory_operand" "L,N,n,r,r")))]
"TARGET_H8300"
"@
+ adds %2,%A0
+ subs %2,%A0
add.b %s2,%s0\;addx %t2,%t0
add.w %T2,%T0
mov.w %T1,%T0\;add.w %T2,%T0"
- [(set_attr "length" "4,2,6")
- (set_attr "cc" "clobber,set_zn,set_zn")])
+ [(set_attr "length" "2,2,4,2,6")
+ (set_attr "cc" "none_0hit,none_0hit,clobber,set_zn,set_zn")])
(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r,r")
- (plus:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "nonmemory_operand" "n,r")))]
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0")
+ (match_operand:HI 2 "nonmemory_operand" "L,N,n,r")))]
"TARGET_H8300H || TARGET_H8300S"
"@
+ adds %2,%A0
+ subs %2,%A0
add.w %T2,%T0
add.w %T2,%T0"
- [(set_attr "length" "4,2")
- (set_attr "cc" "set_zn,set_zn")])
+ [(set_attr "length" "2,2,4,2")
+ (set_attr "cc" "none_0hit,none_0hit,set_zn,set_zn")])
+
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (plus:HI (match_dup 0)
+ (match_operand:HI 1 "two_insn_adds_subs_operand" "")))]
+ ""
+ [(const_int 0)]
+ "split_adds_subs (HImode, operands); DONE;")
(define_expand "addsi3"
[(set (match_operand:SI 0 "register_operand" "")
""
"")
-;; Specialized version using adds/subs. This must come before
-;; the more general patterns below.
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r")
- (plus:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "adds_subs_operand" "n")))]
- "TARGET_H8300H || TARGET_H8300S"
- "* return output_adds_subs (operands);"
- [(set_attr "cc" "none_0hit")
- (set (attr "length")
- (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
- (const_int 0))
- (const_int 2)
- (const_int 4)))])
-
(define_insn "addsi_h8300"
[(set (match_operand:SI 0 "register_operand" "=r,r,&r")
(plus:SI (match_operand:SI 1 "register_operand" "%0,0,r")
(set_attr "cc" "clobber")])
(define_insn "addsi_h8300h"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "i,r")))]
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0")
+ (match_operand:SI 2 "nonmemory_operand" "L,N,i,r")))]
"TARGET_H8300H || TARGET_H8300S"
"@
+ adds %2,%A0
+ subs %2,%A0
add.l %S2,%S0
add.l %S2,%S0"
- [(set_attr "length" "6,2")
- (set_attr "cc" "set_zn,set_zn")])
+ [(set_attr "length" "2,2,6,2")
+ (set_attr "cc" "none_0hit,none_0hit,set_zn,set_zn")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_dup 0)
+ (match_operand:SI 1 "two_insn_adds_subs_operand" "")))]
+ "TARGET_H8300H || TARGET_H8300S"
+ [(const_int 0)]
+ "split_adds_subs (SImode, operands); DONE;")
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
""
"")
-;; Specialized version using adds/subs. This must come before
-;; the more general patterns below. This may not be needed
-;; due to instruction canonicalization.
-(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r")
- (minus:HI (match_operand:HI 1 "register_operand" "r")
- (match_operand:HI 2 "adds_subs_operand" "n")))]
- ""
- "*
-{
- operands[2] = GEN_INT (-INTVAL (operands[2]));
- return output_adds_subs (operands);
-}"
- [(set_attr "cc" "none_0hit")
- (set (attr "length")
- (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
- (const_int 0))
- (const_int 2)
- (const_int 4)))])
-
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r,&r")
(minus:HI (match_operand:HI 1 "general_operand" "0,0")
[(set_attr "length" "6")
(set_attr "cc" "clobber")])
-;; Specialized version using adds/subs. This must come before
-;; the more general patterns below. This may not be needed
-;; due to instruction canonicalization.
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "adds_subs_operand" "n")))]
- "TARGET_H8300H || TARGET_H8300S"
- "*
-{
- operands[2] = GEN_INT (-INTVAL (operands[2]));
- return output_adds_subs (operands);
-}"
- [(set_attr "cc" "none_0hit")
- (set (attr "length")
- (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
- (const_int 0))
- (const_int 2)
- (const_int 4)))])
-
(define_insn "subsi3_h8300h"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(minus:SI (match_operand:SI 1 "general_operand" "0,0")