summaryrefslogtreecommitdiff
path: root/gcc/config/avr
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/avr')
-rw-r--r--gcc/config/avr/avr-protos.h2
-rw-r--r--gcc/config/avr/avr.c225
-rw-r--r--gcc/config/avr/avr.md240
-rw-r--r--gcc/config/avr/constraints.md30
4 files changed, 317 insertions, 180 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 6a0b40cbf7c..215fd834c3f 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -81,6 +81,8 @@ extern int avr_epilogue_uses (int regno);
extern void avr_output_bld (rtx operands[], int bit_nr);
extern void avr_output_addr_vec_elt (FILE *stream, int value);
extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
+extern const char* avr_out_bitop (rtx, rtx*, int*);
+extern bool avr_popcount_each_byte (rtx, int, int);
extern int extra_constraint_Q (rtx x);
extern int adjust_insn_length (rtx insn, int len);
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 42bc6f3fa35..9c8b43d9a37 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -303,6 +303,46 @@ avr_replace_prefix (const char *old_str,
return (const char*) new_str;
}
+
+/* Custom function to count number of set bits. */
+
+static inline int
+avr_popcount (unsigned int val)
+{
+ int pop = 0;
+
+ while (val)
+ {
+ val &= val-1;
+ pop++;
+ }
+
+ return pop;
+}
+
+
+/* Constraint helper function. XVAL is an CONST_INT. Return true if the least
+ significant N_BYTES bytes of XVAL all have a popcount in POP_MASK and false,
+ otherwise. POP_MASK represents a subset of integers which contains an
+ integer N iff bit N of POP_MASK is set. */
+
+bool
+avr_popcount_each_byte (rtx xval, int n_bytes, int pop_mask)
+{
+ int i;
+
+ for (i = 0; i < n_bytes; i++)
+ {
+ rtx xval8 = simplify_gen_subreg (QImode, xval, SImode, i);
+ unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode);
+
+ if (0 == (pop_mask & (1 << avr_popcount (val8))))
+ return false;
+ }
+
+ return true;
+}
+
static void
avr_option_override (void)
{
@@ -4462,6 +4502,157 @@ lshrsi3_out (rtx insn, rtx operands[], int *len)
return "";
}
+
+/* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile
+ time constant XOP[2]:
+
+ XOP[0] = XOP[0] <op> XOP[2]
+
+ and return "". If PLEN == NULL, print assembler instructions to perform the
+ operation; otherwise, set *PLEN to the length of the instruction sequence
+ (in words) printed with PLEN == NULL. XOP[3] is either an 8-bit clobber
+ register or SCRATCH if no clobber register is needed for the operation. */
+
+const char*
+avr_out_bitop (rtx insn, rtx *xop, int *plen)
+{
+ /* CODE and MODE of the operation. */
+ enum rtx_code code = GET_CODE (SET_SRC (single_set (insn)));
+ enum machine_mode mode = GET_MODE (xop[0]);
+
+ /* Number of bytes to operate on. */
+ int i, n_bytes = GET_MODE_SIZE (mode);
+
+ /* Value of T-flag (0 or 1) or -1 if unknow. */
+ int set_t = -1;
+
+ /* Value (0..0xff) held in clobber register op[3] or -1 if unknown. */
+ int clobber_val = -1;
+
+ /* op[0]: 8-bit destination register
+ op[1]: 8-bit const int
+ op[2]: 8-bit clobber register or SCRATCH
+ op[3]: 8-bit register containing 0xff or NULL_RTX */
+ rtx op[4];
+
+ op[2] = xop[3];
+ op[3] = NULL_RTX;
+
+ if (plen)
+ *plen = 0;
+
+ for (i = 0; i < n_bytes; i++)
+ {
+ /* We operate byte-wise on the destination. */
+ rtx reg8 = simplify_gen_subreg (QImode, xop[0], mode, i);
+ rtx xval8 = simplify_gen_subreg (QImode, xop[2], mode, i);
+
+ /* 8-bit value to operate with this byte. */
+ unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode);
+
+ /* Number of bits set in the current byte of the constant. */
+ int pop8 = avr_popcount (val8);
+
+ /* Registers R16..R31 can operate with immediate. */
+ bool ld_reg_p = test_hard_reg_class (LD_REGS, reg8);
+
+ op[0] = reg8;
+ op[1] = GEN_INT (val8);
+
+ switch (code)
+ {
+ case IOR:
+
+ if (0 == pop8)
+ continue;
+ else if (ld_reg_p)
+ avr_asm_len ("ori %0,%1", op, plen, 1);
+ else if (1 == pop8)
+ {
+ if (set_t != 1)
+ avr_asm_len ("set", op, plen, 1);
+ set_t = 1;
+
+ op[1] = GEN_INT (exact_log2 (val8));
+ avr_asm_len ("bld %0,%1", op, plen, 1);
+ }
+ else if (8 == pop8)
+ {
+ if (op[3] != NULL_RTX)
+ avr_asm_len ("mov %0,%3", op, plen, 1);
+ else
+ avr_asm_len ("clr %0" CR_TAB
+ "dec %0", op, plen, 2);
+
+ op[3] = op[0];
+ }
+ else
+ {
+ if (clobber_val != (int) val8)
+ avr_asm_len ("ldi %2,%1", op, plen, 1);
+ clobber_val = (int) val8;
+
+ avr_asm_len ("or %0,%2", op, plen, 1);
+ }
+
+ continue; /* IOR */
+
+ case AND:
+
+ if (8 == pop8)
+ continue;
+ else if (0 == pop8)
+ avr_asm_len ("clr %0", op, plen, 1);
+ else if (ld_reg_p)
+ avr_asm_len ("andi %0,%1", op, plen, 1);
+ else if (7 == pop8)
+ {
+ if (set_t != 0)
+ avr_asm_len ("clt", op, plen, 1);
+ set_t = 0;
+
+ op[1] = GEN_INT (exact_log2 (GET_MODE_MASK (QImode) & ~val8));
+ avr_asm_len ("bld %0,%1", op, plen, 1);
+ }
+ else
+ {
+ if (clobber_val != (int) val8)
+ avr_asm_len ("ldi %2,%1", op, plen, 1);
+ clobber_val = (int) val8;
+
+ avr_asm_len ("and %0,%2", op, plen, 1);
+ }
+
+ continue; /* AND */
+
+ case XOR:
+
+ if (0 == pop8)
+ continue;
+ else if (8 == pop8)
+ avr_asm_len ("com %0", op, plen, 1);
+ else if (ld_reg_p && val8 == (1 << 7))
+ avr_asm_len ("subi %0,%1", op, plen, 1);
+ else
+ {
+ if (clobber_val != (int) val8)
+ avr_asm_len ("ldi %2,%1", op, plen, 1);
+ clobber_val = (int) val8;
+
+ avr_asm_len ("eor %0,%2", op, plen, 1);
+ }
+
+ continue; /* XOR */
+
+ default:
+ /* Unknown rtx_code */
+ gcc_unreachable();
+ }
+ } /* for all sub-bytes */
+
+ return "";
+}
+
/* Create RTL split patterns for byte sized rotate expressions. This
produces a series of move instructions and considers overlap situations.
Overlapping non-HImode operands need a scratch register. */
@@ -4656,6 +4847,10 @@ adjust_insn_length (rtx insn, int len)
output_reload_insisf (insn, op, op[2], &len);
break;
+ case ADJUST_LEN_OUT_BITOP:
+ avr_out_bitop (insn, op, &len);
+ break;
+
default:
gcc_unreachable();
}
@@ -4700,36 +4895,6 @@ adjust_insn_length (rtx insn, int len)
default: break;
}
}
- else if (GET_CODE (op[1]) == AND)
- {
- if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
- {
- HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
- if (GET_MODE (op[1]) == SImode)
- len = (((mask & 0xff) != 0xff)
- + ((mask & 0xff00) != 0xff00)
- + ((mask & 0xff0000L) != 0xff0000L)
- + ((mask & 0xff000000L) != 0xff000000L));
- else if (GET_MODE (op[1]) == HImode)
- len = (((mask & 0xff) != 0xff)
- + ((mask & 0xff00) != 0xff00));
- }
- }
- else if (GET_CODE (op[1]) == IOR)
- {
- if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
- {
- HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
- if (GET_MODE (op[1]) == SImode)
- len = (((mask & 0xff) != 0)
- + ((mask & 0xff00) != 0)
- + ((mask & 0xff0000L) != 0)
- + ((mask & 0xff000000L) != 0));
- else if (GET_MODE (op[1]) == HImode)
- len = (((mask & 0xff) != 0)
- + ((mask & 0xff00) != 0));
- }
- }
}
set = single_set (insn);
if (set)
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index a1fcecbb04d..ab17104453e 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -136,7 +136,7 @@
;; Otherwise do special processing depending on the attribute.
(define_attr "adjust_len"
- "yes,no,reload_in32"
+ "yes,no,reload_in32,out_bitop"
(const_string "yes"))
;; Define mode iterators
@@ -2238,71 +2238,41 @@
(set_attr "cc" "set_zn,set_zn")])
(define_insn "andhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,d,r")
- (and:HI (match_operand:HI 1 "register_operand" "%0,0,0")
- (match_operand:HI 2 "nonmemory_operand" "r,i,M")))
- (clobber (match_scratch:QI 3 "=X,X,&d"))]
+ [(set (match_operand:HI 0 "register_operand" "=r,d,d,r ,r")
+ (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0 ,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,s,n,Ca2,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,&d"))]
""
-{
- if (which_alternative==0)
- return ("and %A0,%A2" CR_TAB
- "and %B0,%B2");
- else if (which_alternative==1)
- {
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- int mask = INTVAL (operands[2]);
- if ((mask & 0xff) != 0xff)
- output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
- if ((mask & 0xff00) != 0xff00)
- output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
- return "";
- }
- return (AS2 (andi,%A0,lo8(%2)) CR_TAB
- AS2 (andi,%B0,hi8(%2)));
- }
- return (AS2 (ldi,%3,lo8(%2)) CR_TAB
- "and %A0,%3" CR_TAB
- AS1 (clr,%B0));
-}
- [(set_attr "length" "2,2,3")
- (set_attr "cc" "set_n,clobber,set_n")])
+ {
+ if (which_alternative == 0)
+ return "and %A0,%A2\;and %B0,%B2";
+ else if (which_alternative == 1)
+ return "andi %A0,lo8(%2)\;andi %B0,hi8(%2)";
+
+ return avr_out_bitop (insn, operands, NULL);
+ }
+ [(set_attr "length" "2,2,2,4,4")
+ (set_attr "adjust_len" "no,no,out_bitop,out_bitop,out_bitop")
+ (set_attr "cc" "set_n,set_n,clobber,clobber,clobber")])
(define_insn "andsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+ [(set (match_operand:SI 0 "register_operand" "=r,d,r ,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,0 ,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,n,Ca4,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X ,&d"))]
""
-{
- if (which_alternative==0)
- return ("and %0,%2" CR_TAB
- "and %B0,%B2" CR_TAB
- "and %C0,%C2" CR_TAB
- "and %D0,%D2");
- else if (which_alternative==1)
- {
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- HOST_WIDE_INT mask = INTVAL (operands[2]);
- if ((mask & 0xff) != 0xff)
- output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
- if ((mask & 0xff00) != 0xff00)
- output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
- if ((mask & 0xff0000L) != 0xff0000L)
- output_asm_insn (AS2 (andi,%C0,hlo8(%2)), operands);
- if ((mask & 0xff000000L) != 0xff000000L)
- output_asm_insn (AS2 (andi,%D0,hhi8(%2)), operands);
- return "";
- }
- return (AS2 (andi, %A0,lo8(%2)) CR_TAB
- AS2 (andi, %B0,hi8(%2)) CR_TAB
- AS2 (andi, %C0,hlo8(%2)) CR_TAB
- AS2 (andi, %D0,hhi8(%2)));
- }
- return "bug";
-}
- [(set_attr "length" "4,4")
- (set_attr "cc" "set_n,clobber")])
+ {
+ if (which_alternative == 0)
+ return "and %0,%2" CR_TAB
+ "and %B0,%B2" CR_TAB
+ "and %C0,%C2" CR_TAB
+ "and %D0,%D2";
+
+ return avr_out_bitop (insn, operands, NULL);
+ }
+ [(set_attr "length" "4,4,8,8")
+ (set_attr "adjust_len" "no,out_bitop,out_bitop,out_bitop")
+ (set_attr "cc" "set_n,clobber,clobber,clobber")])
(define_peephole2 ; andi
[(set (match_operand:QI 0 "d_register_operand" "")
@@ -2332,84 +2302,41 @@
(set_attr "cc" "set_zn,set_zn")])
(define_insn "iorhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,d")
- (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "nonmemory_operand" "r,i")))]
+ [(set (match_operand:HI 0 "register_operand" "=r,d,d,r ,r")
+ (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0 ,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,s,n,Co2,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,&d"))]
""
-{
- if (which_alternative==0)
- return ("or %A0,%A2" CR_TAB
- "or %B0,%B2");
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- int mask = INTVAL (operands[2]);
- if (mask & 0xff)
- output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
- if (mask & 0xff00)
- output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
- return "";
- }
- return (AS2 (ori,%0,lo8(%2)) CR_TAB
- AS2 (ori,%B0,hi8(%2)));
-}
- [(set_attr "length" "2,2")
- (set_attr "cc" "set_n,clobber")])
+ {
+ if (which_alternative == 0)
+ return "or %A0,%A2\;or %B0,%B2";
+ else if (which_alternative == 1)
+ return "ori %A0,lo8(%2)\;ori %B0,hi8(%2)";
-(define_insn "*iorhi3_clobber"
- [(set (match_operand:HI 0 "register_operand" "=r,r")
- (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "immediate_operand" "M,i")))
- (clobber (match_scratch:QI 3 "=&d,&d"))]
- ""
- "@
- ldi %3,lo8(%2)\;or %A0,%3
- ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,hi8(%2)\;or %B0,%3"
- [(set_attr "length" "2,4")
- (set_attr "cc" "clobber,set_n")])
+ return avr_out_bitop (insn, operands, NULL);
+ }
+ [(set_attr "length" "2,2,2,4,4")
+ (set_attr "adjust_len" "no,no,out_bitop,out_bitop,out_bitop")
+ (set_attr "cc" "set_n,set_n,clobber,clobber,clobber")])
(define_insn "iorsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+ [(set (match_operand:SI 0 "register_operand" "=r,d,r ,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0 ,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,n,Co4,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X ,&d"))]
""
-{
- if (which_alternative==0)
- return ("or %0,%2" CR_TAB
- "or %B0,%B2" CR_TAB
- "or %C0,%C2" CR_TAB
- "or %D0,%D2");
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- HOST_WIDE_INT mask = INTVAL (operands[2]);
- if (mask & 0xff)
- output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
- if (mask & 0xff00)
- output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
- if (mask & 0xff0000L)
- output_asm_insn (AS2 (ori,%C0,hlo8(%2)), operands);
- if (mask & 0xff000000L)
- output_asm_insn (AS2 (ori,%D0,hhi8(%2)), operands);
- return "";
- }
- return (AS2 (ori, %A0,lo8(%2)) CR_TAB
- AS2 (ori, %B0,hi8(%2)) CR_TAB
- AS2 (ori, %C0,hlo8(%2)) CR_TAB
- AS2 (ori, %D0,hhi8(%2)));
-}
- [(set_attr "length" "4,4")
- (set_attr "cc" "set_n,clobber")])
+ {
+ if (which_alternative == 0)
+ return "or %0,%2" CR_TAB
+ "or %B0,%B2" CR_TAB
+ "or %C0,%C2" CR_TAB
+ "or %D0,%D2";
-(define_insn "*iorsi3_clobber"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "immediate_operand" "M,i")))
- (clobber (match_scratch:QI 3 "=&d,&d"))]
- ""
- "@
- ldi %3,lo8(%2)\;or %A0,%3
- ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,hi8(%2)\;or %B0,%3\;ldi %3,hlo8(%2)\;or %C0,%3\;ldi %3,hhi8(%2)\;or %D0,%3"
- [(set_attr "length" "2,8")
- (set_attr "cc" "clobber,set_n")])
+ return avr_out_bitop (insn, operands, NULL);
+ }
+ [(set_attr "length" "4,4,8,8")
+ (set_attr "adjust_len" "no,out_bitop,out_bitop,out_bitop")
+ (set_attr "cc" "set_n,clobber,clobber,clobber")])
;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; xor
@@ -2424,26 +2351,39 @@
(set_attr "cc" "set_zn")])
(define_insn "xorhi3"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (xor:HI (match_operand:HI 1 "register_operand" "%0")
- (match_operand:HI 2 "register_operand" "r")))]
+ [(set (match_operand:HI 0 "register_operand" "=r,r ,r")
+ (xor:HI (match_operand:HI 1 "register_operand" "%0,0 ,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,Cx2,n")))
+ (clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
- "eor %0,%2
- eor %B0,%B2"
- [(set_attr "length" "2")
- (set_attr "cc" "set_n")])
+ {
+ if (which_alternative == 0)
+ return "eor %A0,%A2\;eor %B0,%B2";
+
+ return avr_out_bitop (insn, operands, NULL);
+ }
+ [(set_attr "length" "2,2,4")
+ (set_attr "adjust_len" "no,out_bitop,out_bitop")
+ (set_attr "cc" "set_n,clobber,clobber")])
(define_insn "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (xor:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "r")))]
+ [(set (match_operand:SI 0 "register_operand" "=r,r ,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0 ,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,Cx4,n")))
+ (clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
- "eor %0,%2
- eor %B0,%B2
- eor %C0,%C2
- eor %D0,%D2"
- [(set_attr "length" "4")
- (set_attr "cc" "set_n")])
+ {
+ if (which_alternative == 0)
+ return "eor %0,%2" CR_TAB
+ "eor %B0,%B2" CR_TAB
+ "eor %C0,%C2" CR_TAB
+ "eor %D0,%D2";
+
+ return avr_out_bitop (insn, operands, NULL);
+ }
+ [(set_attr "length" "4,8,8")
+ (set_attr "adjust_len" "no,out_bitop,out_bitop")
+ (set_attr "cc" "set_n,clobber,clobber")])
;; swap swap swap swap swap swap swap swap swap swap swap swap swap swap swap
;; swap
diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md
index e754c79070b..d6c172f86e2 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -112,3 +112,33 @@
"Constant integer 4."
(and (match_code "const_int")
(match_test "ival == 4")))
+
+(define_constraint "Ca2"
+ "Constant 2-byte integer that allows AND without clobber register."
+ (and (match_code "const_int")
+ (match_test "avr_popcount_each_byte (op, 2, (1<<0) | (1<<7) | (1<<8))")))
+
+(define_constraint "Ca4"
+ "Constant 4-byte integer that allows AND without clobber register."
+ (and (match_code "const_int")
+ (match_test "avr_popcount_each_byte (op, 4, (1<<0) | (1<<7) | (1<<8))")))
+
+(define_constraint "Co2"
+ "Constant 2-byte integer that allows OR without clobber register."
+ (and (match_code "const_int")
+ (match_test "avr_popcount_each_byte (op, 2, (1<<0) | (1<<1) | (1<<8))")))
+
+(define_constraint "Co4"
+ "Constant 4-byte integer that allows OR without clobber register."
+ (and (match_code "const_int")
+ (match_test "avr_popcount_each_byte (op, 4, (1<<0) | (1<<1) | (1<<8))")))
+
+(define_constraint "Cx2"
+ "Constant 2-byte integer that allows XOR without clobber register."
+ (and (match_code "const_int")
+ (match_test "avr_popcount_each_byte (op, 2, (1<<0) | (1<<8))")))
+
+(define_constraint "Cx4"
+ "Constant 4-byte integer that allows XOR without clobber register."
+ (and (match_code "const_int")
+ (match_test "avr_popcount_each_byte (op, 4, (1<<0) | (1<<8))")))