/* Register Indirect. */
return true;
- if (GET_MODE_SIZE (mode) == 4
+ if ((GET_MODE_SIZE (mode) == 4
+ || GET_MODE_SIZE (mode) == 2
+ || GET_MODE_SIZE (mode) == 1)
&& (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC))
/* Pre-decrement Register Indirect or
Post-increment Register Indirect. */
base = XEXP (mem, 0);
index = XEXP (mem, 1);
- return RX_REG_P (base) && CONST_INT_P (index);
+ if (! RX_REG_P (base) || ! CONST_INT_P (index))
+ return false;
+
+ return IN_RANGE (INTVAL (index), 0, (0x10000 * GET_MODE_SIZE (mode)) - 1);
case SYMBOL_REF:
/* Can happen when small data is being supported.
%L Print low part of a DImode register, integer or address.
%N Print the negation of the immediate value.
%Q If the operand is a MEM, then correctly generate
- register indirect or register relative addressing. */
+ register indirect or register relative addressing.
+ %R Like %Q but for zero-extending loads. */
void
rx_print_operand (FILE * file, rtx op, int letter)
{
+ bool unsigned_load = false;
+
switch (letter)
{
case 'A':
rx_print_integer (file, - INTVAL (op));
break;
+ case 'R':
+ gcc_assert (GET_MODE_SIZE (GET_MODE (op)) < 4);
+ unsigned_load = true;
+ /* Fall through. */
case 'Q':
if (MEM_P (op))
{
HOST_WIDE_INT offset;
+ rtx mem = op;
op = XEXP (op, 0);
rx_print_operand (file, op, 0);
fprintf (file, "].");
- switch (GET_MODE_SIZE (GET_MODE (op)))
+ switch (GET_MODE_SIZE (GET_MODE (mem)))
{
case 1:
- gcc_assert (offset < 65535 * 1);
- fprintf (file, "B");
+ gcc_assert (offset <= 65535 * 1);
+ fprintf (file, unsigned_load ? "UB" : "B");
break;
case 2:
gcc_assert (offset % 2 == 0);
- gcc_assert (offset < 65535 * 2);
- fprintf (file, "W");
+ gcc_assert (offset <= 65535 * 2);
+ fprintf (file, unsigned_load ? "UW" : "W");
break;
- default:
+ case 4:
gcc_assert (offset % 4 == 0);
- gcc_assert (offset < 65535 * 4);
+ gcc_assert (offset <= 65535 * 4);
fprintf (file, "L");
break;
+ default:
+ gcc_unreachable ();
}
break;
}
return true;
}
\f
+int
+rx_align_for_label (rtx lab ATTRIBUTE_UNUSED)
+{
+ return optimize_size ? 1 : 3;
+}
+
+int
+rx_max_skip_for_label (rtx lab)
+{
+ int opsize;
+ rtx op;
+
+ if (lab == NULL_RTX)
+ return 0;
+ op = lab;
+ do
+ {
+ op = next_nonnote_insn (op);
+ }
+ while (op && (LABEL_P (op)
+ || (INSN_P (op) && GET_CODE (PATTERN (op)) == USE)));
+ if (!op)
+ return 0;
+
+ opsize = get_attr_length (op);
+ if (opsize >= 0 && opsize < 8)
+ return opsize - 1;
+ return 0;
+}
+\f
#undef TARGET_FUNCTION_VALUE
#define TARGET_FUNCTION_VALUE rx_function_value
(set (reg CC_REG)
(compare (abs:SI (match_dup 1))
(const_int 0)))]
- "reload_completed && rx_match_ccmode (insn, CC_ZSOmode)"
+ ;; Note - although the ABS instruction does set the O bit in the processor
+ ;; status word, it does not do so in a way that is comparable with the CMP
+ ;; instruction. Hence we use CC_ZSmode rather than CC_ZSOmode.
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
"@
abs\t%0
abs\t%1, %0"
and\t%1, %0
and\t%2, %1, %0
and\t%Q2, %0"
- [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+ [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
(set_attr "length" "2,2,3,4,5,6,2,5,5")]
)
and\t%1, %0
and\t%2, %1, %0
and\t%Q2, %0"
- [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+ [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
(set_attr "length" "2,2,3,4,5,6,2,5,5")]
)
(set_attr "length" "3,4,5,6,7,6")]
)
\f
+;; A set of peepholes to catch extending loads followed by arithmetic operations.
+;; We use iterators where possible to reduce the amount of typing and hence the
+;; possibilities for typos.
+
+(define_code_iterator extend_types [(zero_extend "") (sign_extend "")])
+(define_code_attr letter [(zero_extend "R") (sign_extend "Q")])
+
+(define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")])
+(define_code_iterator memex_noncomm [(div "") (udiv "") (minus "")])
+(define_code_iterator memex_nocc [(smax "") (smin "") (mult "")])
+
+(define_code_attr op [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (parallel [(set (match_operand:SI 2 "register_operand")
+ (memex_commutative:SI (match_dup 0)
+ (match_dup 2)))
+ (clobber (reg:CC CC_REG))])]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(parallel [(set:SI (match_dup 2)
+ (memex_commutative:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (parallel [(set (match_operand:SI 2 "register_operand")
+ (memex_commutative:SI (match_dup 2)
+ (match_dup 0)))
+ (clobber (reg:CC CC_REG))])]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(parallel [(set:SI (match_dup 2)
+ (memex_commutative:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (parallel [(set (match_operand:SI 2 "register_operand")
+ (memex_noncomm:SI (match_dup 2)
+ (match_dup 0)))
+ (clobber (reg:CC CC_REG))])]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(parallel [(set:SI (match_dup 2)
+ (memex_noncomm:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (set (match_operand:SI 2 "register_operand")
+ (memex_nocc:SI (match_dup 0)
+ (match_dup 2)))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(set:SI (match_dup 2)
+ (memex_nocc:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (set (match_operand:SI 2 "register_operand")
+ (memex_nocc:SI (match_dup 2)
+ (match_dup 0)))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(set:SI (match_dup 2)
+ (memex_nocc:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "*<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (memex_commutative:SI (match_operand:SI 1 "register_operand" "%0")
+ (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "<memex_commutative:op>\t%<extend_types:letter>2, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns
+) ;; rather than using iterators we could specify exact sizes.
+
+(define_insn "*<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (memex_noncomm:SI (match_operand:SI 1 "register_operand" "0")
+ (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "<memex_noncomm:op>\t%<extend_types:letter>2, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns
+) ;; rather than using iterators we could specify exact sizes.
+
+(define_insn "*<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (memex_nocc:SI (match_operand:SI 1 "register_operand" "%0")
+ (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))]
+ ""
+ "<memex_nocc:op>\t%<extend_types:letter>2, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns
+) ;; rather than using iterators we could specify exact sizes.
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand")
+ (match_dup 0)))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_dup 2)
+ (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "*comparesi3_<extend_types:code><small_int_modes:mode>"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 0 "register_operand" "=r")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))]
+ ""
+ "cmp\t%<extend_types:letter>1, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns
+) ;; rather than using iterators we could specify exact sizes.
+\f
;; Floating Point Instructions
(define_insn "addsf3"
""
"bset\t%1, %0.B"
[(set_attr "length" "3")
- (set_attr "timings" "34")]
+ (set_attr "timings" "33")]
)
(define_insn "*bitinvert"
""
"bclr\t%1, %0.B"
[(set_attr "length" "3")
- (set_attr "timings" "34")]
+ (set_attr "timings" "33")]
)
(define_insn "*insv_imm"