+2002-05-10 Marek Michalkiewicz <marekm@amelek.gda.pl>
+
+ * config/avr/avr.c (print_operand): Check that addr is a SYMBOL_REF
+ before using SYMBOL_REF_FLAG (addr).
+
+ * config/avr/avr-protos.h (avr_io_address_p): Declare.
+ * config/avr/avr.c (io_address_p): Rename to avr_io_address_p.
+ Make non-static. Update all callers.
+ * config/avr/avr.md (*cbi, *sbi, *sbix_branch, *sbix_branch_bit7):
+ New insns to clear/set/test a single bit in I/O address space.
+
2002-05-09 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* rtl.h (ENABLE_RTL_FLAG_CHECKING): Also check for gcc >= 2.7.
extern void out_shift_with_cnt PARAMS ((const char *template, rtx insn,
rtx operands[], int *len,
int t_len));
+extern int avr_io_address_p PARAMS ((rtx x, int size));
extern int const_int_pow2_p PARAMS ((rtx x));
extern int avr_peep2_scratch_safe PARAMS ((rtx reg_rtx));
#endif /* RTX_CODE */
static RTX_CODE compare_condition PARAMS ((rtx insn));
static int compare_sign_p PARAMS ((rtx insn));
static int reg_was_0 PARAMS ((rtx insn, rtx op));
-static int io_address_p PARAMS ((rtx x, int size));
void debug_hard_reg_set PARAMS ((HARD_REG_SET set));
static tree avr_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *));
static tree avr_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
default:
if (CONSTANT_ADDRESS_P (addr)
- && (SYMBOL_REF_FLAG (addr) || GET_CODE (addr) == LABEL_REF))
+ && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
+ || GET_CODE (addr) == LABEL_REF))
{
fprintf (file, "pm(");
output_addr_const (file,addr);
if (CONSTANT_ADDRESS_P (x))
{
- if (io_address_p (x, 1))
+ if (avr_io_address_p (x, 1))
{
*l = 1;
return AS2 (in,%0,%1-0x20);
}
else if (CONSTANT_ADDRESS_P (base))
{
- if (io_address_p (base, 2))
+ if (avr_io_address_p (base, 2))
{
*l = 2;
return (AS2 (in,%A0,%A1-0x20) CR_TAB
if (CONSTANT_ADDRESS_P (x))
{
- if (io_address_p (x, 1))
+ if (avr_io_address_p (x, 1))
{
*l = 1;
return AS2 (out,%0-0x20,%1);
l = &tmp;
if (CONSTANT_ADDRESS_P (base))
{
- if (io_address_p (base, 2))
+ if (avr_io_address_p (base, 2))
{
*l = 2;
return (AS2 (out,%B0-0x20,%B1) CR_TAB
return 18;
if (CONSTANT_ADDRESS_P (x))
{
- if (io_address_p (x, 1))
+ if (avr_io_address_p (x, 1))
return 2;
return 4;
}
}
/* Returns 1 if X is a valid address for an I/O register of size SIZE
- (1 or 2). Used for lds/sts -> in/out optimization. */
+ (1 or 2). Used for lds/sts -> in/out optimization. Add 0x20 to SIZE
+ to check for the lower half of I/O space (for cbi/sbi/sbic/sbis). */
-static int
-io_address_p (x, size)
+int
+avr_io_address_p (x, size)
rtx x;
int size;
{
[(set_attr "length" "1")
(set_attr "cc" "compare")])
+;; Clear/set/test a single bit in I/O address space.
+
+(define_insn "*cbi"
+ [(set (mem:QI (match_operand 0 "const_int_operand" "n"))
+ (and:QI (mem:QI (match_dup 0))
+ (match_operand 1 "const_int_operand" "n")))]
+ "avr_io_address_p (operands[0], 1 + 0x20)
+ && exact_log2 (~INTVAL (operands[1]) & 0xff) >= 0"
+{
+ operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
+ return AS2 (cbi,%0-0x20,%2);
+}
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+(define_insn "*sbi"
+ [(set (mem:QI (match_operand 0 "const_int_operand" "n"))
+ (ior:QI (mem:QI (match_dup 0))
+ (match_operand 1 "const_int_operand" "n")))]
+ "avr_io_address_p (operands[0], 1 + 0x20)
+ && exact_log2 (INTVAL (operands[1]) & 0xff) >= 0"
+{
+ operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
+ return AS2 (sbi,%0-0x20,%2);
+}
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+(define_insn "*sbix_branch"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(zero_extract
+ (mem:QI (match_operand 1 "const_int_operand" "n"))
+ (const_int 1)
+ (match_operand 2 "const_int_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+ && avr_io_address_p (operands[1], 1 + 0x20)"
+{
+ enum rtx_code comp = GET_CODE (operands[0]);
+ int reverse = (get_attr_length (insn) == 4);
+
+ if (reverse)
+ comp = reverse_condition (comp);
+ if (comp == EQ)
+ output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
+ else
+ output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
+ if (!reverse)
+ return AS1 (rjmp,%3);
+ return (AS1 (rjmp,_PC_+4) CR_TAB
+ AS1 (jmp,%3));
+}
+ [(set (attr "length")
+ (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
+ (le (minus (pc) (match_dup 3)) (const_int 2046)))
+ (const_int 2)
+ (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 2)
+ (const_int 4))))
+ (set_attr "cc" "clobber")])
+
+;; Tests of bit 7 are pessimized to sign tests, so we need this too...
+(define_insn "*sbix_branch_bit7"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(mem:QI (match_operand 1 "const_int_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == GE || GET_CODE (operands[0]) == LT)
+ && avr_io_address_p (operands[1], 1 + 0x20)"
+{
+ enum rtx_code comp = GET_CODE (operands[0]);
+ int reverse = (get_attr_length (insn) == 4);
+
+ if (reverse)
+ comp = reverse_condition (comp);
+ if (comp == GE)
+ output_asm_insn (AS2 (sbis,%1-0x20,7), operands);
+ else
+ output_asm_insn (AS2 (sbic,%1-0x20,7), operands);
+ if (!reverse)
+ return AS1 (rjmp,%2);
+ return (AS1 (rjmp,_PC_+4) CR_TAB
+ AS1 (jmp,%2));
+}
+ [(set (attr "length")
+ (if_then_else (and (ge (minus (pc) (match_dup 2)) (const_int -2046))
+ (le (minus (pc) (match_dup 2)) (const_int 2046)))
+ (const_int 2)
+ (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 2)
+ (const_int 4))))
+ (set_attr "cc" "clobber")])
;; ************************* Peepholes ********************************