;; Machine description for GNU compiler,
;; for ATMEL AVR micro controllers.
;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008,
;; 2009, 2010 Free Software Foundation, Inc.
;; Contributed by Denis Chertykov (chertykov@gmail.com)
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; .
;; Special characters after '%':
;; A No effect (add 0).
;; B Add 1 to REG number, MEM address or CONST_INT.
;; C Add 2.
;; D Add 3.
;; j Branch condition.
;; k Reverse branch condition.
;;..m..Constant Direct Data memory address.
;; o Displacement for (mem (plus (reg) (const_int))) operands.
;; p POST_INC or PRE_DEC address as a pointer (X, Y, Z)
;; r POST_INC or PRE_DEC address as a register (r26, r28, r30)
;;..x..Constant Direct Program memory address.
;; ~ Output 'r' if not AVR_HAVE_JMP_CALL.
;; ! Output 'e' if AVR_HAVE_EIJMP_EICALL.
(define_constants
[(REG_X 26)
(REG_Y 28)
(REG_Z 30)
(REG_W 24)
(REG_SP 32)
(TMP_REGNO 0) ; temporary register r0
(ZERO_REGNO 1) ; zero register r1
(SREG_ADDR 0x5F)
(RAMPZ_ADDR 0x5B)
])
(define_c_enum "unspec"
[UNSPEC_STRLEN
UNSPEC_INDEX_JMP
UNSPEC_FMUL
UNSPEC_FMULS
UNSPEC_FMULSU
UNSPEC_COPYSIGN
])
(define_c_enum "unspecv"
[UNSPECV_PROLOGUE_SAVES
UNSPECV_EPILOGUE_RESTORES
UNSPECV_WRITE_SP_IRQ_ON
UNSPECV_WRITE_SP_IRQ_OFF
UNSPECV_GOTO_RECEIVER
UNSPECV_ENABLE_IRQS
UNSPECV_NOP
UNSPECV_SLEEP
UNSPECV_WDR
UNSPECV_DELAY_CYCLES
])
(include "predicates.md")
(include "constraints.md")
;; Condition code settings.
(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber"
(const_string "none"))
(define_attr "type" "branch,branch1,arith,xcall"
(const_string "arith"))
(define_attr "mcu_have_movw" "yes,no"
(const (if_then_else (symbol_ref "AVR_HAVE_MOVW")
(const_string "yes")
(const_string "no"))))
(define_attr "mcu_mega" "yes,no"
(const (if_then_else (symbol_ref "AVR_HAVE_JMP_CALL")
(const_string "yes")
(const_string "no"))))
;; The size of instructions in bytes.
;; XXX may depend from "cc"
(define_attr "length" ""
(cond [(eq_attr "type" "branch")
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -63))
(le (minus (pc) (match_dup 0))
(const_int 62)))
(const_int 1)
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -2045))
(le (minus (pc) (match_dup 0))
(const_int 2045)))
(const_int 2)
(const_int 3)))
(eq_attr "type" "branch1")
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -62))
(le (minus (pc) (match_dup 0))
(const_int 61)))
(const_int 2)
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -2044))
(le (minus (pc) (match_dup 0))
(const_int 2043)))
(const_int 3)
(const_int 4)))
(eq_attr "type" "xcall")
(if_then_else (eq_attr "mcu_mega" "no")
(const_int 1)
(const_int 2))]
(const_int 2)))
;; Define mode iterator
(define_mode_iterator QISI [(QI "") (HI "") (SI "")])
(define_mode_iterator QIDI [(QI "") (HI "") (SI "") (DI "")])
(define_mode_iterator HIDI [(HI "") (SI "") (DI "")])
(define_mode_iterator HISI [(HI "") (SI "")])
;;========================================================================
;; The following is used by nonlocal_goto and setjmp.
;; The receiver pattern will create no instructions since internally
;; virtual_stack_vars = hard_frame_pointer + 1 so the RTL become R28=R28
;; This avoids creating add/sub offsets in frame_pointer save/resore.
;; The 'null' receiver also avoids problems with optimisation
;; not recognising incoming jmp and removing code that resets frame_pointer.
;; The code derived from builtins.c.
(define_expand "nonlocal_goto_receiver"
[(set (reg:HI REG_Y)
(unspec_volatile:HI [(const_int 0)] UNSPECV_GOTO_RECEIVER))]
""
{
emit_move_insn (virtual_stack_vars_rtx,
gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx,
gen_int_mode (STARTING_FRAME_OFFSET,
Pmode)));
/* This might change the hard frame pointer in ways that aren't
apparent to early optimization passes, so force a clobber. */
emit_clobber (hard_frame_pointer_rtx);
DONE;
})
;; Defining nonlocal_goto_receiver means we must also define this.
;; even though its function is identical to that in builtins.c
(define_expand "nonlocal_goto"
[
(use (match_operand 0 "general_operand"))
(use (match_operand 1 "general_operand"))
(use (match_operand 2 "general_operand"))
(use (match_operand 3 "general_operand"))
]
""
{
rtx r_label = copy_to_reg (operands[1]);
rtx r_fp = operands[3];
rtx r_sp = operands[2];
emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
emit_move_insn (hard_frame_pointer_rtx, r_fp);
emit_stack_restore (SAVE_NONLOCAL, r_sp);
emit_use (hard_frame_pointer_rtx);
emit_use (stack_pointer_rtx);
emit_indirect_jump (r_label);
DONE;
})
(define_insn "*pushqi"
[(set (mem:QI (post_dec:HI (reg:HI REG_SP)))
(match_operand:QI 0 "reg_or_0_operand" "r,L"))]
""
"@
push %0
push __zero_reg__"
[(set_attr "length" "1,1")])
(define_insn "*pushhi"
[(set (mem:HI (post_dec:HI (reg:HI REG_SP)))
(match_operand:HI 0 "reg_or_0_operand" "r,L"))]
""
"@
push %B0\;push %A0
push __zero_reg__\;push __zero_reg__"
[(set_attr "length" "2,2")])
(define_insn "*pushsi"
[(set (mem:SI (post_dec:HI (reg:HI REG_SP)))
(match_operand:SI 0 "reg_or_0_operand" "r,L"))]
""
"@
push %D0\;push %C0\;push %B0\;push %A0
push __zero_reg__\;push __zero_reg__\;push __zero_reg__\;push __zero_reg__"
[(set_attr "length" "4,4")])
(define_insn "*pushsf"
[(set (mem:SF (post_dec:HI (reg:HI REG_SP)))
(match_operand:SF 0 "register_operand" "r"))]
""
"push %D0
push %C0
push %B0
push %A0"
[(set_attr "length" "4")])
;;========================================================================
;; move byte
;; The last alternative (any immediate constant to any register) is
;; very expensive. It should be optimized by peephole2 if a scratch
;; register is available, but then that register could just as well be
;; allocated for the variable we are loading. But, most of NO_LD_REGS
;; are call-saved registers, and most of LD_REGS are call-used registers,
;; so this may still be a win for registers live across function calls.
(define_expand "movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
"/* One of the ops has to be in a register. */
if (!register_operand(operand0, QImode)
&& ! (register_operand(operand1, QImode) || const0_rtx == operand1))
operands[1] = copy_to_mode_reg(QImode, operand1);
")
(define_insn "*movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,d,Qm,r,q,r,*r")
(match_operand:QI 1 "general_operand" "rL,i,rL,Qm,r,q,i"))]
"(register_operand (operands[0],QImode)
|| register_operand (operands[1], QImode) || const0_rtx == operands[1])"
"* return output_movqi (insn, operands, NULL);"
[(set_attr "length" "1,1,5,5,1,1,4")
(set_attr "cc" "none,none,clobber,clobber,none,none,clobber")])
;; This is used in peephole2 to optimize loading immediate constants
;; if a scratch register from LD_REGS happens to be available.
(define_insn "*reload_inqi"
[(set (match_operand:QI 0 "register_operand" "=l")
(match_operand:QI 1 "immediate_operand" "i"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
"ldi %2,lo8(%1)
mov %0,%2"
[(set_attr "length" "2")
(set_attr "cc" "none")])
(define_peephole2
[(match_scratch:QI 2 "d")
(set (match_operand:QI 0 "l_register_operand" "")
(match_operand:QI 1 "immediate_operand" ""))]
"(operands[1] != const0_rtx
&& operands[1] != const1_rtx
&& operands[1] != constm1_rtx)"
[(parallel [(set (match_dup 0) (match_dup 1))
(clobber (match_dup 2))])]
"")
;;============================================================================
;; move word (16 bit)
(define_expand "movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
"
{
/* One of the ops has to be in a register. */
if (!register_operand(operand0, HImode)
&& !(register_operand(operand1, HImode) || const0_rtx == operands[1]))
{
operands[1] = copy_to_mode_reg(HImode, operand1);
}
}")
(define_insn "*movhi_sp"
[(set (match_operand:HI 0 "register_operand" "=q,r")
(match_operand:HI 1 "register_operand" "r,q"))]
"((stack_register_operand(operands[0], HImode) && register_operand (operands[1], HImode))
|| (register_operand (operands[0], HImode) && stack_register_operand(operands[1], HImode)))"
"* return output_movhi (insn, operands, NULL);"
[(set_attr "length" "5,2")
(set_attr "cc" "none,none")])
(define_insn "movhi_sp_r_irq_off"
[(set (match_operand:HI 0 "stack_register_operand" "=q")
(unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r")]
UNSPECV_WRITE_SP_IRQ_OFF))]
""
"out __SP_H__, %B1
out __SP_L__, %A1"
[(set_attr "length" "2")
(set_attr "cc" "none")])
(define_insn "movhi_sp_r_irq_on"
[(set (match_operand:HI 0 "stack_register_operand" "=q")
(unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r")]
UNSPECV_WRITE_SP_IRQ_ON))]
""
"cli
out __SP_H__, %B1
sei
out __SP_L__, %A1"
[(set_attr "length" "4")
(set_attr "cc" "none")])
(define_peephole2
[(match_scratch:QI 2 "d")
(set (match_operand:HI 0 "l_register_operand" "")
(match_operand:HI 1 "immediate_operand" ""))]
"(operands[1] != const0_rtx
&& operands[1] != constm1_rtx)"
[(parallel [(set (match_dup 0) (match_dup 1))
(clobber (match_dup 2))])]
"")
;; '*' because it is not used in rtl generation, only in above peephole
(define_insn "*reload_inhi"
[(set (match_operand:HI 0 "register_operand" "=r")
(match_operand:HI 1 "immediate_operand" "i"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
"* return output_reload_inhi (insn, operands, NULL);"
[(set_attr "length" "4")
(set_attr "cc" "none")])
(define_insn "*movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,d,*r,q,r")
(match_operand:HI 1 "general_operand" "rL,m,rL,i,i,r,q"))]
"(register_operand (operands[0],HImode)
|| register_operand (operands[1],HImode) || const0_rtx == operands[1])"
"* return output_movhi (insn, operands, NULL);"
[(set_attr "length" "2,6,7,2,6,5,2")
(set_attr "cc" "none,clobber,clobber,none,clobber,none,none")])
(define_peephole2 ; movw
[(set (match_operand:QI 0 "even_register_operand" "")
(match_operand:QI 1 "even_register_operand" ""))
(set (match_operand:QI 2 "odd_register_operand" "")
(match_operand:QI 3 "odd_register_operand" ""))]
"(AVR_HAVE_MOVW
&& REGNO (operands[0]) == REGNO (operands[2]) - 1
&& REGNO (operands[1]) == REGNO (operands[3]) - 1)"
[(set (match_dup 4) (match_dup 5))]
{
operands[4] = gen_rtx_REG (HImode, REGNO (operands[0]));
operands[5] = gen_rtx_REG (HImode, REGNO (operands[1]));
})
(define_peephole2 ; movw_r
[(set (match_operand:QI 0 "odd_register_operand" "")
(match_operand:QI 1 "odd_register_operand" ""))
(set (match_operand:QI 2 "even_register_operand" "")
(match_operand:QI 3 "even_register_operand" ""))]
"(AVR_HAVE_MOVW
&& REGNO (operands[2]) == REGNO (operands[0]) - 1
&& REGNO (operands[3]) == REGNO (operands[1]) - 1)"
[(set (match_dup 4) (match_dup 5))]
{
operands[4] = gen_rtx_REG (HImode, REGNO (operands[2]));
operands[5] = gen_rtx_REG (HImode, REGNO (operands[3]));
})
;;==========================================================================
;; move double word (32 bit)
(define_expand "movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
"
{
/* One of the ops has to be in a register. */
if (!register_operand (operand0, SImode)
&& !(register_operand (operand1, SImode) || const0_rtx == operand1))
{
operands[1] = copy_to_mode_reg (SImode, operand1);
}
}")
(define_peephole2 ; *reload_insi
[(match_scratch:QI 2 "d")
(set (match_operand:SI 0 "l_register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))
(match_dup 2)]
"(operands[1] != const0_rtx
&& operands[1] != constm1_rtx)"
[(parallel [(set (match_dup 0) (match_dup 1))
(clobber (match_dup 2))])]
"")
;; '*' because it is not used in rtl generation.
(define_insn "*reload_insi"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "const_int_operand" "n"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
{
return output_reload_insisf (insn, operands, operands[2], NULL);
}
[(set_attr "length" "8")
(set_attr "cc" "clobber")])
(define_insn "*movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Qm,!d,r")
(match_operand:SI 1 "general_operand" "r,L,Qm,rL,i,i"))]
"(register_operand (operands[0],SImode)
|| register_operand (operands[1],SImode) || const0_rtx == operands[1])"
{
return output_movsisf (insn, operands, NULL_RTX, NULL);
}
[(set_attr "length" "4,4,8,9,4,10")
(set_attr "cc" "none,set_zn,clobber,clobber,clobber,clobber")])
;; fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
;; move floating point numbers (32 bit)
(define_expand "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
"
{
/* One of the ops has to be in a register. */
if (!register_operand (operand1, SFmode)
&& !register_operand (operand0, SFmode))
{
operands[1] = copy_to_mode_reg (SFmode, operand1);
}
}")
(define_insn "*movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,Qm,!d,r")
(match_operand:SF 1 "general_operand" "r,G,Qm,rG,F,F"))]
"register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)
|| operands[1] == CONST0_RTX (SFmode)"
{
return output_movsisf (insn, operands, NULL_RTX, NULL);
}
[(set_attr "length" "4,4,8,9,4,10")
(set_attr "cc" "none,set_zn,clobber,clobber,clobber,clobber")])
(define_peephole2 ; *reload_insf
[(match_scratch:QI 2 "d")
(set (match_operand:SF 0 "l_register_operand" "")
(match_operand:SF 1 "const_double_operand" ""))
(match_dup 2)]
"operands[1] != CONST0_RTX (SFmode)"
[(parallel [(set (match_dup 0)
(match_dup 1))
(clobber (match_dup 2))])]
"")
;; '*' because it is not used in rtl generation.
(define_insn "*reload_insf"
[(set (match_operand:SF 0 "register_operand" "=r")
(match_operand:SF 1 "const_double_operand" "F"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
{
return output_reload_insisf (insn, operands, operands[2], NULL);
}
[(set_attr "length" "8")
(set_attr "cc" "clobber")])
;;=========================================================================
;; move string (like memcpy)
;; implement as RTL loop
(define_expand "movmemhi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:HI 2 "const_int_operand" ""))
(use (match_operand:HI 3 "const_int_operand" ""))])]
""
"{
int prob;
HOST_WIDE_INT count;
enum machine_mode mode;
rtx label = gen_label_rtx ();
rtx loop_reg;
rtx jump;
/* Copy pointers into new psuedos - they will be changed. */
rtx addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
rtx addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
/* Create rtx for tmp register - we use this as scratch. */
rtx tmp_reg_rtx = gen_rtx_REG (QImode, TMP_REGNO);
if (GET_CODE (operands[2]) != CONST_INT)
FAIL;
count = INTVAL (operands[2]);
if (count <= 0)
FAIL;
/* Work out branch probability for latter use. */
prob = REG_BR_PROB_BASE - REG_BR_PROB_BASE / count;
/* See if constant fit 8 bits. */
mode = (count < 0x100) ? QImode : HImode;
/* Create loop counter register. */
loop_reg = copy_to_mode_reg (mode, gen_int_mode (count, mode));
/* Now create RTL code for move loop. */
/* Label at top of loop. */
emit_label (label);
/* Move one byte into scratch and inc pointer. */
emit_move_insn (tmp_reg_rtx, gen_rtx_MEM (QImode, addr1));
emit_move_insn (addr1, gen_rtx_PLUS (Pmode, addr1, const1_rtx));
/* Move to mem and inc pointer. */
emit_move_insn (gen_rtx_MEM (QImode, addr0), tmp_reg_rtx);
emit_move_insn (addr0, gen_rtx_PLUS (Pmode, addr0, const1_rtx));
/* Decrement count. */
emit_move_insn (loop_reg, gen_rtx_PLUS (mode, loop_reg, constm1_rtx));
/* Compare with zero and jump if not equal. */
emit_cmp_and_jump_insns (loop_reg, const0_rtx, NE, NULL_RTX, mode, 1,
label);
/* Set jump probability based on loop count. */
jump = get_last_insn ();
add_reg_note (jump, REG_BR_PROB, GEN_INT (prob));
DONE;
}")
;; =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2
;; memset (%0, %2, %1)
(define_expand "setmemhi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
(match_operand 2 "const_int_operand" ""))
(use (match_operand:HI 1 "const_int_operand" ""))
(use (match_operand:HI 3 "const_int_operand" "n"))
(clobber (match_scratch:HI 4 ""))
(clobber (match_dup 5))])]
""
"{
rtx addr0;
int cnt8;
enum machine_mode mode;
/* If value to set is not zero, use the library routine. */
if (operands[2] != const0_rtx)
FAIL;
if (GET_CODE (operands[1]) != CONST_INT)
FAIL;
cnt8 = byte_immediate_operand (operands[1], GET_MODE (operands[1]));
mode = cnt8 ? QImode : HImode;
operands[5] = gen_rtx_SCRATCH (mode);
operands[1] = copy_to_mode_reg (mode,
gen_int_mode (INTVAL (operands[1]), mode));
addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
operands[0] = gen_rtx_MEM (BLKmode, addr0);
}")
(define_insn "*clrmemqi"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
(const_int 0))
(use (match_operand:QI 1 "register_operand" "r"))
(use (match_operand:QI 2 "const_int_operand" "n"))
(clobber (match_scratch:HI 3 "=0"))
(clobber (match_scratch:QI 4 "=&1"))]
""
"st %a0+,__zero_reg__
dec %1
brne .-6"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "*clrmemhi"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
(const_int 0))
(use (match_operand:HI 1 "register_operand" "!w,d"))
(use (match_operand:HI 2 "const_int_operand" "n,n"))
(clobber (match_scratch:HI 3 "=0,0"))
(clobber (match_scratch:HI 4 "=&1,&1"))]
""
"*{
if (which_alternative==0)
return (AS2 (st,%a0+,__zero_reg__) CR_TAB
AS2 (sbiw,%A1,1) CR_TAB
AS1 (brne,.-6));
else
return (AS2 (st,%a0+,__zero_reg__) CR_TAB
AS2 (subi,%A1,1) CR_TAB
AS2 (sbci,%B1,0) CR_TAB
AS1 (brne,.-8));
}"
[(set_attr "length" "3,4")
(set_attr "cc" "clobber,clobber")])
(define_expand "strlenhi"
[(set (match_dup 4)
(unspec:HI [(match_operand:BLK 1 "memory_operand" "")
(match_operand:QI 2 "const_int_operand" "")
(match_operand:HI 3 "immediate_operand" "")]
UNSPEC_STRLEN))
(set (match_dup 4) (plus:HI (match_dup 4)
(const_int -1)))
(set (match_operand:HI 0 "register_operand" "")
(minus:HI (match_dup 4)
(match_dup 5)))]
""
"{
rtx addr;
if (! (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0))
FAIL;
addr = copy_to_mode_reg (Pmode, XEXP (operands[1],0));
operands[1] = gen_rtx_MEM (BLKmode, addr);
operands[5] = addr;
operands[4] = gen_reg_rtx (HImode);
}")
(define_insn "*strlenhi"
[(set (match_operand:HI 0 "register_operand" "=e")
(unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "%0"))
(const_int 0)
(match_operand:HI 2 "immediate_operand" "i")]
UNSPEC_STRLEN))]
""
"ld __tmp_reg__,%a0+
tst __tmp_reg__
brne .-6"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; add bytes
(define_insn "addqi3"
[(set (match_operand:QI 0 "register_operand" "=r,d,r,r")
(plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0")
(match_operand:QI 2 "nonmemory_operand" "r,i,P,N")))]
""
"@
add %0,%2
subi %0,lo8(-(%2))
inc %0
dec %0"
[(set_attr "length" "1,1,1,1")
(set_attr "cc" "set_czn,set_czn,set_zn,set_zn")])
(define_expand "addhi3"
[(set (match_operand:HI 0 "register_operand" "")
(plus:HI (match_operand:HI 1 "register_operand" "")
(match_operand:HI 2 "nonmemory_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
short tmp = INTVAL (operands[2]);
operands[2] = GEN_INT(tmp);
}
}")
(define_insn "*addhi3_zero_extend"
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (zero_extend:HI
(match_operand:QI 1 "register_operand" "r"))
(match_operand:HI 2 "register_operand" "0")))]
""
"add %A0,%1
adc %B0,__zero_reg__"
[(set_attr "length" "2")
(set_attr "cc" "set_n")])
(define_insn "*addhi3_zero_extend1"
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (match_operand:HI 1 "register_operand" "%0")
(zero_extend:HI
(match_operand:QI 2 "register_operand" "r"))))]
""
"add %A0,%2
adc %B0,__zero_reg__"
[(set_attr "length" "2")
(set_attr "cc" "set_n")])
(define_insn "*addhi3_sp_R_pc2"
[(set (match_operand:HI 1 "stack_register_operand" "=q")
(plus:HI (match_operand:HI 2 "stack_register_operand" "q")
(match_operand:HI 0 "avr_sp_immediate_operand" "R")))]
"AVR_2_BYTE_PC"
"*{
if (CONST_INT_P (operands[0]))
{
switch(INTVAL (operands[0]))
{
case -6:
return \"rcall .\" CR_TAB
\"rcall .\" CR_TAB
\"rcall .\";
case -5:
return \"rcall .\" CR_TAB
\"rcall .\" CR_TAB
\"push __tmp_reg__\";
case -4:
return \"rcall .\" CR_TAB
\"rcall .\";
case -3:
return \"rcall .\" CR_TAB
\"push __tmp_reg__\";
case -2:
return \"rcall .\";
case -1:
return \"push __tmp_reg__\";
case 0:
return \"\";
case 1:
return \"pop __tmp_reg__\";
case 2:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
case 3:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
case 4:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
case 5:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
}
}
return \"bug\";
}"
[(set (attr "length")
(cond [(eq (const_int -6) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
(eq (const_int -5) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
(eq (const_int -4) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int -3) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int -2) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
(eq (const_int -1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
(eq (const_int 0) (symbol_ref "INTVAL (operands[0])")) (const_int 0)
(eq (const_int 1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
(eq (const_int 2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int 3) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
(eq (const_int 4) (symbol_ref "INTVAL (operands[0])")) (const_int 4)
(eq (const_int 5) (symbol_ref "INTVAL (operands[0])")) (const_int 5)]
(const_int 0)))])
(define_insn "*addhi3_sp_R_pc3"
[(set (match_operand:HI 1 "stack_register_operand" "=q")
(plus:HI (match_operand:HI 2 "stack_register_operand" "q")
(match_operand:QI 0 "avr_sp_immediate_operand" "R")))]
"AVR_3_BYTE_PC"
"*{
if (CONST_INT_P (operands[0]))
{
switch(INTVAL (operands[0]))
{
case -6:
return \"rcall .\" CR_TAB
\"rcall .\";
case -5:
return \"rcall .\" CR_TAB
\"push __tmp_reg__\" CR_TAB
\"push __tmp_reg__\";
case -4:
return \"rcall .\" CR_TAB
\"push __tmp_reg__\";
case -3:
return \"rcall .\";
case -2:
return \"push __tmp_reg__\" CR_TAB
\"push __tmp_reg__\";
case -1:
return \"push __tmp_reg__\";
case 0:
return \"\";
case 1:
return \"pop __tmp_reg__\";
case 2:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
case 3:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
case 4:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
case 5:
return \"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\" CR_TAB
\"pop __tmp_reg__\";
}
}
return \"bug\";
}"
[(set (attr "length")
(cond [(eq (const_int -6) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int -5) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
(eq (const_int -4) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int -3) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
(eq (const_int -2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int -1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
(eq (const_int 0) (symbol_ref "INTVAL (operands[0])")) (const_int 0)
(eq (const_int 1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
(eq (const_int 2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
(eq (const_int 3) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
(eq (const_int 4) (symbol_ref "INTVAL (operands[0])")) (const_int 4)
(eq (const_int 5) (symbol_ref "INTVAL (operands[0])")) (const_int 5)]
(const_int 0)))])
(define_insn "*addhi3"
[(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r")
(plus:HI
(match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
(match_operand:HI 2 "nonmemory_operand" "r,I,J,i,P,N")))]
""
"@
add %A0,%A2\;adc %B0,%B2
adiw %A0,%2
sbiw %A0,%n2
subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))
sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__
sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__"
[(set_attr "length" "2,1,1,2,3,3")
(set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,!w,!w,d,r,r")
(plus:SI
(match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
(match_operand:SI 2 "nonmemory_operand" "r,I,J,i,P,N")))]
""
"@
add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2
adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__
subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))
sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__"
[(set_attr "length" "4,3,3,4,5,5")
(set_attr "cc" "set_n,set_n,set_czn,set_czn,set_n,set_n")])
(define_insn "*addsi3_zero_extend"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (zero_extend:SI
(match_operand:QI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "0")))]
""
"add %A0,%1
adc %B0,__zero_reg__
adc %C0,__zero_reg__
adc %D0,__zero_reg__"
[(set_attr "length" "4")
(set_attr "cc" "set_n")])
;-----------------------------------------------------------------------------
; sub bytes
(define_insn "subqi3"
[(set (match_operand:QI 0 "register_operand" "=r,d")
(minus:QI (match_operand:QI 1 "register_operand" "0,0")
(match_operand:QI 2 "nonmemory_operand" "r,i")))]
""
"@
sub %0,%2
subi %0,lo8(%2)"
[(set_attr "length" "1,1")
(set_attr "cc" "set_czn,set_czn")])
(define_insn "subhi3"
[(set (match_operand:HI 0 "register_operand" "=r,d")
(minus:HI (match_operand:HI 1 "register_operand" "0,0")
(match_operand:HI 2 "nonmemory_operand" "r,i")))]
""
"@
sub %A0,%A2\;sbc %B0,%B2
subi %A0,lo8(%2)\;sbci %B0,hi8(%2)"
[(set_attr "length" "2,2")
(set_attr "cc" "set_czn,set_czn")])
(define_insn "*subhi3_zero_extend1"
[(set (match_operand:HI 0 "register_operand" "=r")
(minus:HI (match_operand:HI 1 "register_operand" "0")
(zero_extend:HI
(match_operand:QI 2 "register_operand" "r"))))]
""
"sub %A0,%2
sbc %B0,__zero_reg__"
[(set_attr "length" "2")
(set_attr "cc" "set_n")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r,d")
(minus:SI (match_operand:SI 1 "register_operand" "0,0")
(match_operand:SI 2 "nonmemory_operand" "r,i")))]
""
"@
sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2
subi %A0,lo8(%2)\;sbci %B0,hi8(%2)\;sbci %C0,hlo8(%2)\;sbci %D0,hhi8(%2)"
[(set_attr "length" "4,4")
(set_attr "cc" "set_czn,set_czn")])
(define_insn "*subsi3_zero_extend"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "0")
(zero_extend:SI
(match_operand:QI 2 "register_operand" "r"))))]
""
"sub %A0,%2
sbc %B0,__zero_reg__
sbc %C0,__zero_reg__
sbc %D0,__zero_reg__"
[(set_attr "length" "4")
(set_attr "cc" "set_n")])
;******************************************************************************
; mul
(define_expand "mulqi3"
[(set (match_operand:QI 0 "register_operand" "")
(mult:QI (match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "register_operand" "")))]
""
"{
if (!AVR_HAVE_MUL)
{
emit_insn (gen_mulqi3_call (operands[0], operands[1], operands[2]));
DONE;
}
}")
(define_insn "*mulqi3_enh"
[(set (match_operand:QI 0 "register_operand" "=r")
(mult:QI (match_operand:QI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r")))]
"AVR_HAVE_MUL"
"mul %1,%2
mov %0,r0
clr r1"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_expand "mulqi3_call"
[(set (reg:QI 24) (match_operand:QI 1 "register_operand" ""))
(set (reg:QI 22) (match_operand:QI 2 "register_operand" ""))
(parallel [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 22))])
(set (match_operand:QI 0 "register_operand" "") (reg:QI 24))]
""
"")
(define_insn "*mulqi3_call"
[(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 22))]
"!AVR_HAVE_MUL"
"%~call __mulqi3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "mulqihi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d"))
(sign_extend:HI (match_operand:QI 2 "register_operand" "d"))))]
"AVR_HAVE_MUL"
"muls %1,%2
movw %0,r0
clr r1"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "umulqihi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
(zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
"AVR_HAVE_MUL"
"mul %1,%2
movw %0,r0
clr r1"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "usmulqihi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "a"))
(sign_extend:HI (match_operand:QI 2 "register_operand" "a"))))]
"AVR_HAVE_MUL"
"mulsu %2,%1
movw %0,r0
clr __zero_reg__"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
;; Above insn is not canonicalized by insn combine, so here is a version with
;; operands swapped.
(define_insn "*sumulqihi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a"))
(zero_extend:HI (match_operand:QI 2 "register_operand" "a"))))]
"AVR_HAVE_MUL"
"mulsu %1,%2
movw %0,r0
clr __zero_reg__"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
;; One-extend operand 1
(define_insn "*osmulqihi3"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (not:HI (zero_extend:HI (not:QI (match_operand:QI 1 "register_operand" "a"))))
(sign_extend:HI (match_operand:QI 2 "register_operand" "a"))))]
"AVR_HAVE_MUL"
"mulsu %2,%1
movw %0,r0
sub %B0,%2
clr __zero_reg__"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*oumulqihi3"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (not:HI (zero_extend:HI (not:QI (match_operand:QI 1 "register_operand" "r"))))
(zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
"AVR_HAVE_MUL"
"mul %2,%1
movw %0,r0
sub %B0,%2
clr __zero_reg__"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
;******************************************************************************
; mul HI: $1 = sign/zero-extend, $2 = small constant
;******************************************************************************
(define_insn_and_split "*muluqihi3.uconst"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
(match_operand:HI 2 "u8_operand" "M")))
(clobber (match_scratch:QI 3 "=&d"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; umulqihi3
(set (match_dup 0)
(mult:HI (zero_extend:HI (match_dup 1))
(zero_extend:HI (match_dup 3))))]
{
operands[2] = gen_int_mode (INTVAL (operands[2]), QImode);
})
(define_insn_and_split "*muluqihi3.sconst"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "a"))
(match_operand:HI 2 "s8_operand" "n")))
(clobber (match_scratch:QI 3 "=&a"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; usmulqihi3
(set (match_dup 0)
(mult:HI (zero_extend:HI (match_dup 1))
(sign_extend:HI (match_dup 3))))]
{
operands[2] = gen_int_mode (INTVAL (operands[2]), QImode);
})
(define_insn_and_split "*mulsqihi3.sconst"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d"))
(match_operand:HI 2 "s8_operand" "n")))
(clobber (match_scratch:QI 3 "=&d"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; mulqihi3
(set (match_dup 0)
(mult:HI (sign_extend:HI (match_dup 1))
(sign_extend:HI (match_dup 3))))]
{
operands[2] = gen_int_mode (INTVAL (operands[2]), QImode);
})
(define_insn_and_split "*mulsqihi3.uconst"
[(set (match_operand:HI 0 "register_operand" "=r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a"))
(match_operand:HI 2 "u8_operand" "M")))
(clobber (match_scratch:QI 3 "=&a"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; usmulqihi3
(set (match_dup 0)
(mult:HI (zero_extend:HI (match_dup 3))
(sign_extend:HI (match_dup 1))))]
{
operands[2] = gen_int_mode (INTVAL (operands[2]), QImode);
})
(define_insn_and_split "*mulsqihi3.oconst"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a"))
(match_operand:HI 2 "o8_operand" "n")))
(clobber (match_scratch:QI 3 "=&a"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; *osmulqihi3
(set (match_dup 0)
(mult:HI (not:HI (zero_extend:HI (not:QI (match_dup 3))))
(sign_extend:HI (match_dup 1))))]
{
operands[2] = gen_int_mode (INTVAL (operands[2]), QImode);
})
;; The EXTEND of $1 only appears in combine, we don't see it in expand so that
;; expand decides to use ASHIFT instead of MUL because ASHIFT costs are cheaper
;; at that time. Fix that.
(define_insn_and_split "*ashifthi3.signx.const"
[(set (match_operand:HI 0 "register_operand" "=r")
(ashift:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d"))
(match_operand:HI 2 "const_2_to_6_operand" "I")))
(clobber (match_scratch:QI 3 "=&d"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; mulqihi3
(set (match_dup 0)
(mult:HI (sign_extend:HI (match_dup 1))
(sign_extend:HI (match_dup 3))))]
{
operands[2] = GEN_INT (1 << INTVAL (operands[2]));
})
(define_insn_and_split "*ashifthi3.signx.const7"
[(set (match_operand:HI 0 "register_operand" "=r")
(ashift:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a"))
(const_int 7)))
(clobber (match_scratch:QI 2 "=&a"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 2)
(match_dup 3))
; usmulqihi3
(set (match_dup 0)
(mult:HI (zero_extend:HI (match_dup 2))
(sign_extend:HI (match_dup 1))))]
{
operands[3] = gen_int_mode (1 << 7, QImode);
})
(define_insn_and_split "*ashifthi3.zerox.const"
[(set (match_operand:HI 0 "register_operand" "=r")
(ashift:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
(match_operand:HI 2 "const_2_to_7_operand" "I")))
(clobber (match_scratch:QI 3 "=&d"))]
"AVR_HAVE_MUL"
"#"
"&& reload_completed"
[(set (match_dup 3)
(match_dup 2))
; umulqihi3
(set (match_dup 0)
(mult:HI (zero_extend:HI (match_dup 1))
(zero_extend:HI (match_dup 3))))]
{
operands[2] = gen_int_mode (1 << INTVAL (operands[2]), QImode);
})
;******************************************************************************
; mul HI: $1 = sign-/zero-/one-extend, $2 = reg
;******************************************************************************
(define_insn "mulsqihi3"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a"))
(match_operand:HI 2 "register_operand" "a")))]
"AVR_HAVE_MUL"
"mulsu %1,%A2
movw %0,r0
mul %1,%B2
add %B0,r0
clr __zero_reg__"
[(set_attr "length" "5")
(set_attr "cc" "clobber")])
(define_insn "muluqihi3"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
(match_operand:HI 2 "register_operand" "r")))]
"AVR_HAVE_MUL"
"mul %1,%A2
movw %0,r0
mul %1,%B2
add %B0,r0
clr __zero_reg__"
[(set_attr "length" "5")
(set_attr "cc" "clobber")])
;; one-extend operand 1
(define_insn "muloqihi3"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (not:HI (zero_extend:HI (not:QI (match_operand:QI 1 "register_operand" "r"))))
(match_operand:HI 2 "register_operand" "r")))]
"AVR_HAVE_MUL"
"mul %1,%A2
movw %0,r0
mul %1,%B2
add %B0,r0
sub %B0,%A2
clr __zero_reg__"
[(set_attr "length" "6")
(set_attr "cc" "clobber")])
;******************************************************************************
(define_expand "mulhi3"
[(set (match_operand:HI 0 "register_operand" "")
(mult:HI (match_operand:HI 1 "register_operand" "")
(match_operand:HI 2 "register_or_s9_operand" "")))]
""
{
if (!AVR_HAVE_MUL)
{
if (!register_operand (operands[2], HImode))
operands[2] = force_reg (HImode, operands[2]);
emit_insn (gen_mulhi3_call (operands[0], operands[1], operands[2]));
DONE;
}
/* For small constants we can do better by extending them on the fly.
The constant can be loaded in one instruction and the widening
multiplication is shorter. First try the unsigned variant because it
allows constraint "d" instead of "a" for the signed version. */
if (s9_operand (operands[2], HImode))
{
rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode));
if (u8_operand (operands[2], HImode))
{
emit_insn (gen_muluqihi3 (operands[0], reg, operands[1]));
}
else if (s8_operand (operands[2], HImode))
{
emit_insn (gen_mulsqihi3 (operands[0], reg, operands[1]));
}
else
{
emit_insn (gen_muloqihi3 (operands[0], reg, operands[1]));
}
DONE;
}
if (!register_operand (operands[2], HImode))
operands[2] = force_reg (HImode, operands[2]);
})
(define_insn "*mulhi3_enh"
[(set (match_operand:HI 0 "register_operand" "=&r")
(mult:HI (match_operand:HI 1 "register_operand" "r")
(match_operand:HI 2 "register_operand" "r")))]
"AVR_HAVE_MUL"
"mul %A1,%A2
movw %0,r0
mul %A1,%B2
add %B0,r0
mul %B1,%A2
add %B0,r0
clr r1"
[(set_attr "length" "7")
(set_attr "cc" "clobber")])
(define_expand "mulhi3_call"
[(set (reg:HI 24) (match_operand:HI 1 "register_operand" ""))
(set (reg:HI 22) (match_operand:HI 2 "register_operand" ""))
(parallel [(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 22))
(clobber (reg:QI 21))])
(set (match_operand:HI 0 "register_operand" "") (reg:HI 24))]
""
"")
(define_insn "*mulhi3_call"
[(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 22))
(clobber (reg:QI 21))]
"!AVR_HAVE_MUL"
"%~call __mulhi3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; Operand 2 (reg:SI 18) not clobbered on the enhanced core.
;; All call-used registers clobbered otherwise - normal library call.
(define_expand "mulsi3"
[(set (reg:SI 22) (match_operand:SI 1 "register_operand" ""))
(set (reg:SI 18) (match_operand:SI 2 "register_operand" ""))
(parallel [(set (reg:SI 22) (mult:SI (reg:SI 22) (reg:SI 18)))
(clobber (reg:HI 26))
(clobber (reg:HI 30))])
(set (match_operand:SI 0 "register_operand" "") (reg:SI 22))]
"AVR_HAVE_MUL"
"")
(define_insn "*mulsi3_call"
[(set (reg:SI 22) (mult:SI (reg:SI 22) (reg:SI 18)))
(clobber (reg:HI 26))
(clobber (reg:HI 30))]
"AVR_HAVE_MUL"
"%~call __mulsi3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_expand "mulhisi3"
[(set (reg:HI 18)
(match_operand:HI 1 "register_operand" ""))
(set (reg:HI 20)
(match_operand:HI 2 "register_operand" ""))
(set (reg:SI 22)
(mult:SI (sign_extend:SI (reg:HI 18))
(sign_extend:SI (reg:HI 20))))
(set (match_operand:SI 0 "register_operand" "")
(reg:SI 22))]
"AVR_HAVE_MUL"
"")
(define_expand "umulhisi3"
[(set (reg:HI 18)
(match_operand:HI 1 "register_operand" ""))
(set (reg:HI 20)
(match_operand:HI 2 "register_operand" ""))
(set (reg:SI 22)
(mult:SI (zero_extend:SI (reg:HI 18))
(zero_extend:SI (reg:HI 20))))
(set (match_operand:SI 0 "register_operand" "")
(reg:SI 22))]
"AVR_HAVE_MUL"
"")
(define_insn "*mulhisi3_call"
[(set (reg:SI 22)
(mult:SI (sign_extend:SI (reg:HI 18))
(sign_extend:SI (reg:HI 20))))]
"AVR_HAVE_MUL"
"%~call __mulhisi3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*umulhisi3_call"
[(set (reg:SI 22)
(mult:SI (zero_extend:SI (reg:HI 18))
(zero_extend:SI (reg:HI 20))))]
"AVR_HAVE_MUL"
"%~call __umulhisi3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / %
; divmod
;; Generate libgcc.S calls ourselves, because:
;; - we know exactly which registers are clobbered (for QI and HI
;; modes, some of the call-used registers are preserved)
;; - we get both the quotient and the remainder at no extra cost
;; - we split the patterns only after the first CSE passes because
;; CSE has problems to operate on hard regs.
;;
(define_insn_and_split "divmodqi4"
[(parallel [(set (match_operand:QI 0 "pseudo_register_operand" "")
(div:QI (match_operand:QI 1 "pseudo_register_operand" "")
(match_operand:QI 2 "pseudo_register_operand" "")))
(set (match_operand:QI 3 "pseudo_register_operand" "")
(mod:QI (match_dup 1) (match_dup 2)))
(clobber (reg:QI 22))
(clobber (reg:QI 23))
(clobber (reg:QI 24))
(clobber (reg:QI 25))])]
""
"this divmodqi4 pattern should have been splitted;"
""
[(set (reg:QI 24) (match_dup 1))
(set (reg:QI 22) (match_dup 2))
(parallel [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22)))
(set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 22))
(clobber (reg:QI 23))])
(set (match_dup 0) (reg:QI 24))
(set (match_dup 3) (reg:QI 25))]
"")
(define_insn "*divmodqi4_call"
[(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22)))
(set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 22))
(clobber (reg:QI 23))]
""
"%~call __divmodqi4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn_and_split "udivmodqi4"
[(parallel [(set (match_operand:QI 0 "pseudo_register_operand" "")
(udiv:QI (match_operand:QI 1 "pseudo_register_operand" "")
(match_operand:QI 2 "pseudo_register_operand" "")))
(set (match_operand:QI 3 "pseudo_register_operand" "")
(umod:QI (match_dup 1) (match_dup 2)))
(clobber (reg:QI 22))
(clobber (reg:QI 23))
(clobber (reg:QI 24))
(clobber (reg:QI 25))])]
""
"this udivmodqi4 pattern should have been splitted;"
""
[(set (reg:QI 24) (match_dup 1))
(set (reg:QI 22) (match_dup 2))
(parallel [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22)))
(set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 23))])
(set (match_dup 0) (reg:QI 24))
(set (match_dup 3) (reg:QI 25))]
"")
(define_insn "*udivmodqi4_call"
[(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22)))
(set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 23))]
""
"%~call __udivmodqi4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn_and_split "divmodhi4"
[(parallel [(set (match_operand:HI 0 "pseudo_register_operand" "")
(div:HI (match_operand:HI 1 "pseudo_register_operand" "")
(match_operand:HI 2 "pseudo_register_operand" "")))
(set (match_operand:HI 3 "pseudo_register_operand" "")
(mod:HI (match_dup 1) (match_dup 2)))
(clobber (reg:QI 21))
(clobber (reg:HI 22))
(clobber (reg:HI 24))
(clobber (reg:HI 26))])]
""
"this should have been splitted;"
""
[(set (reg:HI 24) (match_dup 1))
(set (reg:HI 22) (match_dup 2))
(parallel [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22)))
(set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 26))
(clobber (reg:QI 21))])
(set (match_dup 0) (reg:HI 22))
(set (match_dup 3) (reg:HI 24))]
"")
(define_insn "*divmodhi4_call"
[(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22)))
(set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 26))
(clobber (reg:QI 21))]
""
"%~call __divmodhi4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn_and_split "udivmodhi4"
[(parallel [(set (match_operand:HI 0 "pseudo_register_operand" "")
(udiv:HI (match_operand:HI 1 "pseudo_register_operand" "")
(match_operand:HI 2 "pseudo_register_operand" "")))
(set (match_operand:HI 3 "pseudo_register_operand" "")
(umod:HI (match_dup 1) (match_dup 2)))
(clobber (reg:QI 21))
(clobber (reg:HI 22))
(clobber (reg:HI 24))
(clobber (reg:HI 26))])]
""
"this udivmodhi4 pattern should have been splitted.;"
""
[(set (reg:HI 24) (match_dup 1))
(set (reg:HI 22) (match_dup 2))
(parallel [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22)))
(set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 26))
(clobber (reg:QI 21))])
(set (match_dup 0) (reg:HI 22))
(set (match_dup 3) (reg:HI 24))]
"")
(define_insn "*udivmodhi4_call"
[(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22)))
(set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 26))
(clobber (reg:QI 21))]
""
"%~call __udivmodhi4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn_and_split "divmodsi4"
[(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "")
(div:SI (match_operand:SI 1 "pseudo_register_operand" "")
(match_operand:SI 2 "pseudo_register_operand" "")))
(set (match_operand:SI 3 "pseudo_register_operand" "")
(mod:SI (match_dup 1) (match_dup 2)))
(clobber (reg:SI 18))
(clobber (reg:SI 22))
(clobber (reg:HI 26))
(clobber (reg:HI 30))])]
""
"this divmodsi4 pattern should have been splitted;"
""
[(set (reg:SI 22) (match_dup 1))
(set (reg:SI 18) (match_dup 2))
(parallel [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18)))
(set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18)))
(clobber (reg:HI 26))
(clobber (reg:HI 30))])
(set (match_dup 0) (reg:SI 18))
(set (match_dup 3) (reg:SI 22))]
"")
(define_insn "*divmodsi4_call"
[(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18)))
(set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18)))
(clobber (reg:HI 26))
(clobber (reg:HI 30))]
""
"%~call __divmodsi4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn_and_split "udivmodsi4"
[(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "")
(udiv:SI (match_operand:SI 1 "pseudo_register_operand" "")
(match_operand:SI 2 "pseudo_register_operand" "")))
(set (match_operand:SI 3 "pseudo_register_operand" "")
(umod:SI (match_dup 1) (match_dup 2)))
(clobber (reg:SI 18))
(clobber (reg:SI 22))
(clobber (reg:HI 26))
(clobber (reg:HI 30))])]
""
"this udivmodsi4 pattern should have been splitted;"
""
[(set (reg:SI 22) (match_dup 1))
(set (reg:SI 18) (match_dup 2))
(parallel [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18)))
(set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18)))
(clobber (reg:HI 26))
(clobber (reg:HI 30))])
(set (match_dup 0) (reg:SI 18))
(set (match_dup 3) (reg:SI 22))]
"")
(define_insn "*udivmodsi4_call"
[(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18)))
(set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18)))
(clobber (reg:HI 26))
(clobber (reg:HI 30))]
""
"%~call __udivmodsi4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; and
(define_insn "andqi3"
[(set (match_operand:QI 0 "register_operand" "=r,d")
(and:QI (match_operand:QI 1 "register_operand" "%0,0")
(match_operand:QI 2 "nonmemory_operand" "r,i")))]
""
"@
and %0,%2
andi %0,lo8(%2)"
[(set_attr "length" "1,1")
(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"))]
""
{
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")])
(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")))]
""
{
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")])
(define_peephole2 ; andi
[(set (match_operand:QI 0 "d_register_operand" "")
(and:QI (match_dup 0)
(match_operand:QI 1 "const_int_operand" "")))
(set (match_dup 0)
(and:QI (match_dup 0)
(match_operand:QI 2 "const_int_operand" "")))]
""
[(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
{
operands[1] = GEN_INT (INTVAL (operands[1]) & INTVAL (operands[2]));
})
;;|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
;; ior
(define_insn "iorqi3"
[(set (match_operand:QI 0 "register_operand" "=r,d")
(ior:QI (match_operand:QI 1 "register_operand" "%0,0")
(match_operand:QI 2 "nonmemory_operand" "r,i")))]
""
"@
or %0,%2
ori %0,lo8(%2)"
[(set_attr "length" "1,1")
(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")))]
""
{
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")])
(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")])
(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")))]
""
{
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")])
(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")])
;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; xor
(define_insn "xorqi3"
[(set (match_operand:QI 0 "register_operand" "=r")
(xor:QI (match_operand:QI 1 "register_operand" "%0")
(match_operand:QI 2 "register_operand" "r")))]
""
"eor %0,%2"
[(set_attr "length" "1")
(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")))]
""
"eor %0,%2
eor %B0,%B2"
[(set_attr "length" "2")
(set_attr "cc" "set_n")])
(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")))]
""
"eor %0,%2
eor %B0,%B2
eor %C0,%C2
eor %D0,%D2"
[(set_attr "length" "4")
(set_attr "cc" "set_n")])
;; swap swap swap swap swap swap swap swap swap swap swap swap swap swap swap
;; swap
(define_expand "rotlqi3"
[(set (match_operand:QI 0 "register_operand" "")
(rotate:QI (match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
"
{
if (!CONST_INT_P (operands[2]) || (INTVAL (operands[2]) != 4))
FAIL;
}")
(define_insn "rotlqi3_4"
[(set (match_operand:QI 0 "register_operand" "=r")
(rotate:QI (match_operand:QI 1 "register_operand" "0")
(const_int 4)))]
""
"swap %0"
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; Split all rotates of HI,SI and DImode registers where rotation is by
;; a whole number of bytes. The split creates the appropriate moves and
;; considers all overlap situations. DImode is split before reload.
;; HImode does not need scratch. Use attribute for this constraint.
;; Use QI scratch for DI mode as this is often split into byte sized operands.
(define_mode_attr rotx [(DI "&r,&r,X") (SI "&r,&r,X") (HI "X,X,X")])
(define_mode_attr rotsmode [(DI "QI") (SI "HI") (HI "QI")])
(define_expand "rotl3"
[(parallel [(set (match_operand:HIDI 0 "register_operand" "")
(rotate:HIDI (match_operand:HIDI 1 "register_operand" "")
(match_operand:VOID 2 "const_int_operand" "")))
(clobber (match_dup 3))])]
""
{
if (CONST_INT_P (operands[2])
&& 0 == INTVAL (operands[2]) % 8)
{
if (AVR_HAVE_MOVW && 0 == INTVAL (operands[2]) % 16)
operands[3] = gen_rtx_SCRATCH (mode);
else
operands[3] = gen_rtx_SCRATCH (QImode);
}
else
FAIL;
})
;; Overlapping non-HImode registers often (but not always) need a scratch.
;; The best we can do is use early clobber alternative "#&r" so that
;; completely non-overlapping operands dont get a scratch but # so register
;; allocation does not prefer non-overlapping.
; Split word aligned rotates using scratch that is mode dependent.
(define_insn_and_split "*rotw"
[(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r")
(rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r")
(match_operand 2 "const_int_operand" "n,n,n")))
(clobber (match_scratch: 3 "="))]
"AVR_HAVE_MOVW
&& CONST_INT_P (operands[2])
&& 0 == INTVAL (operands[2]) % 16"
"#"
"&& (reload_completed || mode == DImode)"
[(const_int 0)]
{
avr_rotate_bytes (operands);
DONE;
})
; Split byte aligned rotates using scratch that is always QI mode.
(define_insn_and_split "*rotb"
[(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r")
(rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r")
(match_operand 2 "const_int_operand" "n,n,n")))
(clobber (match_scratch:QI 3 "="))]
"CONST_INT_P (operands[2])
&& (8 == INTVAL (operands[2]) % 16
|| (!AVR_HAVE_MOVW
&& 0 == INTVAL (operands[2]) % 16))"
"#"
"&& (reload_completed || mode == DImode)"
[(const_int 0)]
{
avr_rotate_bytes (operands);
DONE;
})
;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
;; arithmetic shift left
(define_expand "ashlqi3"
[(set (match_operand:QI 0 "register_operand" "")
(ashift:QI (match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "general_operand" "")))]
""
"")
(define_split ; ashlqi3_const4
[(set (match_operand:QI 0 "d_register_operand" "")
(ashift:QI (match_dup 0)
(const_int 4)))]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (and:QI (match_dup 0) (const_int -16)))]
"")
(define_split ; ashlqi3_const5
[(set (match_operand:QI 0 "d_register_operand" "")
(ashift:QI (match_dup 0)
(const_int 5)))]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))
(set (match_dup 0) (and:QI (match_dup 0) (const_int -32)))]
"")
(define_split ; ashlqi3_const6
[(set (match_operand:QI 0 "d_register_operand" "")
(ashift:QI (match_dup 0)
(const_int 6)))]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2)))
(set (match_dup 0) (and:QI (match_dup 0) (const_int -64)))]
"")
(define_insn "*ashlqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r")
(ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,K,n,n,Qm")))]
""
"* return ashlqi3_out (insn, operands, NULL);"
[(set_attr "length" "5,0,1,2,4,6,9")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")])
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashift:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
""
"* return ashlhi3_out (insn, operands, NULL);"
[(set_attr "length" "6,0,2,2,4,10,10")
(set_attr "cc" "clobber,none,set_n,clobber,set_n,clobber,clobber")])
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
""
"* return ashlsi3_out (insn, operands, NULL);"
[(set_attr "length" "8,0,4,4,8,10,12")
(set_attr "cc" "clobber,none,set_n,clobber,set_n,clobber,clobber")])
;; Optimize if a scratch register from LD_REGS happens to be available.
(define_peephole2 ; ashlqi3_l_const4
[(set (match_operand:QI 0 "l_register_operand" "")
(ashift:QI (match_dup 0)
(const_int 4)))
(match_scratch:QI 1 "d")]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 1) (const_int -16))
(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
"")
(define_peephole2 ; ashlqi3_l_const5
[(set (match_operand:QI 0 "l_register_operand" "")
(ashift:QI (match_dup 0)
(const_int 5)))
(match_scratch:QI 1 "d")]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))
(set (match_dup 1) (const_int -32))
(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
"")
(define_peephole2 ; ashlqi3_l_const6
[(set (match_operand:QI 0 "l_register_operand" "")
(ashift:QI (match_dup 0)
(const_int 6)))
(match_scratch:QI 1 "d")]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2)))
(set (match_dup 1) (const_int -64))
(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
"")
(define_peephole2
[(match_scratch:QI 3 "d")
(set (match_operand:HI 0 "register_operand" "")
(ashift:HI (match_operand:HI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
[(parallel [(set (match_dup 0) (ashift:HI (match_dup 1) (match_dup 2)))
(clobber (match_dup 3))])]
"")
(define_insn "*ashlhi3_const"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
(ashift:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0")
(match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
(clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
"reload_completed"
"* return ashlhi3_out (insn, operands, NULL);"
[(set_attr "length" "0,2,2,4,10")
(set_attr "cc" "none,set_n,clobber,set_n,clobber")])
(define_peephole2
[(match_scratch:QI 3 "d")
(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:SI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
[(parallel [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
(clobber (match_dup 3))])]
"")
(define_insn "*ashlsi3_const"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(ashift:SI (match_operand:SI 1 "register_operand" "0,0,r,0")
(match_operand:QI 2 "const_int_operand" "L,P,O,n")))
(clobber (match_scratch:QI 3 "=X,X,X,&d"))]
"reload_completed"
"* return ashlsi3_out (insn, operands, NULL);"
[(set_attr "length" "0,4,4,10")
(set_attr "cc" "none,set_n,clobber,clobber")])
;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
;; arithmetic shift right
(define_insn "ashrqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
(ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,K,n,Qm")))]
""
"* return ashrqi3_out (insn, operands, NULL);"
[(set_attr "length" "5,0,1,2,5,9")
(set_attr "cc" "clobber,none,clobber,clobber,clobber,clobber")])
(define_insn "ashrhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
""
"* return ashrhi3_out (insn, operands, NULL);"
[(set_attr "length" "6,0,2,4,4,10,10")
(set_attr "cc" "clobber,none,clobber,set_n,clobber,clobber,clobber")])
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
""
"* return ashrsi3_out (insn, operands, NULL);"
[(set_attr "length" "8,0,4,6,8,10,12")
(set_attr "cc" "clobber,none,clobber,set_n,clobber,clobber,clobber")])
;; Optimize if a scratch register from LD_REGS happens to be available.
(define_peephole2
[(match_scratch:QI 3 "d")
(set (match_operand:HI 0 "register_operand" "")
(ashiftrt:HI (match_operand:HI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
[(parallel [(set (match_dup 0) (ashiftrt:HI (match_dup 1) (match_dup 2)))
(clobber (match_dup 3))])]
"")
(define_insn "*ashrhi3_const"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
(ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0")
(match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
(clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
"reload_completed"
"* return ashrhi3_out (insn, operands, NULL);"
[(set_attr "length" "0,2,4,4,10")
(set_attr "cc" "none,clobber,set_n,clobber,clobber")])
(define_peephole2
[(match_scratch:QI 3 "d")
(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
[(parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 1) (match_dup 2)))
(clobber (match_dup 3))])]
"")
(define_insn "*ashrsi3_const"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0")
(match_operand:QI 2 "const_int_operand" "L,P,O,n")))
(clobber (match_scratch:QI 3 "=X,X,X,&d"))]
"reload_completed"
"* return ashrsi3_out (insn, operands, NULL);"
[(set_attr "length" "0,4,4,10")
(set_attr "cc" "none,clobber,set_n,clobber")])
;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
;; logical shift right
(define_expand "lshrqi3"
[(set (match_operand:QI 0 "register_operand" "")
(lshiftrt:QI (match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "general_operand" "")))]
""
"")
(define_split ; lshrqi3_const4
[(set (match_operand:QI 0 "d_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 4)))]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (and:QI (match_dup 0) (const_int 15)))]
"")
(define_split ; lshrqi3_const5
[(set (match_operand:QI 0 "d_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 5)))]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1)))
(set (match_dup 0) (and:QI (match_dup 0) (const_int 7)))]
"")
(define_split ; lshrqi3_const6
[(set (match_operand:QI 0 "d_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 6)))]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2)))
(set (match_dup 0) (and:QI (match_dup 0) (const_int 3)))]
"")
(define_insn "*lshrqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r")
(lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,K,n,n,Qm")))]
""
"* return lshrqi3_out (insn, operands, NULL);"
[(set_attr "length" "5,0,1,2,4,6,9")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")])
(define_insn "lshrhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
""
"* return lshrhi3_out (insn, operands, NULL);"
[(set_attr "length" "6,0,2,2,4,10,10")
(set_attr "cc" "clobber,none,clobber,clobber,clobber,clobber,clobber")])
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
""
"* return lshrsi3_out (insn, operands, NULL);"
[(set_attr "length" "8,0,4,4,8,10,12")
(set_attr "cc" "clobber,none,clobber,clobber,clobber,clobber,clobber")])
;; Optimize if a scratch register from LD_REGS happens to be available.
(define_peephole2 ; lshrqi3_l_const4
[(set (match_operand:QI 0 "l_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 4)))
(match_scratch:QI 1 "d")]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 1) (const_int 15))
(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
"")
(define_peephole2 ; lshrqi3_l_const5
[(set (match_operand:QI 0 "l_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 5)))
(match_scratch:QI 1 "d")]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1)))
(set (match_dup 1) (const_int 7))
(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
"")
(define_peephole2 ; lshrqi3_l_const6
[(set (match_operand:QI 0 "l_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 6)))
(match_scratch:QI 1 "d")]
""
[(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
(set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2)))
(set (match_dup 1) (const_int 3))
(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
"")
(define_peephole2
[(match_scratch:QI 3 "d")
(set (match_operand:HI 0 "register_operand" "")
(lshiftrt:HI (match_operand:HI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
[(parallel [(set (match_dup 0) (lshiftrt:HI (match_dup 1) (match_dup 2)))
(clobber (match_dup 3))])]
"")
(define_insn "*lshrhi3_const"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
(lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0")
(match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
(clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
"reload_completed"
"* return lshrhi3_out (insn, operands, NULL);"
[(set_attr "length" "0,2,2,4,10")
(set_attr "cc" "none,clobber,clobber,clobber,clobber")])
(define_peephole2
[(match_scratch:QI 3 "d")
(set (match_operand:SI 0 "register_operand" "")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "")
(match_operand:QI 2 "const_int_operand" "")))]
""
[(parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 1) (match_dup 2)))
(clobber (match_dup 3))])]
"")
(define_insn "*lshrsi3_const"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0")
(match_operand:QI 2 "const_int_operand" "L,P,O,n")))
(clobber (match_scratch:QI 3 "=X,X,X,&d"))]
"reload_completed"
"* return lshrsi3_out (insn, operands, NULL);"
[(set_attr "length" "0,4,4,10")
(set_attr "cc" "none,clobber,clobber,clobber")])
;; abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x)
;; abs
(define_insn "absqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(abs:QI (match_operand:QI 1 "register_operand" "0")))]
""
"sbrc %0,7
neg %0"
[(set_attr "length" "2")
(set_attr "cc" "clobber")])
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=d,r")
(abs:SF (match_operand:SF 1 "register_operand" "0,0")))]
""
"@
andi %D0,0x7f
clt\;bld %D0,7"
[(set_attr "length" "1,2")
(set_attr "cc" "set_n,clobber")])
;; 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x
;; neg
(define_insn "negqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(neg:QI (match_operand:QI 1 "register_operand" "0")))]
""
"neg %0"
[(set_attr "length" "1")
(set_attr "cc" "set_zn")])
(define_insn "neghi2"
[(set (match_operand:HI 0 "register_operand" "=!d,r,&r")
(neg:HI (match_operand:HI 1 "register_operand" "0,0,r")))]
""
"@
com %B0\;neg %A0\;sbci %B0,lo8(-1)
com %B0\;neg %A0\;sbc %B0,__zero_reg__\;inc %B0
clr %A0\;clr %B0\;sub %A0,%A1\;sbc %B0,%B1"
[(set_attr "length" "3,4,4")
(set_attr "cc" "set_czn,set_n,set_czn")])
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=!d,r,&r")
(neg:SI (match_operand:SI 1 "register_operand" "0,0,r")))]
""
"@
com %D0\;com %C0\;com %B0\;neg %A0\;sbci %B0,lo8(-1)\;sbci %C0,lo8(-1)\;sbci %D0,lo8(-1)
com %D0\;com %C0\;com %B0\;com %A0\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
clr %A0\;clr %B0\;{clr %C0\;clr %D0|movw %C0,%A0}\;sub %A0,%A1\;sbc %B0,%B1\;sbc %C0,%C1\;sbc %D0,%D1"
[(set_attr_alternative "length"
[(const_int 7)
(const_int 8)
(if_then_else (eq_attr "mcu_have_movw" "yes")
(const_int 7)
(const_int 8))])
(set_attr "cc" "set_czn,set_n,set_czn")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=d,r")
(neg:SF (match_operand:SF 1 "register_operand" "0,0")))]
""
"@
subi %D0,0x80
bst %D0,7\;com %D0\;bld %D0,7\;com %D0"
[(set_attr "length" "1,4")
(set_attr "cc" "set_n,set_n")])
;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;; not
(define_insn "one_cmplqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(not:QI (match_operand:QI 1 "register_operand" "0")))]
""
"com %0"
[(set_attr "length" "1")
(set_attr "cc" "set_czn")])
(define_insn "one_cmplhi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(not:HI (match_operand:HI 1 "register_operand" "0")))]
""
"com %0
com %B0"
[(set_attr "length" "2")
(set_attr "cc" "set_n")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "0")))]
""
"com %0
com %B0
com %C0
com %D0"
[(set_attr "length" "4")
(set_attr "cc" "set_n")])
;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
;; sign extend
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r,r")
(sign_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
""
"@
clr %B0\;sbrc %0,7\;com %B0
mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0"
[(set_attr "length" "3,4")
(set_attr "cc" "set_n,set_n")])
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(sign_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
""
"@
clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0
mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0"
[(set_attr "length" "5,6")
(set_attr "cc" "set_n,set_n")])
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,&r")
(sign_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
""
"@
clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0
{mov %A0,%A1\;mov %B0,%B1|movw %A0,%A1}\;clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0"
[(set_attr_alternative "length"
[(const_int 4)
(if_then_else (eq_attr "mcu_have_movw" "yes")
(const_int 5)
(const_int 6))])
(set_attr "cc" "set_n,set_n")])
;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
;; zero extend
(define_insn_and_split "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 3) (const_int 0))]
{
unsigned int low_off = subreg_lowpart_offset (QImode, HImode);
unsigned int high_off = subreg_highpart_offset (QImode, HImode);
operands[2] = simplify_gen_subreg (QImode, operands[0], HImode, low_off);
operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, high_off);
})
(define_insn_and_split "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 2) (zero_extend:HI (match_dup 1)))
(set (match_dup 3) (const_int 0))]
{
unsigned int low_off = subreg_lowpart_offset (HImode, SImode);
unsigned int high_off = subreg_highpart_offset (HImode, SImode);
operands[2] = simplify_gen_subreg (HImode, operands[0], SImode, low_off);
operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, high_off);
})
(define_insn_and_split "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "register_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 3) (const_int 0))]
{
unsigned int low_off = subreg_lowpart_offset (HImode, SImode);
unsigned int high_off = subreg_highpart_offset (HImode, SImode);
operands[2] = simplify_gen_subreg (HImode, operands[0], SImode, low_off);
operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, high_off);
})
(define_insn_and_split "zero_extendqidi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:QI 1 "register_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 2) (zero_extend:SI (match_dup 1)))
(set (match_dup 3) (const_int 0))]
{
unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
unsigned int high_off = subreg_highpart_offset (SImode, DImode);
operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
})
(define_insn_and_split "zero_extendhidi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:HI 1 "register_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 2) (zero_extend:SI (match_dup 1)))
(set (match_dup 3) (const_int 0))]
{
unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
unsigned int high_off = subreg_highpart_offset (SImode, DImode);
operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
})
(define_insn_and_split "zero_extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 3) (const_int 0))]
{
unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
unsigned int high_off = subreg_highpart_offset (SImode, DImode);
operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
})
;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
;; compare
; Optimize negated tests into reverse compare if overflow is undefined.
(define_insn "*negated_tstqi"
[(set (cc0)
(compare (neg:QI (match_operand:QI 0 "register_operand" "r"))
(const_int 0)))]
"(!flag_wrapv && !flag_trapv && flag_strict_overflow)"
"cp __zero_reg__,%0"
[(set_attr "cc" "compare")
(set_attr "length" "1")])
(define_insn "*reversed_tstqi"
[(set (cc0)
(compare (const_int 0)
(match_operand:QI 0 "register_operand" "r")))]
""
"cp __zero_reg__,%0"
[(set_attr "cc" "compare")
(set_attr "length" "2")])
(define_insn "*negated_tsthi"
[(set (cc0)
(compare (neg:HI (match_operand:HI 0 "register_operand" "r"))
(const_int 0)))]
"(!flag_wrapv && !flag_trapv && flag_strict_overflow)"
"cp __zero_reg__,%A0
cpc __zero_reg__,%B0"
[(set_attr "cc" "compare")
(set_attr "length" "2")])
;; Leave here the clobber used by the cmphi pattern for simplicity, even
;; though it is unused, because this pattern is synthesized by avr_reorg.
(define_insn "*reversed_tsthi"
[(set (cc0)
(compare (const_int 0)
(match_operand:HI 0 "register_operand" "r")))
(clobber (match_scratch:QI 1 "=X"))]
""
"cp __zero_reg__,%A0
cpc __zero_reg__,%B0"
[(set_attr "cc" "compare")
(set_attr "length" "2")])
(define_insn "*negated_tstsi"
[(set (cc0)
(compare (neg:SI (match_operand:SI 0 "register_operand" "r"))
(const_int 0)))]
"(!flag_wrapv && !flag_trapv && flag_strict_overflow)"
"cp __zero_reg__,%A0
cpc __zero_reg__,%B0
cpc __zero_reg__,%C0
cpc __zero_reg__,%D0"
[(set_attr "cc" "compare")
(set_attr "length" "4")])
(define_insn "*reversed_tstsi"
[(set (cc0)
(compare (const_int 0)
(match_operand:SI 0 "register_operand" "r")))
(clobber (match_scratch:QI 1 "=X"))]
""
"cp __zero_reg__,%A0
cpc __zero_reg__,%B0
cpc __zero_reg__,%C0
cpc __zero_reg__,%D0"
[(set_attr "cc" "compare")
(set_attr "length" "4")])
(define_insn "*cmpqi"
[(set (cc0)
(compare (match_operand:QI 0 "register_operand" "r,r,d")
(match_operand:QI 1 "nonmemory_operand" "L,r,i")))]
""
"@
tst %0
cp %0,%1
cpi %0,lo8(%1)"
[(set_attr "cc" "compare,compare,compare")
(set_attr "length" "1,1,1")])
(define_insn "*cmpqi_sign_extend"
[(set (cc0)
(compare (sign_extend:HI
(match_operand:QI 0 "register_operand" "d"))
(match_operand:HI 1 "const_int_operand" "n")))]
"INTVAL (operands[1]) >= -128 && INTVAL (operands[1]) <= 127"
"cpi %0,lo8(%1)"
[(set_attr "cc" "compare")
(set_attr "length" "1")])
(define_insn "*cmphi"
[(set (cc0)
(compare (match_operand:HI 0 "register_operand" "!w,r,r,d,d,r,r")
(match_operand:HI 1 "nonmemory_operand" "L,L,r,M,i,M,i")))
(clobber (match_scratch:QI 2 "=X,X,X,X,&d,&d,&d"))]
""
"*{
switch (which_alternative)
{
case 0: case 1:
return out_tsthi (insn, operands[0], NULL);
case 2:
return (AS2 (cp,%A0,%A1) CR_TAB
AS2 (cpc,%B0,%B1));
case 3:
if (reg_unused_after (insn, operands[0])
&& INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63
&& test_hard_reg_class (ADDW_REGS, operands[0]))
return AS2 (sbiw,%0,%1);
else
return (AS2 (cpi,%0,%1) CR_TAB
AS2 (cpc,%B0,__zero_reg__));
case 4:
if (reg_unused_after (insn, operands[0]))
return (AS2 (subi,%0,lo8(%1)) CR_TAB
AS2 (sbci,%B0,hi8(%1)));
else
return (AS2 (ldi, %2,hi8(%1)) CR_TAB
AS2 (cpi, %A0,lo8(%1)) CR_TAB
AS2 (cpc, %B0,%2));
case 5:
return (AS2 (ldi, %2,lo8(%1)) CR_TAB
AS2 (cp, %A0,%2) CR_TAB
AS2 (cpc, %B0,__zero_reg__));
case 6:
return (AS2 (ldi, %2,lo8(%1)) CR_TAB
AS2 (cp, %A0,%2) CR_TAB
AS2 (ldi, %2,hi8(%1)) CR_TAB
AS2 (cpc, %B0,%2));
}
return \"bug\";
}"
[(set_attr "cc" "compare,compare,compare,compare,compare,compare,compare")
(set_attr "length" "1,2,2,2,3,3,4")])
(define_insn "*cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "register_operand" "r,r,d,d,r,r")
(match_operand:SI 1 "nonmemory_operand" "L,r,M,i,M,i")))
(clobber (match_scratch:QI 2 "=X,X,X,&d,&d,&d"))]
""
"*{
switch (which_alternative)
{
case 0:
return out_tstsi (insn, operands[0], NULL);
case 1:
return (AS2 (cp,%A0,%A1) CR_TAB
AS2 (cpc,%B0,%B1) CR_TAB
AS2 (cpc,%C0,%C1) CR_TAB
AS2 (cpc,%D0,%D1));
case 2:
if (reg_unused_after (insn, operands[0])
&& INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63
&& test_hard_reg_class (ADDW_REGS, operands[0]))
return (AS2 (sbiw,%0,%1) CR_TAB
AS2 (cpc,%C0,__zero_reg__) CR_TAB
AS2 (cpc,%D0,__zero_reg__));
else
return (AS2 (cpi,%A0,lo8(%1)) CR_TAB
AS2 (cpc,%B0,__zero_reg__) CR_TAB
AS2 (cpc,%C0,__zero_reg__) CR_TAB
AS2 (cpc,%D0,__zero_reg__));
case 3:
if (reg_unused_after (insn, operands[0]))
return (AS2 (subi,%A0,lo8(%1)) CR_TAB
AS2 (sbci,%B0,hi8(%1)) CR_TAB
AS2 (sbci,%C0,hlo8(%1)) CR_TAB
AS2 (sbci,%D0,hhi8(%1)));
else
return (AS2 (cpi, %A0,lo8(%1)) CR_TAB
AS2 (ldi, %2,hi8(%1)) CR_TAB
AS2 (cpc, %B0,%2) CR_TAB
AS2 (ldi, %2,hlo8(%1)) CR_TAB
AS2 (cpc, %C0,%2) CR_TAB
AS2 (ldi, %2,hhi8(%1)) CR_TAB
AS2 (cpc, %D0,%2));
case 4:
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
AS2 (cp,%A0,%2) CR_TAB
AS2 (cpc,%B0,__zero_reg__) CR_TAB
AS2 (cpc,%C0,__zero_reg__) CR_TAB
AS2 (cpc,%D0,__zero_reg__));
case 5:
return (AS2 (ldi, %2,lo8(%1)) CR_TAB
AS2 (cp, %A0,%2) CR_TAB
AS2 (ldi, %2,hi8(%1)) CR_TAB
AS2 (cpc, %B0,%2) CR_TAB
AS2 (ldi, %2,hlo8(%1)) CR_TAB
AS2 (cpc, %C0,%2) CR_TAB
AS2 (ldi, %2,hhi8(%1)) CR_TAB
AS2 (cpc, %D0,%2));
}
return \"bug\";
}"
[(set_attr "cc" "compare,compare,compare,compare,compare,compare")
(set_attr "length" "4,4,4,7,5,8")])
;; ----------------------------------------------------------------------
;; JUMP INSTRUCTIONS
;; ----------------------------------------------------------------------
;; Conditional jump instructions
(define_expand "cbranchsi4"
[(parallel [(set (cc0)
(compare (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))
(clobber (match_scratch:QI 4 ""))])
(set (pc)
(if_then_else
(match_operator 0 "ordered_comparison_operator" [(cc0)
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"")
(define_expand "cbranchhi4"
[(parallel [(set (cc0)
(compare (match_operand:HI 1 "register_operand" "")
(match_operand:HI 2 "nonmemory_operand" "")))
(clobber (match_scratch:QI 4 ""))])
(set (pc)
(if_then_else
(match_operator 0 "ordered_comparison_operator" [(cc0)
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"")
(define_expand "cbranchqi4"
[(set (cc0)
(compare (match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "nonmemory_operand" "")))
(set (pc)
(if_then_else
(match_operator 0 "ordered_comparison_operator" [(cc0)
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"")
;; Test a single bit in a QI/HI/SImode register.
;; Combine will create zero extract patterns for single bit tests.
;; permit any mode in source pattern by using VOIDmode.
(define_insn "*sbrx_branch"
[(set (pc)
(if_then_else
(match_operator 0 "eqne_operator"
[(zero_extract:QIDI
(match_operand:VOID 1 "register_operand" "r")
(const_int 1)
(match_operand 2 "const_int_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
"* return avr_out_sbxx_branch (insn, operands);"
[(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")])
;; Same test based on Bitwise AND RTL. Keep this incase gcc changes patterns.
;; or for old peepholes.
;; Fixme - bitwise Mask will not work for DImode
(define_insn "*sbrx_and_branch"
[(set (pc)
(if_then_else
(match_operator 0 "eqne_operator"
[(and:QISI
(match_operand:QISI 1 "register_operand" "r")
(match_operand:QISI 2 "single_one_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
{
HOST_WIDE_INT bitnumber;
bitnumber = exact_log2 (GET_MODE_MASK (mode) & INTVAL (operands[2]));
operands[2] = GEN_INT (bitnumber);
return avr_out_sbxx_branch (insn, operands);
}
[(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")])
;; Convert sign tests to bit 7/15/31 tests that match the above insns.
(define_peephole2
[(set (cc0) (compare (match_operand:QI 0 "register_operand" "")
(const_int 0)))
(set (pc) (if_then_else (ge (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
[(set (pc) (if_then_else (eq (zero_extract:HI (match_dup 0)
(const_int 1)
(const_int 7))
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"")
(define_peephole2
[(set (cc0) (compare (match_operand:QI 0 "register_operand" "")
(const_int 0)))
(set (pc) (if_then_else (lt (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
[(set (pc) (if_then_else (ne (zero_extract:HI (match_dup 0)
(const_int 1)
(const_int 7))
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"")
(define_peephole2
[(parallel [(set (cc0) (compare (match_operand:HI 0 "register_operand" "")
(const_int 0)))
(clobber (match_operand:HI 2 ""))])
(set (pc) (if_then_else (ge (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
[(set (pc) (if_then_else (eq (and:HI (match_dup 0) (const_int -32768))
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"")
(define_peephole2
[(parallel [(set (cc0) (compare (match_operand:HI 0 "register_operand" "")
(const_int 0)))
(clobber (match_operand:HI 2 ""))])
(set (pc) (if_then_else (lt (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
[(set (pc) (if_then_else (ne (and:HI (match_dup 0) (const_int -32768))
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"")
(define_peephole2
[(parallel [(set (cc0) (compare (match_operand:SI 0 "register_operand" "")
(const_int 0)))
(clobber (match_operand:SI 2 ""))])
(set (pc) (if_then_else (ge (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
[(set (pc) (if_then_else (eq (and:SI (match_dup 0) (match_dup 2))
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"operands[2] = GEN_INT (-2147483647 - 1);")
(define_peephole2
[(parallel [(set (cc0) (compare (match_operand:SI 0 "register_operand" "")
(const_int 0)))
(clobber (match_operand:SI 2 ""))])
(set (pc) (if_then_else (lt (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
[(set (pc) (if_then_else (ne (and:SI (match_dup 0) (match_dup 2))
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"operands[2] = GEN_INT (-2147483647 - 1);")
;; ************************************************************************
;; Implementation of conditional jumps here.
;; Compare with 0 (test) jumps
;; ************************************************************************
(define_insn "branch"
[(set (pc)
(if_then_else (match_operator 1 "simple_comparison_operator"
[(cc0)
(const_int 0)])
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return ret_cond_branch (operands[1], avr_jump_mode (operands[0],insn), 0);"
[(set_attr "type" "branch")
(set_attr "cc" "clobber")])
;; ****************************************************************
;; AVR does not have following conditional jumps: LE,LEU,GT,GTU.
;; Convert them all to proper jumps.
;; ****************************************************************/
(define_insn "difficult_branch"
[(set (pc)
(if_then_else (match_operator 1 "difficult_comparison_operator"
[(cc0)
(const_int 0)])
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return ret_cond_branch (operands[1], avr_jump_mode (operands[0],insn), 0);"
[(set_attr "type" "branch1")
(set_attr "cc" "clobber")])
;; revers branch
(define_insn "rvbranch"
[(set (pc)
(if_then_else (match_operator 1 "simple_comparison_operator"
[(cc0)
(const_int 0)])
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), 1);"
[(set_attr "type" "branch1")
(set_attr "cc" "clobber")])
(define_insn "difficult_rvbranch"
[(set (pc)
(if_then_else (match_operator 1 "difficult_comparison_operator"
[(cc0)
(const_int 0)])
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), 1);"
[(set_attr "type" "branch")
(set_attr "cc" "clobber")])
;; **************************************************************************
;; Unconditional and other jump instructions.
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"*{
if (AVR_HAVE_JMP_CALL && get_attr_length (insn) != 1)
return AS1 (jmp,%x0);
return AS1 (rjmp,%x0);
}"
[(set (attr "length")
(if_then_else (match_operand 0 "symbol_ref_operand" "")
(if_then_else (eq_attr "mcu_mega" "no")
(const_int 1)
(const_int 2))
(if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2047))
(le (minus (pc) (match_dup 0)) (const_int 2047)))
(const_int 1)
(const_int 2))))
(set_attr "cc" "none")])
;; call
(define_expand "call"
[(parallel[(call (match_operand:HI 0 "call_insn_operand" "")
(match_operand:HI 1 "general_operand" ""))
(use (const_int 0))])]
;; Operand 1 not used on the AVR.
;; Operand 2 is 1 for tail-call, 0 otherwise.
""
"")
(define_expand "sibcall"
[(parallel[(call (match_operand:HI 0 "call_insn_operand" "")
(match_operand:HI 1 "general_operand" ""))
(use (const_int 1))])]
;; Operand 1 not used on the AVR.
;; Operand 2 is 1 for tail-call, 0 otherwise.
""
"")
;; call value
(define_expand "call_value"
[(parallel[(set (match_operand 0 "register_operand" "")
(call (match_operand:HI 1 "call_insn_operand" "")
(match_operand:HI 2 "general_operand" "")))
(use (const_int 0))])]
;; Operand 2 not used on the AVR.
;; Operand 3 is 1 for tail-call, 0 otherwise.
""
"")
(define_expand "sibcall_value"
[(parallel[(set (match_operand 0 "register_operand" "")
(call (match_operand:HI 1 "call_insn_operand" "")
(match_operand:HI 2 "general_operand" "")))
(use (const_int 1))])]
;; Operand 2 not used on the AVR.
;; Operand 3 is 1 for tail-call, 0 otherwise.
""
"")
(define_insn "*call_insn"
[(parallel[(call (mem:HI (match_operand:HI 0 "nonmemory_operand" "z,s,z,s"))
(match_operand:HI 1 "general_operand" "X,X,X,X"))
(use (match_operand:HI 2 "const_int_operand" "L,L,P,P"))])]
;; Operand 1 not used on the AVR.
;; Operand 2 is 1 for tail-call, 0 otherwise.
""
"@
%!icall
%~call %x0
%!ijmp
%~jmp %x0"
[(set_attr "cc" "clobber")
(set_attr_alternative "length"
[(const_int 1)
(if_then_else (eq_attr "mcu_mega" "yes")
(const_int 2)
(const_int 1))
(const_int 1)
(if_then_else (eq_attr "mcu_mega" "yes")
(const_int 2)
(const_int 1))])])
(define_insn "*call_value_insn"
[(parallel[(set (match_operand 0 "register_operand" "=r,r,r,r")
(call (mem:HI (match_operand:HI 1 "nonmemory_operand" "z,s,z,s"))
(match_operand:HI 2 "general_operand" "X,X,X,X")))
(use (match_operand:HI 3 "const_int_operand" "L,L,P,P"))])]
;; Operand 2 not used on the AVR.
;; Operand 3 is 1 for tail-call, 0 otherwise.
""
"@
%!icall
%~call %x1
%!ijmp
%~jmp %x1"
[(set_attr "cc" "clobber")
(set_attr_alternative "length"
[(const_int 1)
(if_then_else (eq_attr "mcu_mega" "yes")
(const_int 2)
(const_int 1))
(const_int 1)
(if_then_else (eq_attr "mcu_mega" "yes")
(const_int 2)
(const_int 1))])])
(define_insn "nop"
[(const_int 0)]
""
"nop"
[(set_attr "cc" "none")
(set_attr "length" "1")])
; indirect jump
(define_expand "indirect_jump"
[(set (pc) (match_operand:HI 0 "nonmemory_operand" ""))]
""
" if ((!AVR_HAVE_JMP_CALL) && !register_operand(operand0, HImode))
{
operands[0] = copy_to_mode_reg(HImode, operand0);
}"
)
; indirect jump
(define_insn "*jcindirect_jump"
[(set (pc) (match_operand:HI 0 "immediate_operand" "i"))]
""
"%~jmp %x0"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;;
(define_insn "*njcindirect_jump"
[(set (pc) (match_operand:HI 0 "register_operand" "!z,*r"))]
"!AVR_HAVE_EIJMP_EICALL"
"@
ijmp
push %A0\;push %B0\;ret"
[(set_attr "length" "1,3")
(set_attr "cc" "none,none")])
(define_insn "*indirect_jump_avr6"
[(set (pc) (match_operand:HI 0 "register_operand" "z"))]
"AVR_HAVE_EIJMP_EICALL"
"eijmp"
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; table jump
;; Table made from "rjmp" instructions for <=8K devices.
(define_insn "*tablejump_rjmp"
[(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")]
UNSPEC_INDEX_JMP))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"(!AVR_HAVE_JMP_CALL) && (!AVR_HAVE_EIJMP_EICALL)"
"@
ijmp
push %A0\;push %B0\;ret"
[(set_attr "length" "1,3")
(set_attr "cc" "none,none")])
;; Not a prologue, but similar idea - move the common piece of code to libgcc.
(define_insn "*tablejump_lib"
[(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")]
UNSPEC_INDEX_JMP))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"AVR_HAVE_JMP_CALL && TARGET_CALL_PROLOGUES"
"%~jmp __tablejump2__"
[(set_attr "length" "2")
(set_attr "cc" "clobber")])
(define_insn "*tablejump_enh"
[(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")]
UNSPEC_INDEX_JMP))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"AVR_HAVE_JMP_CALL && AVR_HAVE_LPMX"
"lsl r30
rol r31
lpm __tmp_reg__,Z+
lpm r31,Z
mov r30,__tmp_reg__
%!ijmp"
[(set_attr "length" "6")
(set_attr "cc" "clobber")])
(define_insn "*tablejump"
[(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")]
UNSPEC_INDEX_JMP))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"AVR_HAVE_JMP_CALL && !AVR_HAVE_EIJMP_EICALL"
"lsl r30
rol r31
lpm
inc r30
push r0
lpm
push r0
ret"
[(set_attr "length" "8")
(set_attr "cc" "clobber")])
(define_expand "casesi"
[(set (match_dup 6)
(minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0)
(match_operand:HI 1 "register_operand" "")))
(parallel [(set (cc0)
(compare (match_dup 6)
(match_operand:HI 2 "register_operand" "")))
(clobber (match_scratch:QI 9 ""))])
(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_dup 6)
(plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
(parallel [(set (pc) (unspec:HI [(match_dup 6)] UNSPEC_INDEX_JMP))
(use (label_ref (match_dup 3)))
(clobber (match_dup 6))])]
""
"
{
operands[6] = gen_reg_rtx (HImode);
}")
;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; This instruction sets Z flag
(define_insn "sez"
[(set (cc0) (const_int 0))]
""
"sez"
[(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 "low_io_address_operand" "n"))
(and:QI (mem:QI (match_dup 0))
(match_operand:QI 1 "single_zero_operand" "n")))]
"(optimize > 0)"
{
operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
return AS2 (cbi,%m0-0x20,%2);
}
[(set_attr "length" "1")
(set_attr "cc" "none")])
(define_insn "*sbi"
[(set (mem:QI (match_operand 0 "low_io_address_operand" "n"))
(ior:QI (mem:QI (match_dup 0))
(match_operand:QI 1 "single_one_operand" "n")))]
"(optimize > 0)"
{
operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
return AS2 (sbi,%m0-0x20,%2);
}
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; Lower half of the I/O space - use sbic/sbis directly.
(define_insn "*sbix_branch"
[(set (pc)
(if_then_else
(match_operator 0 "eqne_operator"
[(zero_extract:HI
(mem:QI (match_operand 1 "low_io_address_operand" "n"))
(const_int 1)
(match_operand 2 "const_int_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"(optimize > 0)"
"* return avr_out_sbxx_branch (insn, operands);"
[(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 "gelt_operator"
[(mem:QI (match_operand 1 "low_io_address_operand" "n"))
(const_int 0)])
(label_ref (match_operand 2 "" ""))
(pc)))]
"(optimize > 0)"
{
operands[3] = operands[2];
operands[2] = GEN_INT (7);
return avr_out_sbxx_branch (insn, operands);
}
[(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")])
;; Upper half of the I/O space - read port to __tmp_reg__ and use sbrc/sbrs.
(define_insn "*sbix_branch_tmp"
[(set (pc)
(if_then_else
(match_operator 0 "eqne_operator"
[(zero_extract:HI
(mem:QI (match_operand 1 "high_io_address_operand" "n"))
(const_int 1)
(match_operand 2 "const_int_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"(optimize > 0)"
"* return avr_out_sbxx_branch (insn, operands);"
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
(le (minus (pc) (match_dup 3)) (const_int 2045)))
(const_int 3)
(if_then_else (eq_attr "mcu_mega" "no")
(const_int 3)
(const_int 5))))
(set_attr "cc" "clobber")])
(define_insn "*sbix_branch_tmp_bit7"
[(set (pc)
(if_then_else
(match_operator 0 "gelt_operator"
[(mem:QI (match_operand 1 "high_io_address_operand" "n"))
(const_int 0)])
(label_ref (match_operand 2 "" ""))
(pc)))]
"(optimize > 0)"
{
operands[3] = operands[2];
operands[2] = GEN_INT (7);
return avr_out_sbxx_branch (insn, operands);
}
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 2)) (const_int -2046))
(le (minus (pc) (match_dup 2)) (const_int 2045)))
(const_int 3)
(if_then_else (eq_attr "mcu_mega" "no")
(const_int 3)
(const_int 5))))
(set_attr "cc" "clobber")])
;; ************************* Peepholes ********************************
(define_peephole
[(set (match_operand:SI 0 "d_register_operand" "")
(plus:SI (match_dup 0)
(const_int -1)))
(parallel
[(set (cc0)
(compare (match_dup 0)
(const_int -1)))
(clobber (match_operand:QI 1 "d_register_operand" ""))])
(set (pc)
(if_then_else (ne (cc0) (const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"*
{
CC_STATUS_INIT;
if (test_hard_reg_class (ADDW_REGS, operands[0]))
output_asm_insn (AS2 (sbiw,%0,1) CR_TAB
AS2 (sbc,%C0,__zero_reg__) CR_TAB
AS2 (sbc,%D0,__zero_reg__) \"\\n\", operands);
else
output_asm_insn (AS2 (subi,%A0,1) CR_TAB
AS2 (sbc,%B0,__zero_reg__) CR_TAB
AS2 (sbc,%C0,__zero_reg__) CR_TAB
AS2 (sbc,%D0,__zero_reg__) \"\\n\", operands);
switch (avr_jump_mode (operands[2],insn))
{
case 1:
return AS1 (brcc,%2);
case 2:
return (AS1 (brcs,.+2) CR_TAB
AS1 (rjmp,%2));
}
return (AS1 (brcs,.+4) CR_TAB
AS1 (jmp,%2));
}")
(define_peephole
[(set (match_operand:HI 0 "d_register_operand" "")
(plus:HI (match_dup 0)
(const_int -1)))
(parallel
[(set (cc0)
(compare (match_dup 0)
(const_int 65535)))
(clobber (match_operand:QI 1 "d_register_operand" ""))])
(set (pc)
(if_then_else (ne (cc0) (const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"*
{
CC_STATUS_INIT;
if (test_hard_reg_class (ADDW_REGS, operands[0]))
output_asm_insn (AS2 (sbiw,%0,1), operands);
else
output_asm_insn (AS2 (subi,%A0,1) CR_TAB
AS2 (sbc,%B0,__zero_reg__) \"\\n\", operands);
switch (avr_jump_mode (operands[2],insn))
{
case 1:
return AS1 (brcc,%2);
case 2:
return (AS1 (brcs,.+2) CR_TAB
AS1 (rjmp,%2));
}
return (AS1 (brcs,.+4) CR_TAB
AS1 (jmp,%2));
}")
(define_peephole
[(set (match_operand:QI 0 "d_register_operand" "")
(plus:QI (match_dup 0)
(const_int -1)))
(set (cc0)
(compare (match_dup 0)
(const_int -1)))
(set (pc)
(if_then_else (ne (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
""
"*
{
CC_STATUS_INIT;
cc_status.value1 = operands[0];
cc_status.flags |= CC_OVERFLOW_UNUSABLE;
output_asm_insn (AS2 (subi,%A0,1), operands);
switch (avr_jump_mode (operands[1],insn))
{
case 1:
return AS1 (brcc,%1);
case 2:
return (AS1 (brcs,.+2) CR_TAB
AS1 (rjmp,%1));
}
return (AS1 (brcs,.+4) CR_TAB
AS1 (jmp,%1));
}")
(define_peephole
[(set (cc0)
(compare (match_operand:QI 0 "register_operand" "")
(const_int 0)))
(set (pc)
(if_then_else (eq (cc0) (const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
"jump_over_one_insn_p (insn, operands[1])"
"cpse %0,__zero_reg__")
(define_peephole
[(set (cc0)
(compare (match_operand:QI 0 "register_operand" "")
(match_operand:QI 1 "register_operand" "")))
(set (pc)
(if_then_else (eq (cc0) (const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
"jump_over_one_insn_p (insn, operands[2])"
"cpse %0,%1")
;;pppppppppppppppppppppppppppppppppppppppppppppppppppp
;;prologue/epilogue support instructions
(define_insn "popqi"
[(set (match_operand:QI 0 "register_operand" "=r")
(mem:QI (pre_inc:HI (reg:HI REG_SP))))]
""
"pop %0"
[(set_attr "cc" "none")
(set_attr "length" "1")])
;; Enable Interrupts
(define_insn "enable_interrupt"
[(unspec_volatile [(const_int 1)] UNSPECV_ENABLE_IRQS)]
""
"sei"
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; Disable Interrupts
(define_insn "disable_interrupt"
[(unspec_volatile [(const_int 0)] UNSPECV_ENABLE_IRQS)]
""
"cli"
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; Library prologue saves
(define_insn "call_prologue_saves"
[(unspec_volatile:HI [(const_int 0)] UNSPECV_PROLOGUE_SAVES)
(match_operand:HI 0 "immediate_operand" "")
(set (reg:HI REG_SP) (minus:HI
(reg:HI REG_SP)
(match_operand:HI 1 "immediate_operand" "")))
(use (reg:HI REG_X))
(clobber (reg:HI REG_Z))]
""
"ldi r30,lo8(gs(1f))
ldi r31,hi8(gs(1f))
%~jmp __prologue_saves__+((18 - %0) * 2)
1:"
[(set_attr_alternative "length"
[(if_then_else (eq_attr "mcu_mega" "yes")
(const_int 6)
(const_int 5))])
(set_attr "cc" "clobber")
])
; epilogue restores using library
(define_insn "epilogue_restores"
[(unspec_volatile:QI [(const_int 0)] UNSPECV_EPILOGUE_RESTORES)
(set (reg:HI REG_Y ) (plus:HI
(reg:HI REG_Y)
(match_operand:HI 0 "immediate_operand" "")))
(set (reg:HI REG_SP) (reg:HI REG_Y))
(clobber (reg:QI REG_Z))]
""
"ldi r30, lo8(%0)
%~jmp __epilogue_restores__ + ((18 - %0) * 2)"
[(set_attr_alternative "length"
[(if_then_else (eq_attr "mcu_mega" "yes")
(const_int 3)
(const_int 2))])
(set_attr "cc" "clobber")
])
; return
(define_insn "return"
[(return)]
"reload_completed && avr_simple_epilogue ()"
"ret"
[(set_attr "cc" "none")
(set_attr "length" "1")])
(define_insn "return_from_epilogue"
[(return)]
"(reload_completed
&& cfun->machine
&& !(cfun->machine->is_interrupt || cfun->machine->is_signal)
&& !cfun->machine->is_naked)"
"ret"
[(set_attr "cc" "none")
(set_attr "length" "1")])
(define_insn "return_from_interrupt_epilogue"
[(return)]
"(reload_completed
&& cfun->machine
&& (cfun->machine->is_interrupt || cfun->machine->is_signal)
&& !cfun->machine->is_naked)"
"reti"
[(set_attr "cc" "none")
(set_attr "length" "1")])
(define_insn "return_from_naked_epilogue"
[(return)]
"(reload_completed
&& cfun->machine
&& cfun->machine->is_naked)"
""
[(set_attr "cc" "none")
(set_attr "length" "0")])
(define_expand "prologue"
[(const_int 0)]
""
"
{
expand_prologue ();
DONE;
}")
(define_expand "epilogue"
[(const_int 0)]
""
{
expand_epilogue (false /* sibcall_p */);
DONE;
})
(define_expand "sibcall_epilogue"
[(const_int 0)]
""
{
expand_epilogue (true /* sibcall_p */);
DONE;
})
;; Some instructions resp. instruction sequences available
;; via builtins.
(define_insn "delay_cycles_1"
[(unspec_volatile [(match_operand:QI 0 "const_int_operand" "n")
(const_int 1)]
UNSPECV_DELAY_CYCLES)
(clobber (match_scratch:QI 1 "=&d"))]
""
"ldi %1,lo8(%0)
1: dec %1
brne 1b"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "delay_cycles_2"
[(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n")
(const_int 2)]
UNSPECV_DELAY_CYCLES)
(clobber (match_scratch:HI 1 "=&w"))]
""
"ldi %A1,lo8(%0)
ldi %B1,hi8(%0)
1: sbiw %A1,1
brne 1b"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "delay_cycles_3"
[(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
(const_int 3)]
UNSPECV_DELAY_CYCLES)
(clobber (match_scratch:QI 1 "=&d"))
(clobber (match_scratch:QI 2 "=&d"))
(clobber (match_scratch:QI 3 "=&d"))]
""
"ldi %1,lo8(%0)
ldi %2,hi8(%0)
ldi %3,hlo8(%0)
1: subi %1,1
sbci %2,0
sbci %3,0
brne 1b"
[(set_attr "length" "7")
(set_attr "cc" "clobber")])
(define_insn "delay_cycles_4"
[(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
(const_int 4)]
UNSPECV_DELAY_CYCLES)
(clobber (match_scratch:QI 1 "=&d"))
(clobber (match_scratch:QI 2 "=&d"))
(clobber (match_scratch:QI 3 "=&d"))
(clobber (match_scratch:QI 4 "=&d"))]
""
"ldi %1,lo8(%0)
ldi %2,hi8(%0)
ldi %3,hlo8(%0)
ldi %4,hhi8(%0)
1: subi %1,1
sbci %2,0
sbci %3,0
sbci %4,0
brne 1b"
[(set_attr "length" "9")
(set_attr "cc" "clobber")])
;; Parity
(define_expand "parityhi2"
[(set (reg:HI 24)
(match_operand:HI 1 "register_operand" ""))
(set (reg:HI 24)
(parity:HI (reg:HI 24)))
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
""
"")
(define_expand "paritysi2"
[(set (reg:SI 22)
(match_operand:SI 1 "register_operand" ""))
(set (reg:HI 24)
(parity:HI (reg:SI 22)))
(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (reg:HI 24)))]
""
"")
(define_insn "*parityhi2.libgcc"
[(set (reg:HI 24)
(parity:HI (reg:HI 24)))]
""
"%~call __parityhi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*parityqihi2.libgcc"
[(set (reg:HI 24)
(parity:HI (reg:QI 24)))]
""
"%~call __parityqi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*paritysihi2.libgcc"
[(set (reg:HI 24)
(parity:HI (reg:SI 22)))]
""
"%~call __paritysi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; Popcount
(define_expand "popcounthi2"
[(set (reg:HI 24)
(match_operand:HI 1 "register_operand" ""))
(set (reg:HI 24)
(popcount:HI (reg:HI 24)))
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
""
"")
(define_expand "popcountsi2"
[(set (reg:SI 22)
(match_operand:SI 1 "register_operand" ""))
(set (reg:HI 24)
(popcount:HI (reg:SI 22)))
(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (reg:HI 24)))]
""
"")
(define_insn "*popcounthi2.libgcc"
[(set (reg:HI 24)
(popcount:HI (reg:HI 24)))]
""
"%~call __popcounthi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*popcountsi2.libgcc"
[(set (reg:HI 24)
(popcount:HI (reg:SI 22)))]
""
"%~call __popcountsi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*popcountqi2.libgcc"
[(set (reg:QI 24)
(popcount:QI (reg:QI 24)))]
""
"%~call __popcountqi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn_and_split "*popcountqihi2.libgcc"
[(set (reg:HI 24)
(popcount:HI (reg:QI 24)))]
""
"#"
""
[(set (reg:QI 24)
(popcount:QI (reg:QI 24)))
(set (reg:QI 25)
(const_int 0))]
"")
;; Count Leading Zeros
(define_expand "clzhi2"
[(set (reg:HI 24)
(match_operand:HI 1 "register_operand" ""))
(parallel [(set (reg:HI 24)
(clz:HI (reg:HI 24)))
(clobber (reg:QI 26))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
""
"")
(define_expand "clzsi2"
[(set (reg:SI 22)
(match_operand:SI 1 "register_operand" ""))
(parallel [(set (reg:HI 24)
(clz:HI (reg:SI 22)))
(clobber (reg:QI 26))])
(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (reg:HI 24)))]
""
"")
(define_insn "*clzhi2.libgcc"
[(parallel [(set (reg:HI 24)
(clz:HI (reg:HI 24)))
(clobber (reg:QI 26))])]
""
"%~call __clzhi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*clzsihi2.libgcc"
[(parallel [(set (reg:HI 24)
(clz:HI (reg:SI 22)))
(clobber (reg:QI 26))])]
""
"%~call __clzsi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; Count Trailing Zeros
(define_expand "ctzhi2"
[(set (reg:HI 24)
(match_operand:HI 1 "register_operand" ""))
(parallel [(set (reg:HI 24)
(ctz:HI (reg:HI 24)))
(clobber (reg:QI 26))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
""
"")
(define_expand "ctzsi2"
[(set (reg:SI 22)
(match_operand:SI 1 "register_operand" ""))
(parallel [(set (reg:HI 24)
(ctz:HI (reg:SI 22)))
(clobber (reg:QI 22))
(clobber (reg:QI 26))])
(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (reg:HI 24)))]
""
"")
(define_insn "*ctzhi2.libgcc"
[(set (reg:HI 24)
(ctz:HI (reg:HI 24)))
(clobber (reg:QI 26))]
""
"%~call __ctzhi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*ctzsihi2.libgcc"
[(set (reg:HI 24)
(ctz:HI (reg:SI 22)))
(clobber (reg:QI 22))
(clobber (reg:QI 26))]
""
"%~call __ctzsi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; Find First Set
(define_expand "ffshi2"
[(set (reg:HI 24)
(match_operand:HI 1 "register_operand" ""))
(parallel [(set (reg:HI 24)
(ffs:HI (reg:HI 24)))
(clobber (reg:QI 26))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
""
"")
(define_expand "ffssi2"
[(set (reg:SI 22)
(match_operand:SI 1 "register_operand" ""))
(parallel [(set (reg:HI 24)
(ffs:HI (reg:SI 22)))
(clobber (reg:QI 22))
(clobber (reg:QI 26))])
(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (reg:HI 24)))]
""
"")
(define_insn "*ffshi2.libgcc"
[(parallel [(set (reg:HI 24)
(ffs:HI (reg:HI 24)))
(clobber (reg:QI 26))])]
""
"%~call __ffshi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
(define_insn "*ffssihi2.libgcc"
[(parallel [(set (reg:HI 24)
(ffs:HI (reg:SI 22)))
(clobber (reg:QI 22))
(clobber (reg:QI 26))])]
""
"%~call __ffssi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; Copysign
(define_insn "copysignsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(unspec:SF [(match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "register_operand" "r")]
UNSPEC_COPYSIGN))]
""
"bst %D2,7\;bld %D0,7"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; Swap Bytes (change byte-endianess)
(define_expand "bswapsi2"
[(set (reg:SI 22)
(match_operand:SI 1 "register_operand" ""))
(set (reg:SI 22)
(bswap:SI (reg:SI 22)))
(set (match_operand:SI 0 "register_operand" "")
(reg:SI 22))]
""
"")
(define_insn "*bswapsi2.libgcc"
[(set (reg:SI 22)
(bswap:SI (reg:SI 22)))]
""
"%~call __bswapsi2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; CPU instructions
;; NOP taking 1 or 2 Ticks
(define_insn "nopv"
[(unspec_volatile [(match_operand:SI 0 "const_int_operand" "P,K")]
UNSPECV_NOP)]
""
"@
nop
rjmp ."
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; SLEEP
(define_insn "sleep"
[(unspec_volatile [(const_int 0)] UNSPECV_SLEEP)]
""
"sleep"
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; WDR
(define_insn "wdr"
[(unspec_volatile [(const_int 0)] UNSPECV_WDR)]
""
"wdr"
[(set_attr "length" "1")
(set_attr "cc" "none")])
;; FMUL
(define_expand "fmul"
[(set (reg:QI 24)
(match_operand:QI 1 "register_operand" ""))
(set (reg:QI 25)
(match_operand:QI 2 "register_operand" ""))
(parallel [(set (reg:HI 22)
(unspec:HI [(reg:QI 24)
(reg:QI 25)] UNSPEC_FMUL))
(clobber (reg:HI 24))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 22))]
""
{
if (AVR_HAVE_MUL)
{
emit_insn (gen_fmul_insn (operand0, operand1, operand2));
DONE;
}
})
(define_insn "fmul_insn"
[(set (match_operand:HI 0 "register_operand" "=r")
(unspec:HI [(match_operand:QI 1 "register_operand" "a")
(match_operand:QI 2 "register_operand" "a")]
UNSPEC_FMUL))]
"AVR_HAVE_MUL"
"fmul %1,%2
movw %0,r0
clr __zero_reg__"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "*fmul.call"
[(set (reg:HI 22)
(unspec:HI [(reg:QI 24)
(reg:QI 25)] UNSPEC_FMUL))
(clobber (reg:HI 24))]
"!AVR_HAVE_MUL"
"%~call __fmul"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; FMULS
(define_expand "fmuls"
[(set (reg:QI 24)
(match_operand:QI 1 "register_operand" ""))
(set (reg:QI 25)
(match_operand:QI 2 "register_operand" ""))
(parallel [(set (reg:HI 22)
(unspec:HI [(reg:QI 24)
(reg:QI 25)] UNSPEC_FMULS))
(clobber (reg:HI 24))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 22))]
""
{
if (AVR_HAVE_MUL)
{
emit_insn (gen_fmuls_insn (operand0, operand1, operand2));
DONE;
}
})
(define_insn "fmuls_insn"
[(set (match_operand:HI 0 "register_operand" "=r")
(unspec:HI [(match_operand:QI 1 "register_operand" "a")
(match_operand:QI 2 "register_operand" "a")]
UNSPEC_FMULS))]
"AVR_HAVE_MUL"
"fmuls %1,%2
movw %0,r0
clr __zero_reg__"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "*fmuls.call"
[(set (reg:HI 22)
(unspec:HI [(reg:QI 24)
(reg:QI 25)] UNSPEC_FMULS))
(clobber (reg:HI 24))]
"!AVR_HAVE_MUL"
"%~call __fmuls"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; FMULSU
(define_expand "fmulsu"
[(set (reg:QI 24)
(match_operand:QI 1 "register_operand" ""))
(set (reg:QI 25)
(match_operand:QI 2 "register_operand" ""))
(parallel [(set (reg:HI 22)
(unspec:HI [(reg:QI 24)
(reg:QI 25)] UNSPEC_FMULSU))
(clobber (reg:HI 24))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 22))]
""
{
if (AVR_HAVE_MUL)
{
emit_insn (gen_fmulsu_insn (operand0, operand1, operand2));
DONE;
}
})
(define_insn "fmulsu_insn"
[(set (match_operand:HI 0 "register_operand" "=r")
(unspec:HI [(match_operand:QI 1 "register_operand" "a")
(match_operand:QI 2 "register_operand" "a")]
UNSPEC_FMULSU))]
"AVR_HAVE_MUL"
"fmulsu %1,%2
movw %0,r0
clr __zero_reg__"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "*fmulsu.call"
[(set (reg:HI 22)
(unspec:HI [(reg:QI 24)
(reg:QI 25)] UNSPEC_FMULSU))
(clobber (reg:HI 24))]
"!AVR_HAVE_MUL"
"%~call __fmulsu"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; Some combiner patterns dealing with bits.
;; See PR42210
;; Move bit $3.0 into bit $0.$4
(define_insn "*movbitqi.1-6.a"
[(set (match_operand:QI 0 "register_operand" "=r")
(ior:QI (and:QI (match_operand:QI 1 "register_operand" "0")
(match_operand:QI 2 "single_zero_operand" "n"))
(and:QI (ashift:QI (match_operand:QI 3 "register_operand" "r")
(match_operand:QI 4 "const_0_to_7_operand" "n"))
(match_operand:QI 5 "single_one_operand" "n"))))]
"INTVAL(operands[4]) == exact_log2 (~INTVAL(operands[2]) & GET_MODE_MASK (QImode))
&& INTVAL(operands[4]) == exact_log2 (INTVAL(operands[5]) & GET_MODE_MASK (QImode))"
"bst %3,0\;bld %0,%4"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; Move bit $3.0 into bit $0.$4
;; Variation of above. Unfortunately, there is no canonicalized representation
;; of moving around bits. So what we see here depends on how user writes down
;; bit manipulations.
(define_insn "*movbitqi.1-6.b"
[(set (match_operand:QI 0 "register_operand" "=r")
(ior:QI (and:QI (match_operand:QI 1 "register_operand" "0")
(match_operand:QI 2 "single_zero_operand" "n"))
(ashift:QI (and:QI (match_operand:QI 3 "register_operand" "r")
(const_int 1))
(match_operand:QI 4 "const_0_to_7_operand" "n"))))]
"INTVAL(operands[4]) == exact_log2 (~INTVAL(operands[2]) & GET_MODE_MASK (QImode))"
"bst %3,0\;bld %0,%4"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; Move bit $3.0 into bit $0.0.
;; For bit 0, combiner generates slightly different pattern.
(define_insn "*movbitqi.0"
[(set (match_operand:QI 0 "register_operand" "=r")
(ior:QI (and:QI (match_operand:QI 1 "register_operand" "0")
(match_operand:QI 2 "single_zero_operand" "n"))
(and:QI (match_operand:QI 3 "register_operand" "r")
(const_int 1))))]
"0 == exact_log2 (~INTVAL(operands[2]) & GET_MODE_MASK (QImode))"
"bst %3,0\;bld %0,0"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; Move bit $2.0 into bit $0.7.
;; For bit 7, combiner generates slightly different pattern
(define_insn "*movbitqi.7"
[(set (match_operand:QI 0 "register_operand" "=r")
(ior:QI (and:QI (match_operand:QI 1 "register_operand" "0")
(const_int 127))
(ashift:QI (match_operand:QI 2 "register_operand" "r")
(const_int 7))))]
""
"bst %2,0\;bld %0,7"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; Combiner transforms above four pattern into ZERO_EXTRACT if it sees MEM
;; and input/output match. We provide a special pattern for this, because
;; in contrast to a IN/BST/BLD/OUT sequence we need less registers and the
;; operation on I/O is atomic.
(define_insn "*insv.io"
[(set (zero_extract:QI (mem:QI (match_operand 0 "low_io_address_operand" "n,n,n"))
(const_int 1)
(match_operand:QI 1 "const_0_to_7_operand" "n,n,n"))
(match_operand:QI 2 "nonmemory_operand" "L,P,r"))]
""
"@
cbi %m0-0x20,%1
sbi %m0-0x20,%1
sbrc %2,0\;sbi %m0-0x20,%1\;sbrs %2,0\;cbi %m0-0x20,%1"
[(set_attr "length" "1,1,4")
(set_attr "cc" "none")])
(define_insn "*insv.not.io"
[(set (zero_extract:QI (mem:QI (match_operand 0 "low_io_address_operand" "n"))
(const_int 1)
(match_operand:QI 1 "const_0_to_7_operand" "n"))
(not:QI (match_operand:QI 2 "register_operand" "r")))]
""
"sbrs %2,0\;sbi %m0-0x20,%1\;sbrc %2,0\;cbi %m0-0x20,%1"
[(set_attr "length" "4")
(set_attr "cc" "none")])
;; The insv expander.
;; We only support 1-bit inserts
(define_expand "insv"
[(set (zero_extract:QI (match_operand:QI 0 "register_operand" "")
(match_operand:QI 1 "const1_operand" "") ; width
(match_operand:QI 2 "const_0_to_7_operand" "")) ; pos
(match_operand:QI 3 "nonmemory_operand" ""))]
"optimize"
"")
;; Insert bit $2.0 into $0.$1
(define_insn "*insv.reg"
[(set (zero_extract:QI (match_operand:QI 0 "register_operand" "+r,d,d,l,l")
(const_int 1)
(match_operand:QI 1 "const_0_to_7_operand" "n,n,n,n,n"))
(match_operand:QI 2 "nonmemory_operand" "r,L,P,L,P"))]
""
"@
bst %2,0\;bld %0,%1
andi %0,lo8(~(1<<%1))
ori %0,lo8(1<<%1)
clt\;bld %0,%1
set\;bld %0,%1"
[(set_attr "length" "2,1,1,2,2")
(set_attr "cc" "none,set_zn,set_zn,none,none")])
;; Some combine patterns that try to fix bad code when a value is composed
;; from byte parts like in PR27663.
;; The patterns give some release but the code still is not optimal,
;; in particular when subreg lowering (-fsplit-wide-types) is turned on.
;; That switch obfuscates things here and in many other places.
(define_insn_and_split "*iorqi.byte0"
[(set (match_operand:HISI 0 "register_operand" "=r")
(ior:HISI
(zero_extend:HISI (match_operand:QI 1 "register_operand" "r"))
(match_operand:HISI 2 "register_operand" "0")))]
""
"#"
"reload_completed"
[(set (match_dup 3)
(ior:QI (match_dup 3)
(match_dup 1)))]
{
operands[3] = simplify_gen_subreg (QImode, operands[0], mode, 0);
})
(define_insn_and_split "*iorqi.byte1-3"
[(set (match_operand:HISI 0 "register_operand" "=r")
(ior:HISI
(ashift:HISI (zero_extend:HISI (match_operand:QI 1 "register_operand" "r"))
(match_operand:QI 2 "const_8_16_24_operand" "n"))
(match_operand:HISI 3 "register_operand" "0")))]
"INTVAL(operands[2]) < GET_MODE_BITSIZE (mode)"
"#"
"&& reload_completed"
[(set (match_dup 4)
(ior:QI (match_dup 4)
(match_dup 1)))]
{
int byteno = INTVAL(operands[2]) / BITS_PER_UNIT;
operands[4] = simplify_gen_subreg (QImode, operands[0], mode, byteno);
})
(define_expand "extzv"
[(set (match_operand:QI 0 "register_operand" "")
(zero_extract:QI (match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "const1_operand" "")
(match_operand:QI 3 "const_0_to_7_operand" "")))]
""
"")
(define_insn "*extzv"
[(set (match_operand:QI 0 "register_operand" "=*d,*d,*d,*d,r")
(zero_extract:QI (match_operand:QI 1 "register_operand" "0,r,0,0,r")
(const_int 1)
(match_operand:QI 2 "const_0_to_7_operand" "L,L,P,C04,n")))]
""
"@
andi %0,1
mov %0,%1\;andi %0,1
lsr %0\;andi %0,1
swap %0\;andi %0,1
bst %1,%2\;clr %0\;bld %0,0"
[(set_attr "length" "1,2,2,2,3")
(set_attr "cc" "set_zn,set_zn,set_zn,set_zn,clobber")])
(define_insn_and_split "*extzv.qihi1"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extract:HI (match_operand:QI 1 "register_operand" "r")
(const_int 1)
(match_operand:QI 2 "const_0_to_7_operand" "n")))]
""
"#"
""
[(set (match_dup 3)
(zero_extract:QI (match_dup 1)
(const_int 1)
(match_dup 2)))
(set (match_dup 4)
(const_int 0))]
{
operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1);
})
(define_insn_and_split "*extzv.qihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI
(zero_extract:QI (match_operand:QI 1 "register_operand" "r")
(const_int 1)
(match_operand:QI 2 "const_0_to_7_operand" "n"))))]
""
"#"
""
[(set (match_dup 3)
(zero_extract:QI (match_dup 1)
(const_int 1)
(match_dup 2)))
(set (match_dup 4)
(const_int 0))]
{
operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1);
})