1998-03-29 12:14:27 +04:00
|
|
|
|
;; GCC machine description for Matsushita MN10200
|
1998-08-16 21:35:45 +04:00
|
|
|
|
;; Copyright (C) 1997, 1998 Free Software Foundation, Inc.
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
;; Contributed by Jeff Law (law@cygnus.com).
|
|
|
|
|
|
|
|
|
|
;; This file is part of GNU CC.
|
|
|
|
|
|
|
|
|
|
;; GNU CC 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 2, or (at your option)
|
|
|
|
|
;; any later version.
|
|
|
|
|
|
|
|
|
|
;; GNU CC 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 GNU CC; see the file COPYING. If not, write to
|
|
|
|
|
;; the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
|
|
;; Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
|
|
;; The original PO technology requires these to be ordered by speed,
|
|
|
|
|
;; so that assigner will pick the fastest.
|
|
|
|
|
|
|
|
|
|
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
|
|
|
|
|
|
|
|
|
|
;; Condition code settings.
|
|
|
|
|
;; none - insn does not affect cc
|
|
|
|
|
;; none_0hit - insn does not affect cc but it does modify operand 0
|
|
|
|
|
;; This attribute is used to keep track of when operand 0 changes.
|
|
|
|
|
;; See the description of NOTICE_UPDATE_CC for more info.
|
1998-08-16 21:35:45 +04:00
|
|
|
|
;; set_znv - sets z,n,v to usable values; c is unknown.
|
1998-03-29 12:14:27 +04:00
|
|
|
|
;; set_zn - sets z,n to usable values; v,c is unknown.
|
|
|
|
|
;; compare - compare instruction
|
|
|
|
|
;; clobber - value of cc is unknown
|
|
|
|
|
(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
|
|
|
|
|
(const_string "clobber"))
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; MOVE INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;;
|
|
|
|
|
;; Some general notes on move instructions.
|
|
|
|
|
;;
|
|
|
|
|
;; The hardware can't encode nop moves involving data registers, so
|
|
|
|
|
;; we catch them and emit a nop instead.
|
|
|
|
|
;;
|
|
|
|
|
;; Loads/stores to/from address registers must be 16bit aligned,
|
|
|
|
|
;; thus we avoid them for QImode.
|
|
|
|
|
;;
|
|
|
|
|
;; Stores from address registers always store 24bits, so avoid
|
|
|
|
|
;; stores from address registers in HImode, SImode, and SFmode.
|
|
|
|
|
;;
|
|
|
|
|
;; As a result of the various problems using address registers in
|
|
|
|
|
;; QImode, HImode, SImode, and SFmode, we discourage their use via
|
|
|
|
|
;; '*' in their constraints. They're still allowed, but they're never
|
1998-08-16 21:35:45 +04:00
|
|
|
|
;; the preferred class for insns with those modes.
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
;; movqi
|
|
|
|
|
|
|
|
|
|
(define_expand "movqi"
|
|
|
|
|
[(set (match_operand:QI 0 "general_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))
|
|
|
|
|
operands[1] = copy_to_mode_reg (QImode, operand1);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; We avoid memory operations involving address registers because we
|
|
|
|
|
;; can't be sure they'll be suitably aligned.
|
|
|
|
|
;;
|
|
|
|
|
;; We also discourage holding QImode values in address registers.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "=d,d,*a,d,d,m,d,*a,*a")
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,I,I,di,m,d,*a,d,i*a"))]
|
|
|
|
|
"register_operand (operands[0], QImode)
|
|
|
|
|
|| register_operand (operands[1], QImode)"
|
|
|
|
|
"@
|
|
|
|
|
nop
|
|
|
|
|
sub %0,%0
|
|
|
|
|
sub %0,%0
|
|
|
|
|
mov %S1,%0
|
|
|
|
|
movbu %1,%0
|
|
|
|
|
movb %1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %1,%0"
|
|
|
|
|
[(set_attr "cc" "none,clobber,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|
|
|
|
|
|
|
|
|
;; movhi
|
|
|
|
|
|
|
|
|
|
(define_expand "movhi"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "")
|
|
|
|
|
(match_operand:HI 1 "general_operand" ""))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* One of the ops has to be in a register */
|
|
|
|
|
if (!register_operand (operand1, HImode)
|
|
|
|
|
&& !register_operand (operand0, HImode))
|
|
|
|
|
operands[1] = copy_to_mode_reg (HImode, operand1);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d,d,*a,d,d,m,d,*a,*a,*a")
|
|
|
|
|
(match_operand:HI 1 "general_operand" "0,I,I,di,m,d,*a,d,i*a,m"))]
|
|
|
|
|
"register_operand (operands[0], HImode)
|
|
|
|
|
|| register_operand (operands[1], HImode)"
|
|
|
|
|
"@
|
|
|
|
|
nop
|
|
|
|
|
sub %0,%0
|
|
|
|
|
sub %0,%0
|
|
|
|
|
mov %s1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %A1,%0"
|
|
|
|
|
[(set_attr "cc" "none,clobber,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|
|
|
|
|
|
|
|
|
;; movpsi and helpers
|
|
|
|
|
|
|
|
|
|
(define_expand "movpsi"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "")
|
|
|
|
|
(match_operand:PSI 1 "general_operand" ""))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* One of the ops has to be in a register */
|
|
|
|
|
if (!register_operand (operand1, PSImode)
|
|
|
|
|
&& !register_operand (operand0, PSImode))
|
|
|
|
|
operands[1] = copy_to_mode_reg (PSImode, operand1);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Constant and indexed addresses are not valid addresses for PSImode,
|
|
|
|
|
;; therefore they won't be matched by the general movpsi pattern below.
|
|
|
|
|
;; ??? We had patterns to handle indexed addresses, but they kept making
|
|
|
|
|
;; us run out of regs, so they were eliminated.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "register_operand" "=a")
|
|
|
|
|
(match_operand:PSI 1 "constant_memory_operand" ""))]
|
|
|
|
|
""
|
|
|
|
|
"mov %A1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "constant_memory_operand" "=X")
|
|
|
|
|
(match_operand:PSI 1 "register_operand" "a"))]
|
|
|
|
|
""
|
|
|
|
|
"mov %1,%A0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
;; We want to prefer address registers here because 24bit moves to/from
|
|
|
|
|
;; memory are shorter and faster when done via address registers.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,a?d,?da,a,m,?d,m")
|
|
|
|
|
(match_operand:PSI 1 "general_operand" "0,I,?dai,m,a,m,?d"))]
|
|
|
|
|
"register_operand (operands[0], PSImode)
|
|
|
|
|
|| register_operand (operands[1], PSImode)"
|
|
|
|
|
"@
|
|
|
|
|
nop
|
|
|
|
|
sub %0,%0
|
|
|
|
|
mov %1,%0
|
|
|
|
|
mov %A1,%0
|
|
|
|
|
mov %1,%A0
|
|
|
|
|
movx %A1,%0
|
|
|
|
|
movx %1,%A0"
|
|
|
|
|
[(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_expand "movsi"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "")
|
|
|
|
|
(match_operand:SI 1 "general_operand" ""))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* One of the ops has to be in a register */
|
|
|
|
|
if (!register_operand (operand1, SImode)
|
|
|
|
|
&& !register_operand (operand0, SImode))
|
|
|
|
|
operands[1] = copy_to_mode_reg (SImode, operand1);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,d,*a,dm,d,d,*a,*a,*a")
|
|
|
|
|
(match_operand:SI 1 "general_operand" "0,I,I,d,dim,*a,d,*a,i"))]
|
|
|
|
|
"register_operand (operands[0], SImode)
|
|
|
|
|
|| register_operand (operands[1], SImode)"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
switch (which_alternative)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return \"nop\";
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
return \"sub %H0,%H0\;sub %L0,%L0\";
|
|
|
|
|
case 3:
|
|
|
|
|
case 5:
|
|
|
|
|
case 6:
|
|
|
|
|
case 7:
|
|
|
|
|
return \"mov %H1,%H0\;mov %L1,%L0\";
|
|
|
|
|
|
|
|
|
|
/* The next two cases try to optimize cases where one half
|
|
|
|
|
of the constant is all zeros, or when the two halves are
|
|
|
|
|
the same. */
|
|
|
|
|
case 4:
|
|
|
|
|
case 8:
|
|
|
|
|
if (REG_P (operands[0])
|
|
|
|
|
&& GET_CODE (operands[1]) == CONST_INT
|
|
|
|
|
&& (INTVAL (operands[1]) & 0xffff0000) == 0)
|
|
|
|
|
output_asm_insn (\"sub %H0,%H0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"mov %h1,%H0\", operands);
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT
|
|
|
|
|
&& ((INTVAL (operands[1]) & 0xffff)
|
|
|
|
|
== ((INTVAL (operands[1]) >> 16) & 0xffff)))
|
|
|
|
|
output_asm_insn (\"mov %H0,%L0\", operands);
|
|
|
|
|
else if (GET_CODE (operands[1]) == CONST_INT
|
|
|
|
|
&& (INTVAL (operands[1]) & 0xffff) == 0)
|
|
|
|
|
output_asm_insn (\"sub %L0,%L0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"mov %o1,%L0\", operands);
|
|
|
|
|
return \"\";
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none,clobber,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_expand "movsf"
|
|
|
|
|
[(set (match_operand:SF 0 "general_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 ""
|
|
|
|
|
[(set (match_operand:SF 0 "general_operand" "=d,d,*a,dm,d,d,*a,*a,*a")
|
|
|
|
|
(match_operand:SF 1 "general_operand" "0,G,G,d,dim,*a,d,*a,i"))]
|
|
|
|
|
"register_operand (operands[0], SFmode)
|
|
|
|
|
|| register_operand (operands[1], SFmode)"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
switch (which_alternative)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return \"nop\";
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
return \"sub %H0,%H0\;sub %L0,%L0\";
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
long val;
|
|
|
|
|
REAL_VALUE_TYPE rv;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
|
|
{
|
|
|
|
|
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
|
|
|
|
|
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|
|
|
|
val = INTVAL (operands[1]);
|
|
|
|
|
|
|
|
|
|
if ((GET_CODE (operands[1]) == CONST_INT
|
|
|
|
|
|| GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
|
|
&& (val & 0xffff0000) == 0)
|
|
|
|
|
output_asm_insn (\"sub %H0,%H0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"mov %h1,%H0\", operands);
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT
|
|
|
|
|
&& ((INTVAL (operands[1]) & 0xffff)
|
|
|
|
|
== ((INTVAL (operands[1]) >> 16) & 0xffff)))
|
|
|
|
|
output_asm_insn (\"mov %H0,%L0\", operands);
|
|
|
|
|
else if ((GET_CODE (operands[1]) == CONST_INT
|
|
|
|
|
|| GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
|
|
&& (val & 0x0000ffff) == 0)
|
|
|
|
|
output_asm_insn (\"sub %L0,%L0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"mov %o1,%L0\", operands);
|
|
|
|
|
return \"\";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none,clobber,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; TEST INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;; Go ahead and define tsthi and tstpsi so we can eliminate redundant tst insns
|
|
|
|
|
;; when we start trying to optimize this port.
|
|
|
|
|
(define_insn "tsthi"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set (cc0) (match_operand:HI 0 "nonimmediate_operand" "da"))]
|
1998-03-29 12:14:27 +04:00
|
|
|
|
""
|
|
|
|
|
"* return output_tst (operands[0], insn);"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
(define_insn "tstpsi"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set (cc0) (match_operand:PSI 0 "nonimmediate_operand" "da"))]
|
1998-03-29 12:14:27 +04:00
|
|
|
|
""
|
|
|
|
|
"* return output_tst (operands[0], insn);"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (zero_extend:HI (match_operand:QI 0 "memory_operand" "d")))]
|
|
|
|
|
""
|
|
|
|
|
"* return output_tst (operands[0], insn);"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (zero_extend:PSI (match_operand:QI 0 "memory_operand" "d")))]
|
|
|
|
|
""
|
|
|
|
|
"* return output_tst (operands[0], insn);"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
(define_insn "cmphi"
|
|
|
|
|
[(set (cc0)
|
1998-08-16 21:35:45 +04:00
|
|
|
|
(compare:HI (match_operand:HI 0 "nonimmediate_operand" "da")
|
1998-03-29 12:14:27 +04:00
|
|
|
|
(match_operand:HI 1 "general_operand" "dai")))]
|
|
|
|
|
""
|
|
|
|
|
"cmp %1,%0"
|
|
|
|
|
[(set_attr "cc" "compare")])
|
|
|
|
|
|
|
|
|
|
(define_insn "cmppsi"
|
|
|
|
|
[(set (cc0)
|
1998-08-16 21:35:45 +04:00
|
|
|
|
(compare:PSI (match_operand:PSI 0 "nonimmediate_operand" "da")
|
1998-03-29 12:14:27 +04:00
|
|
|
|
(match_operand:PSI 1 "general_operand" "dai")))]
|
|
|
|
|
""
|
|
|
|
|
"cmp %1,%0"
|
|
|
|
|
[(set_attr "cc" "compare")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; ADD INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "addhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(plus:HI (match_operand:HI 1 "general_operand" "%0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "dai")))]
|
|
|
|
|
""
|
|
|
|
|
"add %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
(define_insn "addpsi3"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=da")
|
|
|
|
|
(plus:PSI (match_operand:PSI 1 "general_operand" "%0")
|
|
|
|
|
(match_operand:PSI 2 "general_operand" "dai")))]
|
|
|
|
|
""
|
|
|
|
|
"add %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
;; We want to avoid using explicit registers; reload won't tell us
|
|
|
|
|
;; if it has to spill them and may generate incorrect code in such
|
|
|
|
|
;; cases.
|
|
|
|
|
;;
|
|
|
|
|
;; So we call out to a library routine to perform 32bit add or
|
|
|
|
|
;; subtract operations.
|
|
|
|
|
(define_expand "addsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "")
|
|
|
|
|
(plus:SI (match_operand:SI 1 "general_operand" "")
|
|
|
|
|
(match_operand:SI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* If adding a CONST_INT, we are better off generating code ourselves.
|
|
|
|
|
|
|
|
|
|
During RTL generation we call out to library routines.
|
|
|
|
|
|
|
|
|
|
After RTL generation we can not call the library routines as
|
|
|
|
|
they need to push arguments via virtual_outgoing_args_rtx which
|
|
|
|
|
has already been instantiated. So, after RTL generation we just
|
|
|
|
|
FAIL and open code the operation. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT)
|
|
|
|
|
{
|
|
|
|
|
if (!rtx_equal_p (operands[0], operands[1]))
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
emit_insn (gen_addsi3_const (operands[0], operands[0], operands[2]));
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else if (rtx_equal_function_value_matters)
|
|
|
|
|
{
|
|
|
|
|
rtx ret, insns;
|
|
|
|
|
extern rtx emit_library_call_value ();
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
ret = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__addsi3\"),
|
|
|
|
|
NULL_RTX, 1, SImode, 2, operands[1],
|
|
|
|
|
SImode, operands[2], SImode);
|
|
|
|
|
insns = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_libcall_block (insns, operands[0], ret,
|
1998-08-16 21:35:45 +04:00
|
|
|
|
gen_rtx (PLUS, SImode, operands[1], operands[2]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
FAIL;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "addsi3_const"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d")
|
|
|
|
|
(plus:SI (match_operand:SI 1 "general_operand" "0")
|
|
|
|
|
(match_operand:SI 2 "const_int_operand" "i")))
|
|
|
|
|
(clobber (match_scratch:SI 3 "=&d"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
unsigned long value = INTVAL (operands[2]);
|
|
|
|
|
|
|
|
|
|
/* If only the high bits are set in the constant, then we only
|
|
|
|
|
need a single add operation. It might be better to catch this
|
|
|
|
|
at RTL expansion time. */
|
|
|
|
|
if ((value & 0xffff) == 0)
|
|
|
|
|
return \"add %h2,%H0\";
|
|
|
|
|
|
|
|
|
|
value >>= 16;
|
|
|
|
|
value &= 0xffff;
|
|
|
|
|
|
|
|
|
|
if (value == 0)
|
|
|
|
|
return \"sub %3,%3\;add %o2,%L0\;addc %3,%H0\";
|
|
|
|
|
else
|
|
|
|
|
return \"mov %h2,%3\;add %o2,%L0\;addc %3,%H0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; SUBTRACT INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "subhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(minus:HI (match_operand:HI 1 "general_operand" "0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "dai")))]
|
|
|
|
|
""
|
|
|
|
|
"sub %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
(define_insn "subpsi3"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=da")
|
|
|
|
|
(minus:PSI (match_operand:PSI 1 "general_operand" "0")
|
|
|
|
|
(match_operand:PSI 2 "general_operand" "dai")))]
|
|
|
|
|
""
|
|
|
|
|
"sub %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
(define_expand "subsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "")
|
|
|
|
|
(minus:SI (match_operand:SI 1 "general_operand" "")
|
|
|
|
|
(match_operand:SI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* During RTL generation we call out to library routines.
|
|
|
|
|
|
|
|
|
|
After RTL generation we can not call the library routines as
|
|
|
|
|
they need to push arguments via virtual_outgoing_args_rtx which
|
|
|
|
|
has already been instantiated. So, after RTL generation we just
|
|
|
|
|
FAIL and open code the operation. */
|
|
|
|
|
if (rtx_equal_function_value_matters)
|
|
|
|
|
{
|
|
|
|
|
rtx ret, insns;
|
|
|
|
|
extern rtx emit_library_call_value ();
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
ret = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__subsi3\"),
|
|
|
|
|
NULL_RTX, 1, SImode, 2, operands[1],
|
|
|
|
|
SImode, operands[2], SImode);
|
|
|
|
|
insns = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_libcall_block (insns, operands[0], ret,
|
1998-08-16 21:35:45 +04:00
|
|
|
|
gen_rtx (MINUS, SImode, operands[1], operands[2]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
FAIL;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; There isn't a negate instruction, so we fake it.
|
|
|
|
|
;;
|
|
|
|
|
;; We used to expand this into patterns, but a single pattern
|
|
|
|
|
;; actually generates better overall code.
|
|
|
|
|
;;
|
|
|
|
|
;; We could do HImode negations with a "not;add" sequence, but
|
|
|
|
|
;; generally it's generated slightly worse code.
|
|
|
|
|
;;
|
|
|
|
|
;; The second alternative is not strictly necesasry, but helps
|
|
|
|
|
;; when the register allocators start running short of registers.
|
|
|
|
|
(define_insn "neghi2"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=&d,d")
|
|
|
|
|
(neg:HI (match_operand:HI 1 "general_operand" "d,0")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
sub %0,%0\;sub %1,%0
|
|
|
|
|
not %0\;add 1,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
;; The not/and sequence won't work here. It's not clear if we'll
|
|
|
|
|
;; ever need to provide an alternate sequence since this should
|
|
|
|
|
;; be used much less frequently than neghi2.
|
|
|
|
|
(define_insn "negpsi2"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=&d")
|
|
|
|
|
(neg:PSI (match_operand:PSI 1 "general_operand" "d")))]
|
|
|
|
|
""
|
|
|
|
|
"sub %0,%0\;sub %1,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
;; Using a magic libcall that accepts its arguments in any
|
|
|
|
|
;; data register pair has proven to be the most efficient
|
|
|
|
|
;; and most compact way to represent negsi2.
|
|
|
|
|
(define_insn "negsi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d")
|
|
|
|
|
(neg:SI (match_operand:SI 1 "general_operand" "0")))]
|
|
|
|
|
""
|
|
|
|
|
"jsr ___negsi2_%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; MULTIPLY INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;;
|
|
|
|
|
;; The mn10200 has HIxHI->SI widening multiply, but we get _severe_
|
|
|
|
|
;; code density regressions if we enable such a pattern.
|
|
|
|
|
|
|
|
|
|
(define_insn "mulhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(mult:HI (match_operand:HI 1 "general_operand" "%0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "d")))]
|
|
|
|
|
""
|
|
|
|
|
"mul %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
(define_insn "udivmodhi4"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(udiv:HI (match_operand:HI 1 "general_operand" "0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "d")))
|
|
|
|
|
(set (match_operand:HI 3 "general_operand" "=&d")
|
|
|
|
|
(umod:HI (match_dup 1) (match_dup 2)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (zero_dreg)
|
|
|
|
|
output_asm_insn (\"mov %0,mdr\", &zero_dreg);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"sub %3,%3\;mov %3,mdr\", operands);
|
|
|
|
|
|
|
|
|
|
if (find_reg_note (insn, REG_UNUSED, operands[3]))
|
|
|
|
|
return \"divu %2,%0\";
|
|
|
|
|
else
|
|
|
|
|
return \"divu %2,%0\;mov mdr,%3\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; AND INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "andhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d,d")
|
|
|
|
|
(and:HI (match_operand:HI 1 "general_operand" "%0,0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "M,di")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff)
|
|
|
|
|
return \"extxbu %0\";
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fff)
|
|
|
|
|
return \"add %0,%0\;lsr %0\";
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffe)
|
|
|
|
|
return \"lsr %0\;add %0,%0\";
|
|
|
|
|
return \"and %2,%0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none_0hit,set_znv")])
|
|
|
|
|
|
|
|
|
|
;; This expander + pattern exist only to allow trampolines to be aligned
|
|
|
|
|
;; in the stack.
|
|
|
|
|
(define_expand "andpsi3"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "")
|
|
|
|
|
(and:PSI (match_operand:PSI 1 "general_operand" "")
|
|
|
|
|
(match_operand:PSI 2 "const_int_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[2]) != CONST_INT
|
|
|
|
|
|| (INTVAL (operands[2]) & 0xff0000) != 0xff0000)
|
|
|
|
|
FAIL;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d")
|
|
|
|
|
(and:PSI (match_operand:PSI 1 "general_operand" "%0")
|
|
|
|
|
(match_operand:PSI 2 "const_int_operand" "i")))]
|
|
|
|
|
"GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& (INTVAL (operands[2]) & 0xff0000) == 0xff0000"
|
|
|
|
|
"and %2,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; OR INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "iorhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(ior:HI (match_operand:HI 1 "general_operand" "%0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "di")))]
|
|
|
|
|
""
|
|
|
|
|
"or %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; XOR INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "xorhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(xor:HI (match_operand:HI 1 "general_operand" "%0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "di")))]
|
|
|
|
|
""
|
|
|
|
|
"xor %2,%0"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; NOT INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "one_cmplhi2"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(not:HI (match_operand:HI 1 "general_operand" "0")))]
|
|
|
|
|
""
|
|
|
|
|
"not %0"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; -----------------------------------------------------------------
|
|
|
|
|
;; BIT INSTRUCTIONS
|
|
|
|
|
;; -----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;; These clears a constant set of bits in memory or in a register.
|
|
|
|
|
;; We must support register destinations to make reload happy.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "R,d")
|
|
|
|
|
(subreg:QI
|
|
|
|
|
(and:HI (subreg:HI (match_dup 0) 0)
|
|
|
|
|
(match_operand 1 "const_int_operand" "")) 0))
|
|
|
|
|
(clobber (match_scratch:HI 2 "=&d,X"))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
mov %N1,%2\;bclr %2,%0
|
|
|
|
|
and %1,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; This clears a variable set of bits in memory or in a register.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "R,d")
|
|
|
|
|
(subreg:QI
|
|
|
|
|
(and:HI (subreg:HI (match_dup 0) 0)
|
|
|
|
|
(not:HI (match_operand:HI 1 "general_operand" "d,d"))) 0))
|
|
|
|
|
(clobber (match_scratch:HI 2 "=X,&d"))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
bclr %1,%0
|
|
|
|
|
mov %1,%2\;not %2\;and %2,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "R,d")
|
|
|
|
|
(subreg:QI
|
|
|
|
|
(and:HI (not:HI (match_operand:HI 1 "general_operand" "d,d"))
|
|
|
|
|
(subreg:HI (match_dup 0) 0)) 0))
|
|
|
|
|
(clobber (match_scratch:HI 2 "=X,&d"))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
bclr %1,%0
|
|
|
|
|
mov %1,%2\;not %2\;and %2,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; These set bits in memory.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "R,d")
|
|
|
|
|
(subreg:QI
|
|
|
|
|
(ior:HI (subreg:HI (match_dup 0) 0)
|
|
|
|
|
(match_operand:HI 1 "general_operand" "d,d")) 0))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
bset %1,%0
|
|
|
|
|
or %1,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "R,d")
|
|
|
|
|
(subreg:QI
|
|
|
|
|
(ior:HI (match_operand:HI 1 "general_operand" "d,d")
|
|
|
|
|
(subreg:HI (match_dup 0) 0)) 0))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
bset %1,%0
|
|
|
|
|
or %1,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; Not any shorter/faster than using cmp, but it might save a
|
|
|
|
|
;; register if the result of the AND isn't ever used.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0)
|
|
|
|
|
(zero_extract:HI (match_operand:HI 0 "general_operand" "d")
|
|
|
|
|
(match_operand 1 "const_int_operand" "")
|
|
|
|
|
(match_operand 2 "const_int_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int len = INTVAL (operands[1]);
|
|
|
|
|
int bit = INTVAL (operands[2]);
|
|
|
|
|
int mask = 0;
|
|
|
|
|
rtx xoperands[2];
|
|
|
|
|
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
mask |= (1 << bit);
|
|
|
|
|
bit++;
|
|
|
|
|
len--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xoperands[0] = operands[0];
|
|
|
|
|
xoperands[1] = GEN_INT (mask);
|
|
|
|
|
output_asm_insn (\"btst %1,%0\", xoperands);
|
|
|
|
|
return \"\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (and:HI (match_operand:HI 0 "general_operand" "d")
|
|
|
|
|
(match_operand:HI 1 "const_int_operand" "i")))]
|
|
|
|
|
""
|
|
|
|
|
"btst %1,%0"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; JUMP INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;; Conditional jump instructions
|
|
|
|
|
|
|
|
|
|
(define_expand "ble"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (le (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bleu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (leu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bge"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ge (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bgeu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (geu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "blt"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (lt (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bltu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ltu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bgt"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (gt (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bgtu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (gtu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "beq"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_expand "bne"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (match_operator 1 "comparison_operator"
|
|
|
|
|
[(cc0) (const_int 0)])
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
|
|
|
|
|
&& (GET_CODE (operands[1]) == GT
|
|
|
|
|
|| GET_CODE (operands[1]) == GE
|
|
|
|
|
|| GET_CODE (operands[1]) == LE
|
|
|
|
|
|| GET_CODE (operands[1]) == LT))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (GET_MODE (SET_SRC (PATTERN (PREV_INSN (insn)))) == PSImode)
|
|
|
|
|
return \"b%b1x %0\";
|
|
|
|
|
else
|
|
|
|
|
return \"b%b1 %0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (match_operator 1 "comparison_operator"
|
|
|
|
|
[(cc0) (const_int 0)])
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 0 "" ""))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
|
|
|
|
|
&& (GET_CODE (operands[1]) == GT
|
|
|
|
|
|| GET_CODE (operands[1]) == GE
|
|
|
|
|
|| GET_CODE (operands[1]) == LE
|
|
|
|
|
|| GET_CODE (operands[1]) == LT))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (GET_MODE (SET_SRC (PATTERN (PREV_INSN (insn)))) == PSImode)
|
|
|
|
|
return \"b%B1x %0\";
|
|
|
|
|
else
|
|
|
|
|
return \"b%B1 %0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none")])
|
|
|
|
|
|
|
|
|
|
(define_insn "jump"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(label_ref (match_operand 0 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"jmp %l0"
|
|
|
|
|
[(set_attr "cc" "none")])
|
|
|
|
|
|
|
|
|
|
(define_insn "indirect_jump"
|
|
|
|
|
[(set (pc) (match_operand:PSI 0 "general_operand" "a"))]
|
|
|
|
|
""
|
|
|
|
|
"jmp (%0)"
|
|
|
|
|
[(set_attr "cc" "none")])
|
|
|
|
|
|
|
|
|
|
(define_insn "tablejump"
|
|
|
|
|
[(set (pc) (match_operand:PSI 0 "general_operand" "a"))
|
|
|
|
|
(use (label_ref (match_operand 1 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"jmp (%0)"
|
|
|
|
|
[(set_attr "cc" "none")])
|
|
|
|
|
|
|
|
|
|
;; Call subroutine with no return value.
|
|
|
|
|
|
|
|
|
|
(define_expand "call"
|
|
|
|
|
[(call (match_operand:QI 0 "general_operand" "")
|
|
|
|
|
(match_operand:HI 1 "general_operand" ""))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (! call_address_operand (XEXP (operands[0], 0)))
|
|
|
|
|
XEXP (operands[0], 0) = force_reg (PSImode, XEXP (operands[0], 0));
|
|
|
|
|
emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "call_internal"
|
|
|
|
|
[(call (mem:QI (match_operand:PSI 0 "call_address_operand" "aS"))
|
|
|
|
|
(match_operand:HI 1 "general_operand" "g"))]
|
|
|
|
|
""
|
|
|
|
|
"jsr %C0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; Call subroutine, returning value in operand 0
|
|
|
|
|
;; (which must be a hard register).
|
|
|
|
|
|
|
|
|
|
(define_expand "call_value"
|
|
|
|
|
[(set (match_operand 0 "" "")
|
|
|
|
|
(call (match_operand:QI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (! call_address_operand (XEXP (operands[1], 0)))
|
|
|
|
|
XEXP (operands[1], 0) = force_reg (PSImode, XEXP (operands[1], 0));
|
|
|
|
|
emit_call_insn (gen_call_value_internal (operands[0],
|
|
|
|
|
XEXP (operands[1], 0),
|
|
|
|
|
operands[2]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "call_value_internal"
|
|
|
|
|
[(set (match_operand 0 "" "=da")
|
|
|
|
|
(call (mem:QI (match_operand:PSI 1 "call_address_operand" "aS"))
|
|
|
|
|
(match_operand:HI 2 "general_operand" "g")))]
|
|
|
|
|
""
|
|
|
|
|
"jsr %C1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_expand "untyped_call"
|
|
|
|
|
[(parallel [(call (match_operand 0 "" "")
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(match_operand 1 "" "")
|
|
|
|
|
(match_operand 2 "" "")])]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
emit_call_insn (gen_call (operands[0], const0_rtx));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
|
|
|
|
{
|
|
|
|
|
rtx set = XVECEXP (operands[2], 0, i);
|
|
|
|
|
emit_move_insn (SET_DEST (set), SET_SRC (set));
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "nop"
|
|
|
|
|
[(const_int 0)]
|
|
|
|
|
""
|
|
|
|
|
"nop"
|
|
|
|
|
[(set_attr "cc" "none")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; EXTEND INSTRUCTIONS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendqihi2"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(zero_extend:HI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxbu %0
|
|
|
|
|
mov %1,%0\;extxbu %0
|
|
|
|
|
movbu %1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendqipsi2"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(zero_extend:PSI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxbu %0
|
|
|
|
|
mov %1,%0\;extxbu %0
|
|
|
|
|
movbu %1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendqisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(zero_extend:SI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxbu %L0\;sub %H0,%H0
|
|
|
|
|
mov %1,%L0\;extxbu %L0\;sub %H0,%H0
|
|
|
|
|
movbu %1,%L0\;sub %H0,%H0"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set_attr "cc" "clobber")])
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendhipsi2"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(zero_extend:PSI
|
|
|
|
|
(match_operand:HI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxu %0
|
|
|
|
|
mov %1,%0\;extxu %0
|
|
|
|
|
mov %1,%0\;extxu %0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendhisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,d")
|
|
|
|
|
(zero_extend:SI
|
|
|
|
|
(match_operand:HI 1 "general_operand" "0,dim")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
sub %H0,%H0
|
|
|
|
|
mov %1,%L0\;sub %H0,%H0"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set_attr "cc" "clobber,clobber")])
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
;; The last alternative is necessary because the second operand might
|
|
|
|
|
;; have been the frame pointer. The frame pointer would get replaced
|
|
|
|
|
;; by (plus (stack_pointer) (const_int)).
|
|
|
|
|
;;
|
|
|
|
|
;; Reload would think that it only needed a PSImode register in
|
|
|
|
|
;; push_reload and at the start of allocate_reload_regs. However,
|
|
|
|
|
;; at the end of allocate_reload_reg it would realize that the
|
|
|
|
|
;; reload register must also be valid for SImode, and if it was
|
|
|
|
|
;; not valid reload would abort.
|
|
|
|
|
(define_insn "zero_extendpsisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=d,?d,?*d,?*d")
|
|
|
|
|
(zero_extend:SI (match_operand:PSI 1 "extendpsi_operand"
|
|
|
|
|
"m,?0,?*dai,Q")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
mov %L1,%L0\;movbu %H1,%H0
|
|
|
|
|
jsr ___zero_extendpsisi2_%0
|
|
|
|
|
mov %1,%L0\;jsr ___zero_extendpsisi2_%0
|
|
|
|
|
mov a3,%L0\;add %Z1,%L0\;jsr ___zero_extendpsisi2_%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;;- sign extension instructions
|
|
|
|
|
|
|
|
|
|
(define_insn "extendqihi2"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(sign_extend:HI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
return \"extxb %0\";
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
return \"mov %1,%0\;extxb %0\";
|
|
|
|
|
else if (GET_CODE (XEXP (operands[1], 0)) == REG)
|
|
|
|
|
return \"movbu %1,%0\;extxb %0\";
|
|
|
|
|
else
|
|
|
|
|
return \"movb %1,%0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn "extendqipsi2"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(sign_extend:PSI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
return \"extxb %0\";
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
return \"mov %1,%0\;extxb %0\";
|
|
|
|
|
else if (GET_CODE (XEXP (operands[1], 0)) == REG)
|
|
|
|
|
return \"movbu %1,%0\;extxb %0\";
|
|
|
|
|
else
|
|
|
|
|
return \"movb %1,%0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn "extendqisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
return \"extxb %L0\;mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0\";
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
return \"mov %1,%L0\;extxb %L0\;mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0\";
|
|
|
|
|
else if (GET_CODE (XEXP (operands[1], 0)) == REG)
|
|
|
|
|
return \"movbu %1,%L0\;extxb %L0\;mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0\";
|
|
|
|
|
else
|
|
|
|
|
return \"movb %1,%L0\;mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0\";
|
|
|
|
|
}"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set_attr "cc" "clobber")])
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
(define_insn "extendhipsi2"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(sign_extend:PSI
|
|
|
|
|
(match_operand:HI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extx %0
|
|
|
|
|
mov %1,%0\;extx %0
|
|
|
|
|
mov %1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn "extendhisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:HI 1 "general_operand" "0,di,m")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0
|
|
|
|
|
mov %1,%L0\;mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0
|
|
|
|
|
mov %1,%L0\;mov %L0,%H0\;add %H0,%H0\;subc %H0,%H0"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set_attr "cc" "clobber")])
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
;; The last alternative is necessary because the second operand might
|
|
|
|
|
;; have been the frame pointer. The frame pointer would get replaced
|
|
|
|
|
;; by (plus (stack_pointer) (const_int)).
|
|
|
|
|
;;
|
|
|
|
|
;; Reload would think that it only needed a PSImode register in
|
|
|
|
|
;; push_reload and at the start of allocate_reload_regs. However,
|
|
|
|
|
;; at the end of allocate_reload_reg it would realize that the
|
|
|
|
|
;; reload register must also be valid for SImode, and if it was
|
|
|
|
|
;; not valid reload would abort.
|
|
|
|
|
(define_insn "extendpsisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,?d,?*d,?*d")
|
|
|
|
|
(sign_extend:SI (match_operand:PSI 1 "extendpsi_operand"
|
|
|
|
|
"m,?0,?*dai,Q")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
mov %L1,%L0\;movb %H1,%H0
|
|
|
|
|
jsr ___sign_extendpsisi2_%0
|
|
|
|
|
mov %1,%L0\;jsr ___sign_extendpsisi2_%0
|
|
|
|
|
mov a3,%L0\;add %Z1,%L0\;jsr ___sign_extendpsisi2_%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn "truncsipsi2"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=a,?d,?*d,da")
|
|
|
|
|
(truncate:PSI (match_operand:SI 1 "general_operand" "m,?m,?*d,i")))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
mov %1,%0
|
|
|
|
|
movx %A1,%0
|
|
|
|
|
jsr ___truncsipsi2_%1_%0
|
|
|
|
|
mov %1,%0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Combine should be simplifying this stuff, but isn't.
|
|
|
|
|
;;
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(zero_extend:HI (match_operand:QI 1 "general_operand" "0,di,m"))))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxbu %L0\;sub %H0,%H0
|
|
|
|
|
mov %1,%L0\;extxbu %L0\;sub %H0,%H0
|
|
|
|
|
movbu %1,%L0\;sub %H0,%H0"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(set_attr "cc" "clobber")])
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(sign_extend:SI (match_operand:QI 1 "general_operand" "0,di,m"))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
return \"extxb %0\";
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
return \"mov %1,%0\;extxb %0\";
|
|
|
|
|
else if (GET_CODE (XEXP (operands[1], 0)) == REG)
|
|
|
|
|
return \"movbu %1,%0\;extxb %0\";
|
|
|
|
|
else
|
|
|
|
|
return \"movb %1,%0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(sign_extend:SI (match_operand:HI 1 "general_operand" "0,di,m"))))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extx %0
|
|
|
|
|
mov %1,%0\;extx %0
|
|
|
|
|
mov %1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(zero_extend:HI (match_operand:QI 1 "general_operand" "0,di,m")))))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxbu %0
|
|
|
|
|
mov %1,%0\;extxbu %0
|
|
|
|
|
movbu %1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(zero_extend:SI (match_operand:HI 1 "general_operand" "0,di,m"))))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxu %0
|
|
|
|
|
mov %1,%0\;extxu %0
|
|
|
|
|
mov %1,%0\;extxu %0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(zero_extend:SI (match_operand:QI 1 "general_operand" "0,di,m"))))]
|
|
|
|
|
""
|
|
|
|
|
"@
|
|
|
|
|
extxbu %0
|
|
|
|
|
mov %1,%0\;extxbu %0
|
|
|
|
|
movbu %1,%0"
|
|
|
|
|
[(set_attr "cc" "none_0hit")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; SHIFTS
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;; If the shift count is small, we expand it into several single bit
|
|
|
|
|
;; shift insns. Otherwise we expand into a generic shift insn which
|
|
|
|
|
;; handles larger shift counts, shift by variable amounts, etc.
|
|
|
|
|
(define_expand "ashlhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "")
|
|
|
|
|
(ashift:HI (match_operand:HI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* This is an experiment to see if exposing more of the underlying
|
|
|
|
|
operations results in better code. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& INTVAL (operands[2]) <= 4)
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, HImode, operands[0],
|
|
|
|
|
gen_rtx (ASHIFT, HImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
expand_a_shift (HImode, ASHIFT, operands);
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ASHIFT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(ashift:HI (match_operand:HI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"add %0,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
(define_expand "lshrhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "")
|
|
|
|
|
(lshiftrt:HI (match_operand:HI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* This is an experiment to see if exposing more of the underlying
|
|
|
|
|
operations results in better code. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& INTVAL (operands[2]) <= 4)
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, HImode, operands[0],
|
|
|
|
|
gen_rtx (LSHIFTRT, HImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
expand_a_shift (HImode, LSHIFTRT, operands);
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; LSHIFTRT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"lsr %0"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
(define_expand "ashrhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "")
|
|
|
|
|
(ashiftrt:HI (match_operand:HI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* This is an experiment to see if exposing more of the underlying
|
|
|
|
|
operations results in better code. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& INTVAL (operands[2]) <= 4)
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, HImode, operands[0],
|
|
|
|
|
gen_rtx (ASHIFTRT, HImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
expand_a_shift (HImode, ASHIFTRT, operands);
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ASHIFTRT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d")
|
|
|
|
|
(ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"asr %0"
|
|
|
|
|
[(set_attr "cc" "set_znv")])
|
|
|
|
|
|
|
|
|
|
;; And the general HImode shift pattern. Handles both shift by constants
|
|
|
|
|
;; and shift by variable counts.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=d,d")
|
|
|
|
|
(match_operator:HI 3 "nshift_operator"
|
|
|
|
|
[ (match_operand:HI 1 "general_operand" "0,0")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "KL,dan")]))
|
|
|
|
|
(clobber (match_scratch:HI 4 "=X,&d"))]
|
|
|
|
|
""
|
|
|
|
|
"* return emit_a_shift (insn, operands);"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; We expect only ASHIFT with constant shift counts to be common for
|
|
|
|
|
;; PSImode, so we optimize just that case. For all other cases we
|
|
|
|
|
;; extend the value to SImode and perform the shift in SImode.
|
|
|
|
|
(define_expand "ashlpsi3"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "")
|
|
|
|
|
(ashift:PSI (match_operand:PSI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* This is an experiment to see if exposing more of the underlying
|
|
|
|
|
operations results in better code. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& INTVAL (operands[2]) <= 7)
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, PSImode, operands[0],
|
|
|
|
|
gen_rtx (ASHIFT, PSImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
expand_a_shift (PSImode, ASHIFT, operands);
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ASHIFT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d")
|
|
|
|
|
(ashift:PSI (match_operand:PSI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"add %0,%0"
|
|
|
|
|
[(set_attr "cc" "set_zn")])
|
|
|
|
|
|
|
|
|
|
(define_expand "lshrpsi3"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "")
|
|
|
|
|
(lshiftrt:PSI (match_operand:PSI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
rtx reg = gen_reg_rtx (SImode);
|
|
|
|
|
|
|
|
|
|
emit_insn (gen_zero_extendpsisi2 (reg, operands[1]));
|
|
|
|
|
reg = expand_binop (SImode, lshr_optab, reg,
|
|
|
|
|
operands[2], reg, 1, OPTAB_WIDEN);
|
|
|
|
|
emit_insn (gen_truncsipsi2 (operands[0], reg));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "ashrpsi3"
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "")
|
|
|
|
|
(ashiftrt:PSI (match_operand:PSI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
rtx reg = gen_reg_rtx (SImode);
|
|
|
|
|
|
|
|
|
|
emit_insn (gen_extendpsisi2 (reg, operands[1]));
|
|
|
|
|
reg = expand_binop (SImode, ashr_optab, reg,
|
|
|
|
|
operands[2], reg, 0, OPTAB_WIDEN);
|
|
|
|
|
emit_insn (gen_truncsipsi2 (operands[0], reg));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "ashlsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "")
|
|
|
|
|
(ashift:SI (match_operand:SI 1 "nonmemory_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* For small shifts, just emit a series of single bit shifts inline.
|
|
|
|
|
|
|
|
|
|
For other constant shift counts smaller than a word or non-constant
|
|
|
|
|
shift counts we call out to a library call during RTL generation time;
|
|
|
|
|
after RTL generation time we allow optabs.c to open code the operation.
|
|
|
|
|
See comments in addsi3/subsi3 expanders.
|
|
|
|
|
|
|
|
|
|
Otherwise we allow optabs.c to open code the operation. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& (INTVAL (operands[2]) <= 3))
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, SImode, operands[0],
|
|
|
|
|
gen_rtx (ASHIFT, SImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else if (rtx_equal_function_value_matters
|
|
|
|
|
&& (GET_CODE (operands[2]) != CONST_INT
|
|
|
|
|
|| INTVAL (operands[2]) <= 15))
|
|
|
|
|
{
|
|
|
|
|
rtx ret, insns;
|
|
|
|
|
extern rtx emit_library_call_value ();
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
ret = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__ashlsi3\"),
|
|
|
|
|
NULL_RTX, 1, SImode, 2, operands[1],
|
|
|
|
|
SImode, operands[2], HImode);
|
|
|
|
|
insns = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_libcall_block (insns, operands[0], ret,
|
|
|
|
|
gen_rtx (ASHIFT, SImode, operands[1], operands[2]));
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
FAIL;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ASHIFT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d")
|
|
|
|
|
(ashift:SI (match_operand:SI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"add %L0,%L0\;addc %H0,%H0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_expand "lshrsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "")
|
|
|
|
|
(lshiftrt:SI (match_operand:SI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* For small shifts, just emit a series of single bit shifts inline.
|
|
|
|
|
|
|
|
|
|
For other constant shift counts smaller than a word or non-constant
|
|
|
|
|
shift counts we call out to a library call during RTL generation time;
|
|
|
|
|
after RTL generation time we allow optabs.c to open code the operation.
|
|
|
|
|
See comments in addsi3/subsi3 expanders.
|
|
|
|
|
|
|
|
|
|
Otherwise we allow optabs.c to open code the operation. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& (INTVAL (operands[2]) <= 2))
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, SImode, operands[0],
|
|
|
|
|
gen_rtx (LSHIFTRT, SImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else if (rtx_equal_function_value_matters
|
|
|
|
|
&& (GET_CODE (operands[2]) != CONST_INT
|
|
|
|
|
|| INTVAL (operands[2]) <= 15))
|
|
|
|
|
{
|
|
|
|
|
rtx ret, insns;
|
|
|
|
|
extern rtx emit_library_call_value ();
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
ret = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__lshrsi3\"),
|
|
|
|
|
NULL_RTX, 1, SImode, 2, operands[1],
|
|
|
|
|
SImode, operands[2], HImode);
|
|
|
|
|
insns = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_libcall_block (insns, operands[0], ret,
|
|
|
|
|
gen_rtx (LSHIFTRT, SImode, operands[1], operands[2]));
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
FAIL;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; LSHIFTRT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d")
|
|
|
|
|
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"lsr %H0\;ror %L0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_expand "ashrsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "")
|
|
|
|
|
(ashiftrt:SI (match_operand:SI 1 "register_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* For small shifts, just emit a series of single bit shifts inline.
|
|
|
|
|
|
|
|
|
|
For other constant shift counts smaller than a word or non-constant
|
|
|
|
|
shift counts we call out to a library call during RTL generation time;
|
|
|
|
|
after RTL generation time we allow optabs.c to open code the operation.
|
|
|
|
|
See comments in addsi3/subsi3 expanders.
|
|
|
|
|
|
|
|
|
|
Otherwise we allow optabs.c to open code the operation. */
|
|
|
|
|
if (GET_CODE (operands[2]) == CONST_INT
|
|
|
|
|
&& (INTVAL (operands[2]) <= 2))
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
emit_move_insn (operands[0], operands[1]);
|
|
|
|
|
while (count > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_rtx (SET, SImode, operands[0],
|
|
|
|
|
gen_rtx (ASHIFTRT, SImode,
|
|
|
|
|
operands[0], GEN_INT (1))));
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else if (rtx_equal_function_value_matters
|
|
|
|
|
&& (GET_CODE (operands[2]) != CONST_INT
|
|
|
|
|
|| INTVAL (operands[2]) <= 15))
|
|
|
|
|
{
|
|
|
|
|
rtx ret, insns;
|
|
|
|
|
extern rtx emit_library_call_value ();
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
ret = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__ashrsi3\"),
|
|
|
|
|
NULL_RTX, 1, SImode, 2, operands[1],
|
|
|
|
|
SImode, operands[2], HImode);
|
|
|
|
|
insns = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_libcall_block (insns, operands[0], ret,
|
|
|
|
|
gen_rtx (ASHIFTRT, SImode, operands[1], operands[2]));
|
|
|
|
|
DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
FAIL;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ASHIFTRT one bit.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=d")
|
|
|
|
|
(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
|
|
|
|
|
(const_int 1)))]
|
|
|
|
|
""
|
|
|
|
|
"asr %H0\;ror %L0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
;; PROLOGUE/EPILOGUE
|
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|
(define_expand "prologue"
|
|
|
|
|
[(const_int 0)]
|
|
|
|
|
""
|
|
|
|
|
"expand_prologue (); DONE;")
|
|
|
|
|
|
|
|
|
|
(define_insn "outline_prologue_call"
|
|
|
|
|
[(const_int 1)]
|
|
|
|
|
""
|
|
|
|
|
"jsr ___prologue"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_expand "epilogue"
|
|
|
|
|
[(return)]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
expand_epilogue ();
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "outline_epilogue_call_a0"
|
|
|
|
|
[(const_int 2)]
|
|
|
|
|
""
|
|
|
|
|
"jsr ___epilogue_a0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn "outline_epilogue_call_d0"
|
|
|
|
|
[(const_int 3)]
|
|
|
|
|
""
|
|
|
|
|
"jsr ___epilogue_d0"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn "outline_epilogue_jump"
|
|
|
|
|
[(const_int 4)]
|
|
|
|
|
""
|
|
|
|
|
"jmp ___epilogue_noreturn"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn "return"
|
|
|
|
|
[(return)]
|
|
|
|
|
"reload_completed && total_frame_size () == 0
|
|
|
|
|
&& !current_function_needs_context"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
rtx next = next_active_insn (insn);
|
|
|
|
|
|
|
|
|
|
if (next
|
|
|
|
|
&& GET_CODE (next) == JUMP_INSN
|
|
|
|
|
&& GET_CODE (PATTERN (next)) == RETURN)
|
|
|
|
|
return \"\";
|
|
|
|
|
return \"rts\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn "return_internal"
|
|
|
|
|
[(const_int 0)
|
|
|
|
|
(return)]
|
|
|
|
|
""
|
|
|
|
|
"rts"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; These are special combiner patterns to improve array/pointer accesses.
|
|
|
|
|
;;
|
|
|
|
|
;; A typical sequence involves extending an integer/char, shifting it left
|
|
|
|
|
;; a few times, then truncating the value to PSImode.
|
|
|
|
|
;;
|
|
|
|
|
;; This first pattern combines the shifting & truncation operations, by
|
1998-08-16 21:35:45 +04:00
|
|
|
|
;; itself it is a win because the shifts end up occurring in PSImode instead
|
1998-03-29 12:14:27 +04:00
|
|
|
|
;; of SImode. However, it has the secondary effect of giving us the
|
|
|
|
|
;; opportunity to match patterns which allow us to remove the initial
|
|
|
|
|
;; extension completely, which is a big win.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,a")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(ashift:SI (match_operand:SI 1 "general_operand" "d,m,m")
|
|
|
|
|
(match_operand:HI 2 "const_int_operand" "i,i,i"))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
output_asm_insn (\"jsr ___truncsipsi2_%1_%0\", operands);
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
output_asm_insn (\"movx %A1,%0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\" mov %1,%0\", operands);
|
|
|
|
|
|
|
|
|
|
while (count)
|
|
|
|
|
{
|
|
|
|
|
output_asm_insn (\"add %0,%0\", operands);
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
return \"\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; Similarly, except that we also have zero/sign extension of the
|
|
|
|
|
;; original operand. */
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(ashift:SI
|
|
|
|
|
(zero_extend:SI (match_operand:HI 1 "general_operand" "0,dim"))
|
|
|
|
|
(match_operand:HI 2 "const_int_operand" "i,i"))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
|
|
|
|
|
/* First extend operand 1 to PSImode. */
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
output_asm_insn (\"extxu %0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"mov %1,%0\;extxu %0\", operands);
|
|
|
|
|
|
|
|
|
|
/* Now do the shifting. */
|
|
|
|
|
while (count)
|
|
|
|
|
{
|
|
|
|
|
output_asm_insn (\"add %0,%0\", operands);
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
return \"\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(ashift:SI
|
|
|
|
|
(sign_extend:SI (match_operand:HI 1 "general_operand" "0,di,m"))
|
|
|
|
|
(match_operand:HI 2 "const_int_operand" "i,i,i"))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
|
|
|
|
|
/* First extend operand 1 to PSImode. */
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
output_asm_insn (\"extx %0\", operands);
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
output_asm_insn (\"mov %1,%0\;extx %0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"mov %1,%0\", operands);
|
|
|
|
|
|
|
|
|
|
/* Now do the shifting. */
|
|
|
|
|
while (count)
|
|
|
|
|
{
|
|
|
|
|
output_asm_insn (\"add %0,%0\", operands);
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
return \"\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(ashift:SI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(zero_extend:HI (match_operand:QI 1 "general_operand" "0,di,m")))
|
|
|
|
|
(match_operand:HI 2 "const_int_operand" "i,i,i"))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
|
|
|
|
|
/* First extend operand 1 to PSImode. */
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
output_asm_insn (\"extxbu %0\", operands);
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
output_asm_insn (\"mov %1,%0\;extxbu %0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"movbu %1,%0\", operands);
|
|
|
|
|
|
|
|
|
|
/* Now do the shifting. */
|
|
|
|
|
while (count)
|
|
|
|
|
{
|
|
|
|
|
output_asm_insn (\"add %0,%0\", operands);
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
return \"\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:PSI 0 "general_operand" "=d,d,d")
|
|
|
|
|
(truncate:PSI
|
|
|
|
|
(ashift:SI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:QI 1 "general_operand" "0,di,m"))
|
|
|
|
|
(match_operand:HI 2 "const_int_operand" "i,i,i"))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int count = INTVAL (operands[2]);
|
|
|
|
|
|
|
|
|
|
/* First extend operand 1 to PSImode. */
|
|
|
|
|
if (which_alternative == 0)
|
|
|
|
|
output_asm_insn (\"extxb %0\", operands);
|
|
|
|
|
else if (which_alternative == 1)
|
|
|
|
|
output_asm_insn (\"mov %1,%0\;extxb %0\", operands);
|
|
|
|
|
else if (GET_CODE (XEXP (operands[1], 0)) == REG)
|
|
|
|
|
output_asm_insn (\"movbu %1,%0\;extxb %0\", operands);
|
|
|
|
|
else
|
|
|
|
|
output_asm_insn (\"movb %1,%0\", operands);
|
|
|
|
|
|
|
|
|
|
/* Now do the shifting. */
|
|
|
|
|
while (count)
|
|
|
|
|
{
|
|
|
|
|
output_asm_insn (\"add %0,%0\", operands);
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
return \"\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; Try to combine consecutive updates of the stack pointer (or any
|
|
|
|
|
;; other register for that matter).
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:PSI 0 "register_operand" "=da")
|
|
|
|
|
(plus:PSI (match_dup 0)
|
|
|
|
|
(match_operand 1 "const_int_operand" "")))
|
|
|
|
|
(set (match_dup 0)
|
|
|
|
|
(plus:PSI (match_dup 0)
|
|
|
|
|
(match_operand 2 "const_int_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
|
|
|
|
|
return \"add %1,%0\";
|
|
|
|
|
}"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; We had patterns to check eq/ne, but the they don't work because
|
|
|
|
|
;; 0x80000000 + 0x80000000 = 0x0 with a carry out.
|
|
|
|
|
;;
|
|
|
|
|
;; The Z flag and C flag would be set, and we have no way to
|
|
|
|
|
;; check for the Z flag set and C flag clear.
|
|
|
|
|
;;
|
|
|
|
|
;; This will work on the mn10200 because we can check the ZX flag
|
|
|
|
|
;; if the comparison is in HImode.
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:HI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (ge (cc0) (const_int 0))
|
|
|
|
|
(match_operand 1 "" "")
|
|
|
|
|
(pc)))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bcc %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:HI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (lt (cc0) (const_int 0))
|
|
|
|
|
(match_operand 1 "" "")
|
|
|
|
|
(pc)))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bcs %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:HI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (ge (cc0) (const_int 0))
|
|
|
|
|
(pc)
|
|
|
|
|
(match_operand 1 "" "")))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bcs %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:HI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (lt (cc0) (const_int 0))
|
|
|
|
|
(pc)
|
|
|
|
|
(match_operand 1 "" "")))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bcc %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:PSI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (ge (cc0) (const_int 0))
|
|
|
|
|
(match_operand 1 "" "")
|
|
|
|
|
(pc)))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bccx %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:PSI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (lt (cc0) (const_int 0))
|
|
|
|
|
(match_operand 1 "" "")
|
|
|
|
|
(pc)))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bcsx %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:PSI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (ge (cc0) (const_int 0))
|
|
|
|
|
(pc)
|
|
|
|
|
(match_operand 1 "" "")))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bcsx %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (cc0) (match_operand:PSI 0 "register_operand" "d"))
|
|
|
|
|
(set (pc) (if_then_else (lt (cc0) (const_int 0))
|
|
|
|
|
(pc)
|
|
|
|
|
(match_operand 1 "" "")))]
|
|
|
|
|
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
|
|
|
|
|
"add %0,%0\;bccx %1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
;; We call out to library routines to perform 32bit addition and subtraction
|
|
|
|
|
;; operations (see addsi3/subsi3 expanders for why). These peepholes catch
|
|
|
|
|
;; the trivial case where the operation could be done with an add;addc or
|
|
|
|
|
;; sub;subc sequence.
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (mem:SI (reg:PSI 7)) (reg:SI 2))
|
|
|
|
|
(set (reg:SI 0) (call (match_operand:QI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
"GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
|
|
|
|
|
&& strcmp (XSTR (XEXP (operands[1], 0), 0), \"__addsi3\") == 0"
|
|
|
|
|
"add d2,d0\;addc d3,d1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (mem:SI (reg:PSI 7)) (reg:SI 2))
|
|
|
|
|
(set (reg:SI 0) (call (match_operand:QI 1 "general_operand" "")
|
|
|
|
|
(match_operand:HI 2 "general_operand" "")))]
|
|
|
|
|
"GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
|
|
|
|
|
&& strcmp (XSTR (XEXP (operands[1], 0), 0), \"__subsi3\") == 0"
|
|
|
|
|
"sub d2,d0\;subc d3,d1"
|
|
|
|
|
[(set_attr "cc" "clobber")])
|