home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Education Sampler 1992 [NeXTSTEP]
/
Education_1992_Sampler.iso
/
NeXT
/
GnuSource
/
cc-61.0.1
/
cc
/
config
/
sparc.md
< prev
next >
Wrap
Text File
|
1991-06-03
|
75KB
|
2,600 lines
;;- Machine description for SPARC chip for GNU C compiler
;; Copyright (C) 1988-1990 Free Software Foundation, Inc.
;; Contributed by Michael Tiemann (tiemann@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, 675 Mass Ave, Cambridge, MA 02139, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;; Insn type. Used to default other attribute values.
;; type "unary" insns have one input operand (1) and one output operand (0)
;; type "binary" insns have two input operands (1,2) and one output (0)
;; type "compare" insns have one or two input operands (0,1) and no output
(define_attr "type"
"move,unary,binary,compare,load,store,branch,call,address,fpload,fpstore,fp,fpcc,fpmul,fpdiv,fpsqrt,multi,misc"
(const_string "binary"))
;; Set true if insn uses call-clobbered intermediate register.
(define_attr "use_clobbered" "false,true"
(if_then_else (and (eq_attr "type" "address")
(match_operand 0 "clobbered_register" ""))
(const_string "true")
(const_string "false")))
;; Length (in # of insns).
(define_attr "length" ""
(cond [(eq_attr "type" "load,fpload")
(if_then_else (match_operand 1 "symbolic_memory_operand" "")
(const_int 2) (const_int 1))
(eq_attr "type" "store,fpstore")
(if_then_else (match_operand 0 "symbolic_memory_operand" "")
(const_int 2) (const_int 1))
(eq_attr "type" "address") (const_int 2)
(eq_attr "type" "binary")
(if_then_else (match_operand 2 "arith_operand" "")
(const_int 1) (const_int 3))
(eq_attr "type" "move,unary")
(if_then_else (match_operand 1 "arith_operand" "")
(const_int 1) (const_int 2))]
(const_int 1)))
(define_asm_attributes
[(set_attr "length" "1")
(set_attr "type" "multi")])
;; Attributes for instruction and branch scheduling
(define_attr "in_call_delay" "false,true"
(cond [(eq_attr "type" "branch,call,multi") (const_string "false")
(eq_attr "type" "load,fpload,store,fpstore")
(if_then_else (eq_attr "length" "1")
(const_string "true")
(const_string "false"))
(eq_attr "type" "address")
(if_then_else (eq_attr "use_clobbered" "false")
(const_string "true")
(const_string "false"))]
(if_then_else (eq_attr "length" "1")
(const_string "true")
(const_string "false"))))
(define_delay (eq_attr "type" "call")
[(eq_attr "in_call_delay" "true") (nil) (nil)])
(define_delay (eq_attr "type" "fpcc")
[(eq_attr "type" "!branch,fpload,fpstore,fp,fpmul,fpdiv,fpsqrt,fpcc")
(nil) (nil)])
(define_attr "in_branch_delay" "false,true"
(if_then_else (and (eq_attr "type" "!branch,call,multi")
(eq_attr "length" "1"))
(const_string "true")
(const_string "false")))
(define_delay (eq_attr "type" "branch")
[(eq_attr "in_branch_delay" "true")
(nil) (eq_attr "in_branch_delay" "true")])
;; Function units of the SPARC
;; (define_function_unit {name} {num-units} {n-users} {test}
;; {ready-delay} {busy-delay} [{conflict-list}])
;; The integer ALU.
;; (Noted only for documentation; units that take one cycle do not need to
;; be specified.)
;; (define_function_unit "alu" 1 0
;; (eq_attr "type" "unary,binary,move,address") 1 0)
;; Memory with load-delay of 1 (i.e., 2 cycle load).
(define_function_unit "memory" 1 0 (eq_attr "type" "load,fpload") 2 0)
;; SPARC has two floating-point units: the FP ALU,
;; and the FP MUL/DIV/SQRT unit.
;; Instruction timings on the CY7C602 are as follows
;; FABSs 4
;; FADDs/d 5/5
;; FCMPs/d 4/4
;; FDIVs/d 23/37
;; FMOVs 4
;; FMULs/d 5/7
;; FNEGs 4
;; FSQRTs/d 34/63
;; FSUBs/d 5/5
;; FdTOi/s 5/5
;; FsTOi/d 5/5
;; FiTOs/d 9/5
;; The CY7C602 can only support 2 fp isnsn simultaneously.
;; More insns cause the chip to stall. Until we handle this
;; better in the scheduler, we use excess cycle times to
;; more evenly spread out fp insns.
(define_function_unit "fp_alu" 1 2 (eq_attr "type" "fp") 8 0)
(define_function_unit "fp_mul" 1 2 (eq_attr "type" "fpmul") 10 0)
(define_function_unit "fp_div" 1 2 (eq_attr "type" "fpdiv") 23 0)
(define_function_unit "fp_sqrt" 1 2 (eq_attr "type" "fpsqrt") 34 0)
;; Compare instructions.
;; This controls RTL generation and register allocation.
;; We generate RTL for comparisons and branches by having the cmpxx
;; patterns store away the operands. Then, the scc and bcc patterns
;; emit RTL for both the compare and the branch.
;;
;; We do this because we want to generate different code for an sne and
;; seq insn. In those cases, if the second operand of the compare is not
;; const0_rtx, we want to compute the xor of the two operands and test
;; it against zero.
;;
;; We start with the DEFINE_EXPANDs, then then DEFINE_INSNs to match
;; the patterns. Finally, we have the DEFINE_SPLITs for some of the scc
;; insns that actually require more than one machine instruction.
;; Put cmpsi first among compare insns so it matches two CONST_INT operands.
(define_expand "cmpsi"
[(set (reg:CC 0)
(compare:CC (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "arith_operand" "")))]
""
"
{
sparc_compare_op0 = operands[0];
sparc_compare_op1 = operands[1];
DONE;
}")
(define_expand "cmpsf"
[(set (reg:CCFP 0)
(compare:CCFP (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "register_operand" "")))]
""
"
{
sparc_compare_op0 = operands[0];
sparc_compare_op1 = operands[1];
DONE;
}")
(define_expand "cmpdf"
[(set (reg:CCFP 0)
(compare:CCFP (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "register_operand" "")))]
""
"
{
sparc_compare_op0 = operands[0];
sparc_compare_op1 = operands[1];
DONE;
}")
;; Next come the scc insns. For seq, sne, sgeu, and sltu, we can do this
;; without jumps using the addx/subx instructions. For the rest, we do
;; branches. Except for seq and sne, we really do not clobber the condition
;; code. However, indicate that we do to allow combine to change from
;; one operation to another easily. When SCRATCH is implemented, we will not
;; have to do this any more.
(define_expand "seq_special"
[(set (match_dup 3) (xor:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "")))
(parallel [(set (match_operand:SI 0 "register_operand" "")
(eq:SI (match_dup 3) (const_int 0)))
(clobber (reg:CC 0))])]
""
"{ operands[3] = gen_reg_rtx (SImode); }")
(define_expand "sne_special"
[(set (match_dup 3) (xor:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "")))
(parallel [(set (match_operand:SI 0 "register_operand" "")
(ne:SI (match_dup 3) (const_int 0)))
(clobber (reg:CC 0))])]
""
"{ operands[3] = gen_reg_rtx (SImode); }")
(define_expand "seq"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(eq:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ if (GET_MODE (sparc_compare_op0) == SImode)
{
if (sparc_compare_op1 == const0_rtx)
operands[1] = sparc_compare_op0;
else
{
emit_insn (gen_seq_special (operands[0], sparc_compare_op0,
sparc_compare_op1));
DONE;
}
}
else
operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "sne"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(ne:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ if (GET_MODE (sparc_compare_op0) == SImode)
{
if (sparc_compare_op1 == const0_rtx)
operands[1] = sparc_compare_op0;
else
{
emit_insn (gen_sne_special (operands[0], sparc_compare_op0,
sparc_compare_op1));
DONE;
}
}
else
operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "sgt"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(gt:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "slt"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(lt:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "sge"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(ge:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "sle"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(le:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "sgtu"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(gtu:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{
rtx tem;
/* We can do ltu easily, so if both operands are registers, swap them and
do a LTU. */
if (GET_CODE (sparc_compare_op0) == REG
&& GET_CODE (sparc_compare_op1) == REG)
{
tem = sparc_compare_op0;
sparc_compare_op0 = sparc_compare_op1;
sparc_compare_op1 = tem;
emit_insn (gen_sltu (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "sltu"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(ltu:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "sgeu"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(geu:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{ operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "sleu"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
(leu:SI (match_dup 1) (const_int 0)))
(clobber (reg:CC 0))])]
""
"
{
rtx tem;
/* We can do geu easily, so if both operands are registers, swap them and
do a GEU. */
if (GET_CODE (sparc_compare_op0) == REG
&& GET_CODE (sparc_compare_op1) == REG)
{
tem = sparc_compare_op0;
sparc_compare_op0 = sparc_compare_op1;
sparc_compare_op1 = tem;
emit_insn (gen_sgeu (operands[0]));
DONE;
}
operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
}")
;; Now the DEFINE_INSNs for the compare and scc cases. First the compares.
(define_insn ""
[(set (reg:CC 0)
(compare:CC (match_operand:SI 0 "reg_or_0_operand" "rJ")
(match_operand:SI 1 "arith_operand" "rI")))]
""
"cmp %r0,%1"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CCFP 0)
(compare:CCFP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"fcmped %0,%1%#"
[(set_attr "type" "fpcc")])
(define_insn ""
[(set (reg:CCFP 0)
(compare:CCFP (match_operand:SF 0 "nonmemory_operand" "f")
(match_operand:SF 1 "nonmemory_operand" "f")))]
""
"fcmpes %0,%1%#"
[(set_attr "type" "fpcc")])
;; The SEQ and SNE patterns are special because they can be done
;; without any branching and do not involve a COMPARE.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ne:SI (match_operand:SI 1 "register_operand" "r") (const_int 0)))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;addx %%g0,0,%0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (ne:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0))))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;subx %%g0,0,%0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(eq:SI (match_operand:SI 1 "register_operand" "r") (const_int 0)))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;subx %%g0,-1,%0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (eq:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0))))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;addx %%g0,-1,%0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
;; We can also do (x + (i == 0)) and related, so put them in.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (ne:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0))
(match_operand:SI 2 "register_operand" "r")))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;addx %2,0,%0"
[(set_attr "type" "binary")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 2 "register_operand" "r")
(ne:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0))))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;subx %2,0,%0"
[(set_attr "type" "binary")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (eq:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0))
(match_operand:SI 2 "register_operand" "r")))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;subx %2,-1,%0"
[(set_attr "type" "binary")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 2 "register_operand" "r")
(eq:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0))))
(clobber (reg:CC 0))]
""
"subcc %%g0,%1,%%g0\;addx %2,-1,%0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
;; We can also do GEU and LTU directly, but these operate after a
;; compare.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ltu:SI (reg:CC 0) (const_int 0)))
(clobber (reg:CC 0))]
""
"addx %%g0,0,%0"
[(set_attr "type" "misc")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (ltu:SI (reg:CC 0) (const_int 0))))]
""
"subx %%g0,0,%0"
[(set_attr "type" "misc")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(geu:SI (reg:CC 0) (const_int 0)))
(clobber (reg:CC 0))]
""
"subx %%g0,-1,%0"
[(set_attr "type" "misc")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (geu:SI (reg:CC 0) (const_int 0))))]
""
"addx %%g0,-1,%0"
[(set_attr "type" "misc")])
;; We can also do (x + ((unsigned) i >= 0)) and related, so put them in.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (ltu:SI (reg:CC 0) (const_int 0))
(match_operand:SI 1 "register_operand" "r")))]
""
"addx %1,0,%0"
[(set_attr "type" "unary")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(ltu:SI (reg:CC 0) (const_int 0))))]
""
"subx %1,0,%0"
[(set_attr "type" "unary")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (geu:SI (reg:CC 0) (const_int 0))
(match_operand:SI 1 "register_operand" "r")))]
""
"subx %1,-1,%0"
[(set_attr "type" "unary")])
;; Now we have the generic scc insns. These will be done using a jump.
;; We have to exclude the cases above, since we won't want combine to
;; turn something that doesn't require a jump into something that does.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "normal_comp_operator" [(reg 0) (const_int 0)]))
(clobber (reg:CC 0))]
""
"* return output_scc_insn (operands, insn); "
[(set_attr "type" "multi")])
;; These control RTL generation for conditional jump insns
(define_expand "beq"
[(set (pc)
(if_then_else (eq (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "bne"
[(set (pc)
(if_then_else (ne (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "bgt"
[(set (pc)
(if_then_else (gt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "bgtu"
[(set (pc)
(if_then_else (gtu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (GTU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "blt"
[(set (pc)
(if_then_else (lt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "bltu"
[(set (pc)
(if_then_else (ltu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "bge"
[(set (pc)
(if_then_else (ge (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "bgeu"
[(set (pc)
(if_then_else (geu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);
}")
(define_expand "ble"
[(set (pc)
(if_then_else (le (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1); }")
(define_expand "bleu"
[(set (pc)
(if_then_else (leu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{ operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
}")
;; Now match both normal and inverted jump.
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "noov_compare_op"
[(reg 0) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
""
"*
{
return output_cbranch (operands[0], 1, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence);
}"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "noov_compare_op"
[(reg 0) (const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
""
"*
{
return output_cbranch (operands[0], 1, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence);
}"
[(set_attr "type" "branch")])
;; Move instructions
(define_expand "movsi"
[(set (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, SImode))
DONE;
}")
(define_insn ""
[(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,r,Q")
(match_operand:SI 1 "move_operand" "rJ,Q,rJ"))]
""
"@
mov %1,%0
ld %1,%0
st %r1,%0"
[(set_attr "type" "move,load,store")
(set_attr "length" "*,*,1")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(match_operand:SI 1 "move_reg_or_immed_operand" "rI,K,i"))]
""
"@
mov %1,%0
sethi %%hi(%a1),%0
\\n1:\;call 2f\;sethi %%hi(%l1-1b),%0\\n2:\\tor %0,%%lo(%l1-1b),%0\;add %0,%%o7,%0"
[(set_attr "type" "move,move,multi")
(set_attr "length" "*,1,4")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (match_operand 1 "" "")))]
"check_pic (1)"
"sethi %%hi(%a1),%0"
[(set_attr "type" "move")
(set_attr "length" "1")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(high:HI (match_operand 1 "" "")))]
"check_pic (1)"
"sethi %%hi(%a1),%0"
[(set_attr "type" "move")
(set_attr "length" "1")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")))]
""
"or %1,%%lo(%a2),%0"
;; Need to set length for this arith insn because operand2
;; is not an "arith_operand".
[(set_attr "length" "1")])
(define_insn ""
[(set (mem:SI (match_operand:SI 0 "symbolic_operand" ""))
(match_operand:SI 1 "reg_or_0_operand" "rJ"))
(clobber (match_scratch:SI 2 "=&r"))]
""
"sethi %%hi(%a0),%2\;st %r1,[%2+%%lo(%a0)]"
[(set_attr "type" "store")
(set_attr "length" "2")])
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, HImode))
DONE;
}")
(define_insn ""
[(set (match_operand:HI 0 "reg_or_nonsymb_mem_operand" "=r,r,Q")
(match_operand:HI 1 "move_operand" "rJ,Q,rJ"))]
""
"@
mov %1,%0
lduh %1,%0
sth %r1,%0"
[(set_attr "type" "move,load,store")
(set_attr "length" "*,*,1")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r,r")
(match_operand:HI 1 "move_reg_or_immed_operand" "rI,K"))]
""
"@
mov %1,%0
sethi %%hi(%a1),%0"
[(set_attr "type" "move,move")
(set_attr "length" "*,1")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(lo_sum:HI (match_operand:HI 1 "register_operand" "r")
(match_operand 2 "immediate_operand" "in")))]
""
"or %1,%%lo(%a2),%0"
[(set_attr "length" "1")])
(define_insn ""
[(set (mem:HI (match_operand:SI 0 "symbolic_operand" ""))
(match_operand:HI 1 "reg_or_0_operand" "rJ"))
(clobber (match_scratch:SI 2 "=&r"))]
""
"sethi %%hi(%a0),%2\;sth %r1,[%2+%%lo(%a0)]"
[(set_attr "type" "store")
(set_attr "length" "2")])
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, QImode))
DONE;
}")
(define_insn ""
[(set (match_operand:QI 0 "reg_or_nonsymb_mem_operand" "=r,r,Q")
(match_operand:QI 1 "move_operand" "rJ,Q,rJ"))]
""
"@
mov %1,%0
ldub %1,%0
stb %r1,%0"
[(set_attr "type" "move,load,store")
(set_attr "length" "*,*,1")])
(define_insn ""
[(set (match_operand:QI 0 "register_operand" "=r,r")
(match_operand:QI 1 "move_reg_or_immed_operand" "rI,K"))]
""
"@
mov %1,%0
sethi %%hi(%a1),%0"
[(set_attr "type" "move,move")
(set_attr "length" "*,1")])
(define_insn ""
[(set (match_operand:QI 0 "register_operand" "=r")
(subreg:QI (lo_sum:SI (match_operand:QI 1 "register_operand" "r")
(match_operand 2 "immediate_operand" "in")) 0))]
""
"or %1,%%lo(%a2),%0"
[(set_attr "length" "1")])
(define_insn ""
[(set (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
(match_operand:QI 1 "reg_or_0_operand" "rJ"))
(clobber (match_scratch:SI 2 "=&r"))]
""
"sethi %%hi(%a0),%2\;stb %r1,[%2+%%lo(%a0)]"
[(set_attr "type" "store")
(set_attr "length" "2")])
;; The definition of this insn does not really explain what it does,
;; but it should suffice
;; that anything generated as this insn will be recognized as one
;; and that it will not successfully combine with anything.
(define_expand "movstrsi"
[(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
(mem:BLK (match_operand:BLK 1 "general_operand" "")))
(use (match_operand:SI 2 "arith32_operand" ""))
(use (match_operand:SI 3 "immediate_operand" ""))
(clobber (match_dup 0))
(clobber (match_dup 1))
(clobber (match_scratch:SI 4 ""))
(clobber (reg:SI 0))
(clobber (reg:SI 1))])]
""
"
{
operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
operands[2] = force_not_mem (operands[2]);
}")
(define_insn ""
[(set (mem:BLK (match_operand:SI 0 "register_operand" "r"))
(mem:BLK (match_operand:SI 1 "register_operand" "r")))
(use (match_operand:SI 2 "arith32_operand" "rn"))
(use (match_operand:SI 3 "immediate_operand" "i"))
(clobber (match_dup 0))
(clobber (match_dup 1))
(clobber (match_scratch:SI 4 "=&r"))
(clobber (reg:SI 0))
(clobber (reg:SI 1))]
""
"* return output_block_move (operands);"
[(set_attr "type" "multi")])
;; Floating point move insns
;; This pattern forces (set (reg:DF ...) (const_double ...))
;; to be reloaded by putting the constant into memory.
;; It must come before the more general movdf pattern.
(define_insn ""
[(set (match_operand:DF 0 "general_operand" "=?r,r,f,o")
(match_operand:DF 1 "" "?E,G,m,G"))]
"GET_CODE (operands[1]) == CONST_DOUBLE"
"*
{
switch (which_alternative)
{
case 0:
return output_move_double (operands);
case 1:
return \"mov %%g0,%0\;mov %%g0,%R0\";
case 2:
return output_fp_move_double (operands);
case 3:
operands[1] = adj_offsettable_operand (operands[0], 4);
return \"st %%g0,%0\;st %%g0,%1\";
}
}"
[(set_attr "type" "load,move,fpload,store")
(set_attr "length" "3,2,3,3")])
(define_expand "movdf"
[(set (match_operand:DF 0 "general_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, DFmode))
DONE;
}")
(define_insn ""
[(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=f,r,Q,Q,f,&r,?f,?r")
(match_operand:DF 1 "reg_or_nonsymb_mem_operand" "f,r,f,r,Q,Q,r,f"))]
""
"*
{
if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
return output_fp_move_double (operands);
return output_move_double (operands);
}"
[(set_attr "type" "fp,move,fpstore,store,fpload,load,multi,multi")
(set_attr "length" "2,2,3,3,3,3,3,3")])
(define_insn ""
[(set (mem:DF (match_operand:SI 0 "symbolic_operand" "i,i"))
(match_operand:DF 1 "reg_or_0_operand" "rf,G"))
(clobber (match_scratch:SI 2 "=&r,&r"))]
""
"*
{
output_asm_insn (\"sethi %%hi(%a0),%2\", operands);
if (which_alternative == 0)
return \"std %1,[%2+%%lo(%a0)]\";
else
return \"st %%g0,[%2+%%lo(%a0)]\;st %%g0,[%2+%%lo(%a0+4)]\";
}"
[(set_attr "type" "store")
(set_attr "length" "3")])
(define_expand "movdi"
[(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, DImode))
DONE;
}")
(define_insn ""
[(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,Q,&r,&r,?f,?f,?f,?r,Q")
(match_operand:DI 1 "general_operand" "r,r,Q,i,r,f,Q,f,f"))]
""
"*
{
if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
return output_fp_move_double (operands);
return output_move_double (operands);
}"
[(set_attr "type" "move,store,load,misc,multi,fp,fpload,multi,fpstore")
(set_attr "length" "2,3,3,3,3,2,3,3,3")])
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, SFmode))
DONE;
}")
(define_insn ""
[(set (match_operand:SF 0 "reg_or_nonsymb_mem_operand" "=f,r,rf,f,r,Q,Q")
(match_operand:SF 1 "reg_or_nonsymb_mem_operand" "f,r,!rf,Q,Q,f,r"))]
""
"@
fmovs %1,%0
mov %1,%0
st %r1,[%%fp-4]\;ld [%%fp-4],%0
ld %1,%0
ld %1,%0
st %r1,%0
st %r1,%0"
[(set_attr "type" "fp,move,multi,fpload,load,fpstore,store")
(set_attr "length" "*,*,2,*,*,*,*")])
(define_insn ""
[(set (mem:SI (match_operand:SF 0 "symbolic_operand" "i"))
(match_operand:SF 1 "reg_or_0_operand" "rfG"))
(clobber (match_scratch:SI 2 "=&r"))]
""
"sethi %%hi(%a0),%2\;st %r1,[%2+%%lo(%a0)]"
[(set_attr "type" "store")
(set_attr "length" "2")])
;;- zero extension instructions
;; Note that the one starting from HImode comes before those for QImode
;; so that a constant operand will match HImode, not QImode.
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI
(match_operand:HI 1 "general_operand" "")))]
""
"
{
if (GET_CODE (operand1) == MEM
&& symbolic_operand (XEXP (operand1, 0), Pmode))
{
rtx temp = copy_to_mode_reg (Pmode, gen_rtx (HIGH, Pmode,
XEXP (operand1, 0)));
operands[1] = gen_rtx (MEM, HImode,
gen_rtx (LO_SUM, Pmode,
temp, XEXP (operand1, 0)));
}
if (GET_CODE (operand1) == REG
|| (GET_CODE (operand1) == SUBREG
&& GET_CODE (XEXP (operand1, 0)) == REG))
{
rtx temp = gen_reg_rtx (SImode);
rtx shift_16 = gen_rtx (CONST_INT, VOIDmode, 16);
if (GET_CODE (operand1) == SUBREG)
operand1 = XEXP (operand1, 0);
emit_insn (gen_ashlsi3 (temp, gen_rtx (SUBREG, SImode, operand1, 0), shift_16));
emit_insn (gen_lshrsi3 (operand0, temp, shift_16));
DONE;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
""
"lduh %1,%0"
[(set_attr "type" "load")])
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(zero_extend:HI
(match_operand:QI 1 "general_operand" "")))]
""
"
{
if (GET_CODE (operand1) == MEM
&& symbolic_operand (XEXP (operand1, 0), Pmode))
{
rtx temp = copy_to_mode_reg (Pmode, gen_rtx (HIGH, Pmode,
XEXP (operand1, 0)));
operands[1] = gen_rtx (MEM, QImode,
gen_rtx (LO_SUM, Pmode,
temp, XEXP (operand1, 0)));
}
}")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r,r,r")
(zero_extend:HI
(match_operand:QI 1 "sparc_operand" "r,I,Q")))]
""
"@
and %1,0xff,%0;
mov (%1 & 0xff),%0
ldub %1,%0"
[(set_attr "type" "unary,move,load")
(set_attr "length" "1")])
(define_expand "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI
(match_operand:QI 1 "general_operand" "")))]
""
"
{
if (GET_CODE (operand1) == MEM
&& symbolic_operand (XEXP (operand1, 0), Pmode))
{
rtx temp = copy_to_mode_reg (Pmode, gen_rtx (HIGH, Pmode,
XEXP (operand1, 0)));
operand1 = gen_rtx (MEM, QImode,
gen_rtx (LO_SUM, Pmode,
temp, XEXP (operand1, 0)));
emit_insn (gen_rtx (SET, VOIDmode, operand0,
gen_rtx (ZERO_EXTEND, SImode, operand1)));
DONE;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(zero_extend:SI
(match_operand:QI 1 "sparc_operand" "r,I,Q")))]
""
"@
and %1,0xff,%0
mov (%1 & 0xff),%0
ldub %1,%0"
[(set_attr "type" "unary,move,load")
(set_attr "length" "1")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC (zero_extend:SI (match_operand:QI 0 "register_operand" "r"))
(const_int 0)))]
""
"andcc %0,0xff,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_dup 1)))]
""
"andcc %1,0xff,%0"
[(set_attr "type" "unary")])
;;- sign extension instructions
;; Note that the one starting from HImode comes before those for QImode
;; so that a constant operand will match HImode, not QImode.
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(sign_extend:SI
(match_operand:HI 1 "general_operand" "")))]
""
"
{
if (GET_CODE (operand1) == MEM
&& symbolic_operand (XEXP (operand1, 0), Pmode))
{
rtx temp = copy_to_mode_reg (Pmode, gen_rtx (HIGH, Pmode,
XEXP (operand1, 0)));
operands[1] = gen_rtx (MEM, HImode,
gen_rtx (LO_SUM, Pmode,
temp, XEXP (operand1, 0)));
}
if (GET_CODE (operand1) == REG
|| (GET_CODE (operand1) == SUBREG
&& GET_CODE (XEXP (operand1, 0)) == REG))
{
rtx temp = gen_reg_rtx (SImode);
rtx shift_16 = gen_rtx (CONST_INT, VOIDmode, 16);
if (GET_CODE (operand1) == SUBREG)
operand1 = XEXP (operand1, 0);
emit_insn (gen_ashlsi3 (temp, gen_rtx (SUBREG, SImode, operand1, 0), shift_16));
emit_insn (gen_ashrsi3 (operand0, temp, shift_16));
DONE;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
""
"ldsh %1,%0"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
(set (match_operand:HI 2 "register_operand" "=r")
(match_dup 1))]
""
"ldsh %1,%0\;mov %0,%2"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
(set (match_operand:HI 2 "register_operand" "=r")
(match_dup 1))
(set (reg:CC 0)
(compare:CC (match_dup 0) (const_int 0)))]
""
"* warning (\"new cc insn\"); return \"ldsh %1,%0\;orcc %0,%%g0,%2\";"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_expand "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(sign_extend:HI
(match_operand:QI 1 "general_operand" "")))]
""
"
{
if (GET_CODE (operand1) == MEM
&& symbolic_operand (XEXP (operand1, 0), Pmode))
{
rtx temp = copy_to_mode_reg (Pmode, gen_rtx (HIGH, Pmode,
XEXP (operand1, 0)));
operands[1] = gen_rtx (MEM, QImode,
gen_rtx (LO_SUM, Pmode,
temp, XEXP (operand1, 0)));
}
if (GET_CODE (operand1) == REG
|| (GET_CODE (operand1) == SUBREG
&& GET_CODE (XEXP (operand1, 0)) == REG))
{
rtx temp = gen_reg_rtx (SImode);
rtx shift_24 = gen_rtx (CONST_INT, VOIDmode, 24);
if (GET_CODE (operand1) == SUBREG)
operand1 = XEXP (operand1, 0);
if (GET_CODE (operand0) == SUBREG)
operand0 = XEXP (operand0, 0);
emit_insn (gen_ashlsi3 (temp, gen_rtx (SUBREG, SImode, operand1, 0), shift_24));
if (GET_MODE (operand0) != SImode)
operand0 = gen_rtx (SUBREG, SImode, operand0, 0);
emit_insn (gen_ashrsi3 (operand0, temp, shift_24));
DONE;
}
}")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
""
"ldsb %1,%0"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:HI 2 "register_operand" "=r")
(match_dup 1))]
""
"ldsb %1,%0\;mov %0,%2"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:HI 2 "register_operand" "=r")
(match_dup 1))
(set (reg:CC 0)
(compare:CC (match_dup 1) (const_int 0)))]
""
"* warning (\"new cc insn\"); return \"ldsb %1,%0\;orcc %0,%%g0,%2\";"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_expand "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(sign_extend:SI
(match_operand:QI 1 "general_operand" "")))]
""
"
{
if (GET_CODE (operand1) == MEM
&& symbolic_operand (XEXP (operand1, 0), Pmode))
{
rtx temp = copy_to_mode_reg (Pmode, gen_rtx (HIGH, Pmode,
XEXP (operand1, 0)));
operands[1] = gen_rtx (MEM, QImode,
gen_rtx (LO_SUM, Pmode,
temp, XEXP (operand1, 0)));
}
if (GET_CODE (operand1) == REG
|| (GET_CODE (operand1) == SUBREG
&& GET_CODE (XEXP (operand1, 0)) == REG))
{
rtx temp = gen_reg_rtx (SImode);
rtx shift_24 = gen_rtx (CONST_INT, VOIDmode, 24);
if (GET_CODE (operand1) == SUBREG)
operand1 = XEXP (operand1, 0);
emit_insn (gen_ashlsi3 (temp, gen_rtx (SUBREG, SImode, operand1, 0), shift_24));
emit_insn (gen_ashrsi3 (operand0, temp, shift_24));
DONE;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
""
"ldsb %1,%0"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:QI 2 "register_operand" "=r")
(match_dup 1))]
""
"ldsb %1,%0\;mov %0,%2"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:QI 2 "register_operand" "=r")
(match_dup 1))
(set (reg:CC 0)
(compare:CC (match_dup 0) (const_int 0)))]
""
"* warning (\"new cc insn\"); return \"ldsb %1,%0\;orcc %0,%%g0,%2\";"
[(set_attr "type" "multi")
(set_attr "length" "2")])
;; Signed bitfield extractions come out looking like
;; (shiftrt (shift (sign_extend <Y>) <C1>) <C2>)
;; which we expand poorly as four shift insns.
;; These patters yeild two shifts:
;; (shiftrt (shift <Y> <C3>) <C4>)
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "small_int" "n")
(match_operand:SI 3 "small_int" "n")))]
""
"sll %1,%3,%0\;sra %0,32-%2,%0"
[(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "small_int" "n")
(match_operand:SI 3 "small_int" "n")))]
""
"sll %1,%3,%0\;srl %0,32-%2,%0"
[(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "small_int" "n")
(match_operand:SI 3 "small_int" "n")))]
""
[(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))]
"
{
operands[2] = gen_rtx (CONST_INT, VOIDmode,
BITS_PER_WORD - INTVAL (operands[2]));
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "small_int" "n")
(match_operand:SI 3 "small_int" "n")))]
""
[(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
"
{
operands[2] = gen_rtx (CONST_INT, VOIDmode,
BITS_PER_WORD - INTVAL (operands[2]));
}")
;; Special pattern for optimizing bit-field compares.
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "small_int" "n")
(match_operand:SI 2 "small_int" "n"))
(const_int 0)))]
"INTVAL (operands[2]) > 19"
"*
{
int len = INTVAL (operands[1]);
int pos = 32 - INTVAL (operands[2]) - len;
unsigned mask = ((1 << len) - 1) << pos;
operands[1] = gen_rtx (CONST_INT, VOIDmode, mask);
return \"andcc %0,%1,%%g0\";
}")
;; Conversions between float and double.
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float_extend:DF
(match_operand:SF 1 "register_operand" "f")))]
""
"fstod %1,%0"
[(set_attr "type" "fp")])
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float_truncate:SF
(match_operand:DF 1 "register_operand" "f")))]
""
"fdtos %1,%0"
[(set_attr "type" "fp")])
;; Conversion between fixed point and floating point.
;; Note that among the fix-to-float insns
;; the ones that start with SImode come first.
;; That is so that an operand that is a CONST_INT
;; (and therefore lacks a specific machine mode).
;; will be recognized as SImode (which is always valid)
;; rather than as QImode or HImode.
;; This pattern forces (set (reg:SF ...) (float:SF (const_int ...)))
;; to be reloaded by putting the constant into memory.
;; It must come before the more general floatsisf2 pattern.
(define_insn ""
[(set (match_operand:SF 0 "general_operand" "=f")
(float:SF (match_operand 1 "" "m")))]
"GET_CODE (operands[1]) == CONST_INT"
"* return output_floatsisf2 (operands);"
[(set_attr "type" "fp")
(set_attr "length" "3")])
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "general_operand" "=f")
(float:SF (match_operand:SI 1 "general_operand" "rfm")))]
""
"* return output_floatsisf2 (operands);"
[(set_attr "type" "fp")
(set_attr "length" "3")])
;; This pattern forces (set (reg:DF ...) (float:DF (const_int ...)))
;; to be reloaded by putting the constant into memory.
;; It must come before the more general floatsidf2 pattern.
(define_insn ""
[(set (match_operand:DF 0 "general_operand" "=f")
(float:DF (match_operand 1 "" "m")))]
"GET_CODE (operands[1]) == CONST_INT"
"* return output_floatsidf2 (operands);"
[(set_attr "type" "fp")
(set_attr "length" "3")])
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "general_operand" "=f")
(float:DF (match_operand:SI 1 "general_operand" "rm")))]
""
"* return output_floatsidf2 (operands);"
[(set_attr "type" "fp")
(set_attr "length" "3")])
;; Convert a float to an actual integer.
;; Truncation is performed as part of the conversion.
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))
(clobber (match_scratch:SF 2 "=&f"))]
""
"*
{
if (FP_REG_P (operands[1]))
output_asm_insn (\"fstoi %1,%2\", operands);
else
output_asm_insn (\"ld %1,%2\;fstoi %2,%2\", operands);
if (GET_CODE (operands[0]) == MEM)
return \"st %2,%0\";
else
return \"st %2,[%%fp-4]\;ld [%%fp-4],%0\";
}"
[(set_attr "type" "fp")
(set_attr "length" "3")])
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))
(clobber (match_scratch:DF 2 "=&f"))]
""
"*
{
if (FP_REG_P (operands[1]))
output_asm_insn (\"fdtoi %1,%2\", operands);
else
{
rtx xoperands[3];
xoperands[0] = operands[2];
xoperands[1] = operands[1];
output_asm_insn (output_fp_move_double (xoperands), xoperands);
output_asm_insn (\"fdtoi %2,%2\", operands);
}
if (GET_CODE (operands[0]) == MEM)
return \"st %2,%0\";
else
return \"st %2,[%%fp-4]\;ld [%%fp-4],%0\";
}"
[(set_attr "type" "fp")
(set_attr "length" "3")])
;;- arithmetic instructions
(define_insn "adddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_operand:DI 1 "register_operand" "%r")
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:SI 0))]
""
"addcc %R1,%R2,%R0\;addx %1,%2,%0"
[(set_attr "type" "binary")
(set_attr "length" "2")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "arith_operand" "%r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"add %1,%2,%0")
(define_insn ""
[(set (reg:CC_NOOV 0)
(compare:CC_NOOV (plus:SI (match_operand:SI 0 "register_operand" "%r")
(match_operand:SI 1 "arith_operand" "rI"))
(const_int 0)))]
""
"addcc %0,%1,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC_NOOV 0)
(compare:CC_NOOV (plus:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 1) (match_dup 2)))]
""
"addcc %1,%2,%0")
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:SI 0))]
""
"subcc %R1,%R2,%R0\;subx %1,%2,%0"
[(set_attr "length" "2")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "arith_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"sub %1,%2,%0")
(define_insn ""
[(set (reg:CC_NOOV 0)
(compare:CC_NOOV (minus:SI (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "arith_operand" "rI"))
(const_int 0)))]
""
"subcc %0,%1,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC_NOOV 0)
(compare:CC_NOOV (minus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_dup 1) (match_dup 2)))]
""
"subcc %1,%2,%0")
;;- and instructions
;; We define DImode `and` so with DImode `not` we can get
;; DImode `andn`. Other combinations are possible.
(define_expand "anddi3"
[(set (match_operand:DI 0 "register_operand" "")
(and:DI (match_operand:DI 1 "arith_double_operand" "")
(match_operand:DI 2 "arith_double_operand" "")))]
""
"
{
if (! register_operand (operands[1], DImode)
|| ! register_operand (operands[2], DImode))
/* Let GCC break this into word-at-a-time operations. */
FAIL;
}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (match_operand:DI 1 "register_operand" "%r")
(match_operand:DI 2 "register_operand" "r")))]
""
"and %1,%2,%0\;and %R1,%R2,%R0"
[(set_attr "length" "2")])
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operand:SI 1 "arith_operand" "%r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"and %1,%2,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))]
""
"andn %2,%1,%0\;andn %R2,%R1,%R0"
[(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "r")))]
""
"andn %2,%1,%0")
(define_expand "iordi3"
[(set (match_operand:DI 0 "register_operand" "")
(ior:DI (match_operand:DI 1 "arith_double_operand" "")
(match_operand:DI 2 "arith_double_operand" "")))]
""
"
{
if (! register_operand (operands[1], DImode)
|| ! register_operand (operands[2], DImode))
/* Let GCC break this into word-at-a-time operations. */
FAIL;
}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (match_operand:DI 1 "register_operand" "%r")
(match_operand:DI 2 "register_operand" "r")))]
""
"or %1,%2,%0\;or %R1,%R2,%R0"
[(set_attr "length" "2")])
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operand:SI 1 "arith_operand" "%r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"or %1,%2,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))]
""
"orn %2,%1,%0\;orn %R2,%R1,%R0"
[(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "r")))]
""
"orn %2,%1,%0")
(define_expand "xordi3"
[(set (match_operand:DI 0 "register_operand" "")
(xor:DI (match_operand:DI 1 "arith_double_operand" "")
(match_operand:DI 2 "arith_double_operand" "")))]
""
"
{
if (! register_operand (operands[1], DImode)
|| ! register_operand (operands[2], DImode))
/* Let GCC break this into word-at-a-time operations. */
FAIL;
}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(xor:DI (match_operand:DI 1 "register_operand" "%r")
(match_operand:DI 2 "register_operand" "r")))]
""
"xor %1,%2,%0\;xor %R1,%R2,%R0"
[(set_attr "length" "2")])
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(xor:SI (match_operand:SI 1 "arith_operand" "%rJ")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"xor %r1,%2,%0")
;; xnor patterns. Note that (a ^ ~b) == (~a ^ b) == ~(a ^ b).
;; Combine now canonicalizes to the rightmost expression.
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (xor:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "register_operand" "rI"))))]
""
"xnor %1,%2,%0\;xnor %R1,%R2,%R0"
[(set_attr "length" "2")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (xor:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
(match_operand:SI 2 "arith_operand" "rI"))))]
""
"xnor %r1,%2,%0")
;; These correspond to the above in the case where we also (or only)
;; want to set the condition code.
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(match_operator:SI 2 "cc_arithop"
[(match_operand:SI 0 "register_operand" "%r")
(match_operand:SI 1 "arith_operand" "rI")])
(const_int 0)))]
""
"%A2cc %0,%1,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(match_operator:SI 3 "cc_arithop"
[(match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "arith_operand" "rI")])
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(match_dup 3))]
""
"%A3cc %1,%2,%0")
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(not:SI (xor:SI (match_operand:SI 0 "reg_or_0_operand" "%rJ")
(match_operand:SI 1 "arith_operand" "rI")))
(const_int 0)))]
""
"xnorcc %r0,%1,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(not:SI (xor:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
(match_operand:SI 2 "arith_operand" "rI")))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (xor:SI (match_dup 1) (match_dup 2))))]
""
"xnorcc %r1,%2,%0")
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(match_operator:SI 2 "cc_arithopn"
[(not:SI (match_operand:SI 0 "arith_operand" "rI"))
(match_operand:SI 1 "reg_or_0_operand" "rJ")])
(const_int 0)))]
""
"%B2cc %r1,%0,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC
(match_operator:SI 3 "cc_arithopn"
[(not:SI (match_operand:SI 1 "arith_operand" "rI"))
(match_operand:SI 2 "reg_or_0_operand" "rJ")])
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(match_dup 3))]
""
"%B3cc %r2,%1,%0")
;; We cannot use the "neg" pseudo insn because the Sun assembler
;; does not know how to make it work for constants.
(define_insn "negdi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(neg:DI (match_operand:DI 1 "register_operand" "r")))
(clobber (reg:SI 0))]
""
"subcc %%g0,%R1,%R0\;subx %%g0,%1,%0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
(define_insn "negsi2"
[(set (match_operand:SI 0 "general_operand" "=r")
(neg:SI (match_operand:SI 1 "arith_operand" "rI")))]
""
"sub %%g0,%1,%0"
[(set_attr "type" "unary")])
(define_insn ""
[(set (reg:CC_NOOV 0)
(compare:CC_NOOV (neg:SI (match_operand:SI 0 "arith_operand" "rI"))
(const_int 0)))]
""
"subcc %%g0,%0,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC_NOOV 0)
(compare:CC_NOOV (neg:SI (match_operand:SI 1 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_dup 1)))]
""
"subcc %%g0,%1,%0"
[(set_attr "type" "unary")])
;; We cannot use the "not" pseudo insn because the Sun assembler
;; does not know how to make it work for constants.
(define_expand "one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "")
(not:DI (match_operand:DI 1 "arith_double_operand" "")))]
""
"
{
if (! register_operand (operands[1], DImode))
FAIL;
}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (match_operand:DI 1 "arith_double_operand" "r")))]
""
"xnor %%g0,%1,%0\;xnor %%g0,%R1,%R0"
[(set_attr "type" "unary")
(set_attr "length" "2")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=r")
(not:SI (match_operand:SI 1 "arith_operand" "rI")))]
""
"xnor %%g0,%1,%0"
[(set_attr "type" "unary")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC (not:SI (match_operand:SI 0 "arith_operand" "rI"))
(const_int 0)))]
""
"xnorcc %%g0,%0,%%g0"
[(set_attr "type" "compare")])
(define_insn ""
[(set (reg:CC 0)
(compare:CC (not:SI (match_operand:SI 1 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_dup 1)))]
""
"xnorcc %%g0,%1,%0"
[(set_attr "type" "unary")])
;; Floating point arithmetic instructions.
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
""
"faddd %1,%2,%0"
[(set_attr "type" "fp")])
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
""
"fadds %1,%2,%0"
[(set_attr "type" "fp")])
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
""
"fsubd %1,%2,%0"
[(set_attr "type" "fp")])
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(minus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
""
"fsubs %1,%2,%0"
[(set_attr "type" "fp")])
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
""
"fmuld %1,%2,%0"
[(set_attr "type" "fpmul")])
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
""
"fmuls %1,%2,%0"
[(set_attr "type" "fpmul")])
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
""
"fdivd %1,%2,%0"
[(set_attr "type" "fpdiv")])
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(div:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
""
"fdivs %1,%2,%0"
[(set_attr "type" "fpdiv")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f,f")
(neg:DF (match_operand:DF 1 "register_operand" "0,f")))]
""
"@
fnegs %0,%0
fnegs %1,%0\;fmovs %R1,%R0"
[(set_attr "type" "fp")
(set_attr "length" "1,2")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "register_operand" "f")))]
""
"fnegs %1,%0"
[(set_attr "type" "fp")])
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f,f")
(abs:DF (match_operand:DF 1 "register_operand" "0,f")))]
""
"@
fabss %0,%0
fabss %1,%0\;%fmovs %R1,%R0"
[(set_attr "type" "fp")
(set_attr "length" "1,2")])
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(abs:SF (match_operand:SF 1 "register_operand" "f")))]
""
"fabss %1,%0"
[(set_attr "type" "fp")])
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(sqrt:DF (match_operand:DF 1 "register_operand" "f")))]
""
"fsqrtd %1,%0"
[(set_attr "type" "fpsqrt")])
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
""
"fsqrts %1,%0"
[(set_attr "type" "fpsqrt")])
;; Shift instructions
;; Optimized special case of shifting.
;; Must precede the general case.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24)))]
""
"ldsb %1,%0"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24)))]
""
"ldub %1,%0"
[(set_attr "type" "load")])
;;- arithmetic shift instructions
;; We can trivially handle shifting the constant 1 by 64 bits.
;; For other shifts we use the library routine.
(define_expand "ashldi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "=&r")
(ashift:DI (match_operand:DI 1 "const_double_operand" "")
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:SI 0))])]
""
"
{
if (GET_CODE (operands[1]) == CONST_DOUBLE
|| (CONST_DOUBLE_HIGH (operands[1]) == 0
&& CONST_DOUBLE_LOW (operands[1]) == 1))
operands[1] = const1_rtx;
else if (operands[1] != const1_rtx)
FAIL;
}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=&r")
(ashift:DI (const_int 1)
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:SI 0))]
""
"subcc %2,32,%%g0\;addx %%g0,0,%R0\;xor %R0,1,%0\;sll %R0,%2,%R0\;sll %0,%2,%0"
[(set_attr "type" "multi")
(set_attr "length" "5")])
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"sll %1,%2,%0")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"sra %1,%2,%0")
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"srl %1,%2,%0")
;; Unconditional and other jump instructions
;; Note that for the Sparc, by setting the annul bit on an unconditional
;; branch, the following insn is never executed. This saves us a nop,
;; but requires a debugger which can handle annuled branches.
(define_insn "jump"
[(set (pc) (label_ref (match_operand 0 "" "")))]
""
"b%* %l0"
[(set_attr "type" "branch")])
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"jmp %^%0%#"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc) (label_ref (match_operand 0 "" "")))
(set (reg:SI 15) (label_ref (match_dup 0)))]
""
"call %l0%#"
[(set_attr "type" "branch")])
;;- jump to subroutine
(define_expand "call"
[(call (match_operand:SI 0 "call_operand" "")
(match_operand 1 "" "i"))]
;; operand[2] is next_arg_register
""
"
{
rtx fn_rtx, nregs_rtx;
if (GET_CODE (XEXP (operands[0], 0)) == LABEL_REF)
{
/* This is really a PIC sequence. We want to represent
it as a funny jump so it`s delay slots can be filled.
??? But if this really *is* a CALL, will not it clobber the
call-clobbered registers? We lose this if it is a JUMP_INSN.
Why cannot we have delay slots filled if it were a CALL? */
emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
gen_rtx (SET, VOIDmode, pc_rtx,
XEXP (operands[0], 0)),
gen_rtx (CLOBBER, VOIDmode,
gen_rtx (REG, SImode, 15)))));
DONE;
}
if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[0], 0)) == REG)
{
rtx g1_rtx = gen_rtx (REG, Pmode, 1);
emit_move_insn (g1_rtx, XEXP (operands[0], 0));
fn_rtx = gen_rtx (MEM, Pmode, g1_rtx);
}
else
fn_rtx = operands[0];
/* Count the number of parameter registers being used by this call.
if that argument is NULL, it means we are using them all, which
means 6 on the sparc. */
#if 0
if (operands[2])
nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[2]) - 8);
else
nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6);
#else
nregs_rtx = const0_rtx;
#endif
emit_call_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx),
gen_rtx (CLOBBER, VOIDmode,
gen_rtx (REG, SImode, 15)))));
DONE;
}")
(define_insn ""
[(call (mem:SI (match_operand:SI 0 "call_operand_address" "S,r"))
(match_operand 1 "" ""))
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
""
"*
{
if (TARGET_SUN_ASM && GET_CODE (operands[0]) == REG)
return \"jmpl %a0,%%o7%#\";
else
return \"call %a0,%1%#\";
}"
[(set_attr "type" "call")])
(define_expand "call_value"
[(set (match_operand 0 "register_operand" "=rf")
(call (match_operand:SI 1 "" "")
(match_operand 2 "" "")))]
;; operand 3 is next_arg_register
""
"
{
rtx fn_rtx, nregs_rtx;
rtvec vec;
if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[1], 0)) == REG)
{
rtx g1_rtx = gen_rtx (REG, Pmode, 1);
emit_move_insn (g1_rtx, XEXP (operands[1], 0));
fn_rtx = gen_rtx (MEM, Pmode, g1_rtx);
}
else
fn_rtx = operands[1];
#if 0
if (operands[3])
nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[3]) - 8);
else
nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6);
#else
nregs_rtx = const0_rtx;
#endif
vec = gen_rtvec (2,
gen_rtx (SET, VOIDmode, operands[0],
gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx)),
gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 15)));
emit_call_insn (gen_rtx (PARALLEL, VOIDmode, vec));
DONE;
}")
(define_insn ""
[(set (match_operand 0 "" "=rf")
(call (mem:SI (match_operand:SI 1 "call_operand_address" "rS"))
(match_operand 2 "" "")))
(clobber (reg:SI 15))]
;;- Do not use operand 2 for most machines.
""
"*
{
if (TARGET_SUN_ASM && GET_CODE (operands[1]) == REG)
return \"jmpl %a1,%%o7%#\";
else
return \"call %a1,%2%#\";
}"
[(set_attr "type" "call")])
(define_insn "return"
[(return)]
"! TARGET_EPILOGUE"
"* return output_return (operands);"
[(set_attr "type" "multi")])
(define_insn "nop"
[(const_int 0)]
""
"nop")
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))]
""
"jmp %0%#"
[(set_attr "type" "branch")])
;(define_insn "tail_call" ;; tail call
; [(set (pc) (match_operand 0 "memory_operand" "m"))]
; "tail_call_valid_p ()"
; "* return output_tail_call (operands, insn);"
; [(set_attr "type" "branch")])
;; Split up troublesome insns for better scheduling. */
;; The following patterns are straightforward. They can be applied
;; either before or after register allocation.
(define_split
[(set (match_operator 0 "memop" [(match_operand:SI 1 "symbolic_operand" "")])
(match_operand 2 "reg_or_0_operand" ""))
(clobber (match_operand:SI 3 "register_operand" ""))]
"! flag_pic"
[(set (match_dup 3) (high:SI (match_dup 1)))
(set (match_op_dup 0 [(lo_sum:SI (match_dup 3) (match_dup 1))])
(match_dup 2))]
"")
(define_split
[(set (match_operator 0 "memop"
[(match_operand:SI 1 "immediate_operand" "")])
(match_operand 2 "general_operand" ""))
(clobber (match_operand:SI 3 "register_operand" ""))]
"flag_pic"
[(set (match_op_dup 0 [(match_dup 1)])
(match_dup 2))]
"
{
operands[1] = legitimize_pic_address (operands[1], GET_MODE (operands[0]),
operands[3]);
}")
(define_split
[(set (match_operand 0 "register_operand" "")
(match_operator 1 "memop"
[(match_operand:SI 2 "immediate_operand" "")]))]
"flag_pic"
[(set (match_dup 0)
(match_op_dup 1 [(match_dup 2)]))]
"
{
operands[2] = legitimize_pic_address (operands[2], GET_MODE (operands[1]),
operands[0]);
}")
;; Sign- and Zero-extend operations can have symbolic memory operands.
(define_split
[(set (match_operand 0 "register_operand" "")
(match_operator 1 "extend_op"
[(match_operator 2 "memop"
[(match_operand:SI 3 "immediate_operand" "")])]))]
"flag_pic"
[(set (match_dup 0)
(match_op_dup 1 [(match_op_dup 2 [(match_dup 3)])]))]
"
{
operands[3] = legitimize_pic_address (operands[3], GET_MODE (operands[2]),
operands[0]);
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "immediate_operand" ""))]
"! flag_pic && (GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == CONST
|| GET_CODE (operands[1]) == LABEL_REF)"
[(set (match_dup 0) (high:SI (match_dup 1)))
(set (match_dup 0)
(lo_sum:SI (match_dup 0) (match_dup 1)))]
"")
;; LABEL_REFs are not modified by `legitimize_pic_address`
;; so do not recurse infinitely in the PIC case.
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "immediate_operand" ""))]
"flag_pic && (GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == CONST)"
[(set (match_dup 0) (match_dup 1))]
"
{
operands[1] = legitimize_pic_address (operands[1], Pmode, operands[0]);
}")
;; Split certain compound insns back into single insns.
(define_split
[(parallel [(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
(set (match_operand:HI 2 "register_operand" "=r")
(match_dup 1))])]
""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
(set (match_operand:HI 2 "register_operand" "=r")
(match_dup 1))]
"")
(define_split
[(parallel [(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:QI 2 "register_operand" "=r")
(match_dup 1))])]
""
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:QI 2 "register_operand" "=r")
(match_dup 1))]
"")
(define_split
[(parallel [(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:QI 2 "register_operand" "=r")
(match_dup 1))])]
""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))
(set (match_operand:QI 2 "register_operand" "=r")
(match_dup 1))]
"")
;; These split sne/seq insns. The forms of the resulting insns are
;; somewhat bogus, but they avoid extra patterns and show data dependency.
;; Nothing will look at these in detail after splitting has occurred.
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(ne:SI (match_operand:SI 1 "register_operand" "") (const_int 0)))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(parallel [(set (match_dup 0) (ltu:SI (reg:CC 0) (const_int 0)))
(clobber (reg:CC 0))])]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(neg:SI (ne:SI (match_operand:SI 1 "register_operand" "")
(const_int 0))))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(set (match_dup 0) (neg:SI (ltu:SI (reg:CC 0) (const_int 0))))]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(eq:SI (match_operand:SI 1 "register_operand" "") (const_int 0)))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(parallel [(set (match_dup 0) (geu:SI (reg:CC 0) (const_int 0)))
(clobber (reg:CC 0))])]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(neg:SI (eq:SI (match_operand:SI 1 "register_operand" "")
(const_int 0))))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(set (match_dup 0) (neg:SI (geu:SI (reg:CC 0) (const_int 0))))]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(plus:SI (ne:SI (match_operand:SI 1 "register_operand" "")
(const_int 0))
(match_operand:SI 2 "register_operand" "")))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(set (match_dup 0) (plus:SI (ltu:SI (reg:CC 0) (const_int 0))
(match_dup 2)))]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(minus:SI (match_operand:SI 2 "register_operand" "")
(ne:SI (match_operand:SI 1 "register_operand" "")
(const_int 0))))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(set (match_dup 0) (minus:SI (match_dup 2)
(geu:SI (match_dup 1) (const_int 0))))]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(plus:SI (eq:SI (match_operand:SI 1 "register_operand" "")
(const_int 0))
(match_operand:SI 2 "register_operand" "")))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(set (match_dup 0) (plus:SI (geu:SI (reg:CC 0) (const_int 0))
(match_dup 2)))]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(minus:SI (match_operand:SI 2 "register_operand" "")
(eq:SI (match_operand:SI 1 "register_operand" "")
(const_int 0))))
(clobber (reg:CC 0))]
""
[(set (reg:CC_NOOV 0) (compare:CC_NOOV (neg:SI (match_dup 1))
(const_int 0)))
(set (match_dup 0) (minus:SI (match_dup 2)
(geu:SI (match_dup 1) (const_int 0))))]
"")
;; Peepholes go at the end.
;; Optimize the case of following a reg-reg move with a test
;; of reg just moved.
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "register_operand" "r"))
(set (reg:CC 0)
(compare:CC (match_operand:SI 2 "register_operand" "r")
(const_int 0)))]
"rtx_equal_p (operands[2], operands[0])
|| rtx_equal_p (operands[2], operands[1])"
"orcc %1,%%g0,%0"
[(set_attr "type" "move")])
;; Do {sign,zero}-extended compares somewhat more efficiently.
;; ??? Is this now the Right Way to do this? Or will SCRATCH
;; eventually have some impact here?
(define_peephole
[(set (match_operand:HI 0 "register_operand" "")
(match_operand:HI 1 "memory_operand" ""))
(set (match_operand:SI 2 "register_operand" "")
(sign_extend:SI (match_dup 0)))
(set (reg:CC 0)
(compare:CC (match_dup 2)
(const_int 0)))]
""
"ldsh %1,%0\;orcc %0,%%g0,%2")
(define_peephole
[(set (match_operand:QI 0 "register_operand" "")
(match_operand:QI 1 "memory_operand" ""))
(set (match_operand:SI 2 "register_operand" "")
(sign_extend:SI (match_dup 0)))
(set (reg:CC 0)
(compare:CC (match_dup 2)
(const_int 0)))]
""
"ldsb %1,%0\;orcc %0,%%g0,%2")
(define_peephole
[(set (match_operand:HI 0 "register_operand" "")
(match_operand:HI 1 "memory_operand" ""))
(set (match_operand:SI 2 "register_operand" "")
(sign_extend:SI (match_dup 0)))]
"dead_or_set_p (insn, operands[0])"
"*
{
warning (\"bad peephole\");
if (! MEM_VOLATILE_P (operands[1]))
abort ();
return \"ldsh %1,%2\";
}")
(define_peephole
[(set (match_operand:QI 0 "register_operand" "")
(match_operand:QI 1 "memory_operand" ""))
(set (match_operand:SI 2 "register_operand" "")
(sign_extend:SI (match_dup 0)))]
"dead_or_set_p (insn, operands[0])"
"*
{
warning (\"bad peephole\");
if (! MEM_VOLATILE_P (operands[1]))
abort ();
return \"ldsb %1,%2\";
}")
;; Floating-point move peepholes
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_dup 0)
(match_operand:SI 1 "immediate_operand" "i")))
(set (match_operand:DF 2 "register_operand" "=fr")
(mem:DF (match_dup 0)))]
"RTX_UNCHANGING_P (operands[1]) && reg_unused_after (operands[0], insn)"
"ldd [%0+%%lo(%a1)],%2")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_dup 0)
(match_operand:SI 1 "immediate_operand" "i")))
(set (match_operand:SF 2 "register_operand" "=fr")
(mem:SF (match_dup 0)))]
"RTX_UNCHANGING_P (operands[1]) && reg_unused_after (operands[0], insn)"
"ld [%0+%%lo(%a1)],%2")
;; Return peepholes. First the "normal" ones
(define_insn ""
[(set (match_operand:SI 0 "restore_operand" "")
(match_operand:SI 1 "arith_operand" "rI"))
(return)]
"! TARGET_EPILOGUE"
"ret\;restore %%g0,%1,%Y0"
[(set_attr "type" "multi")])
(define_insn ""
[(set (match_operand:SI 0 "restore_operand" "")
(plus:SI (match_operand:SI 1 "register_operand" "r%")
(match_operand:SI 2 "arith_operand" "rI")))
(return)]
"! TARGET_EPILOGUE"
"ret\;restore %r1,%2,%Y0"
[(set_attr "type" "multi")])
(define_insn ""
[(set (match_operand:SI 0 "restore_operand" "")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "small_int" "I")))
(return)]
"! TARGET_EPILOGUE"
"ret\;restore %1,-(%2),%Y0"
[(set_attr "type" "multi")])
;; The following pattern is only generated by delayed-branch scheduling,
;; when the insn winds up in the epilogue.
(define_insn ""
[(set (reg:SF 32)
(match_operand:SF 0 "register_operand" "f"))
(return)]
"! TARGET_EPILOGUE"
"ret\;fmovs %0,%%f0")
;; Now peepholes to go a call followed by a jump.
(define_peephole
[(parallel [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "call_operand_address" "S,r"))
(match_operand 2 "" "")))
(clobber (reg:SI 15))])
(set (pc) (label_ref (match_operand 3 "" "")))]
"short_branch (INSN_UID (insn), INSN_UID (operands[3]))"
"*
{
if (TARGET_SUN_ASM && GET_CODE (operands[1]) == REG)
return \"jmpl %a1,%%o7\;add %%o7,(%l3-.-4),%%o7\";
else
return \"call %a1,%2\;add %%o7,(%l3-.-4),%%o7\";
}")
(define_peephole
[(parallel [(call (mem:SI (match_operand:SI 0 "call_operand_address" "S,r"))
(match_operand 1 "" ""))
(clobber (reg:SI 15))])
(set (pc) (label_ref (match_operand 2 "" "")))]
"short_branch (INSN_UID (insn), INSN_UID (operands[2]))"
"*
{
if (TARGET_SUN_ASM && GET_CODE (operands[0]) == REG)
return \"jmpl %a0,%%o7\;add %%o7,(%l2-.-4),%%o7\";
else
return \"call %a0,%1\;add %%o7,(%l2-.-4),%%o7\";
}")
(define_peephole
[(parallel [(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
(reg:SI 0)))
(clobber (reg:SI 0))])
(set (reg:SI 0) (compare (match_dup 0) (const_int 0)))]
""
"subxcc %r1,0,%0"
[(set_attr "type" "compare")])
;;- Local variables:
;;- mode:emacs-lisp
;;- comment-start: ";;- "
;;- eval: (set-syntax-table (copy-sequence (syntax-table)))
;;- eval: (modify-syntax-entry ?[ "(]")
;;- eval: (modify-syntax-entry ?] ")[")
;;- eval: (modify-syntax-entry ?{ "(}")
;;- eval: (modify-syntax-entry ?} "){")
;;- End: