8sa1-gcc/gcc/config/pyr/pyr.md
Richard Kenner 8aa9dc6a81 Delete emacs local-variables block at end.
From-SVN: r3342
1993-01-25 18:53:41 -05:00

1405 lines
38 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;; GNU C machine description for Pyramid 90x, 9000, MIServer Series
;; Copyright (C) 1989, 1990 Free Software Foundation, Inc.
;; 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.
;; Instruction patterns. When multiple patterns apply,
;; the first one in the file is chosen.
;;
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;
;; cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
;; updates for most instructions.
;; These comments are mostly obsolete. Written for gcc version 1.XX.
;; * Try using define_insn instead of some peepholes in more places.
;; * Set REG_NOTES:REG_EQUIV for cvt[bh]w loads. This would make the
;; backward scan in sign_extend needless.
;; * Match (pc) (label_ref) case in peephole patterns.
;; * Should optimize
;; "cmpX op1,op2; b{eq,ne} LY; ucmpX op1.op2; b{lt,le,gt,ge} LZ"
;; to
;; "ucmpX op1,op2; b{eq,ne} LY; b{lt,le,gt,ge} LZ"
;; by pre-scanning insn and running notice_update_cc for them.
;; * Is it necessary to do copy_rtx in the test and compare patterns?
;; * Fix true frame pointer omission.
;; * Make the jump tables contain branches, not addresses! This would
;; save us one instruction.
;; * Could the complicated scheme for compares be simplified, if we had
;; no named cmpqi or cmphi patterns, and instead anonymous patterns for
;; the less-than-word compare cases pyr can handle???
;; * The jump insn seems to accept more than just IR addressing. Would
;; we win by telling GCC? Or can we use movw into the global reg which
;; is a synonym for pc?
;; * More DImode patterns.
;; * Scan backwards in "zero_extendhisi2", "zero_extendqisi2" to find out
;; if the extension can be omitted.
;; * "divmodsi" with Pyramid "ediv" insn. Is it possible in rtl??
;; * Would "rcsp tmpreg; u?cmp[bh] op1_regdispl(tmpreg),op2" win in
;; comparison with the two extensions and single test generated now?
;; The rcsp insn could be expanded, and moved out of loops by the
;; optimizer, making 1 (64 bit) insn of 3 (32 bit) insns in loops.
;; The rcsp insn could be followed by an add insn, making non-displacement
;; IR addressing sufficient.
;______________________________________________________________________
;
; Test and Compare Patterns.
;______________________________________________________________________
; The argument for the rather complicated test and compare expansion
; scheme, is the irregular pyramid instructions for these operations.
; 1) Pyramid has different signed and unsigned compares. 2) HImode
; and QImode integers are memory-memory and immediate-memory only. 3)
; Unsigned HImode compares doesn't exist. 4) Only certain
; combinations of addresses are allowed for memory-memory compares.
; Whenever necessary, in order to fulfill these addressing
; constraints, the compare operands are swapped.
(define_expand "tstsi"
[(set (cc0)
(match_operand:SI 0 "general_operand" ""))]
"" "operands[0] = force_reg (SImode, operands[0]);")
(define_insn ""
[(set (cc0)
(compare (match_operand:SI 0 "memory_operand" "m")
(match_operand:SI 1 "memory_operand" "m")))]
"weird_memory_memory (operands[0], operands[1])"
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
weird_memory_memory (operands[0], operands[1]);
if (swap_operands)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %0,%1\";
}
return \"cmpw %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %1,%0\";
}
return \"cmpw %1,%0\";
}")
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "nonimmediate_operand" "r,g")
(match_operand:SI 1 "general_operand" "g,r")))]
""
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
if (which_alternative != 0)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %0,%1\";
}
return \"cmpw %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %1,%0\";
}
return \"cmpw %1,%0\";
}")
(define_insn ""
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "r"))]
""
"*
{
#if 0
cc_status.flags |= CC_NO_OVERFLOW;
return \"cmpw $0,%0\";
#endif
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw $0,%0\";
}
return \"mtstw %0,%0\";
}")
(define_expand "cmphi"
[(set (cc0)
(compare (match_operand:HI 0 "nonimmediate_operand" "")
(match_operand:HI 1 "general_operand" "")))]
""
"
{
extern rtx test_op0, test_op1; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_op1 = copy_rtx (operands[1]);
test_mode = HImode;
DONE;
}")
(define_expand "tsthi"
[(set (cc0)
(match_operand:HI 0 "nonimmediate_operand" ""))]
""
"
{
extern rtx test_op0; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_mode = HImode;
DONE;
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:HI 0 "memory_operand" "m")
(match_operand:HI 1 "memory_operand" "m")))]
"(!TRULY_UNSIGNED_COMPARE_P (GET_CODE (XEXP (SET_SRC (PATTERN (NEXT_INSN (insn))), 0))))
&& weird_memory_memory (operands[0], operands[1])"
"*
{
rtx br_insn = NEXT_INSN (insn);
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
weird_memory_memory (operands[0], operands[1]);
if (swap_operands)
{
cc_status.flags = CC_REVERSED;
return \"cmph %0,%1\";
}
return \"cmph %1,%0\";
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:HI 0 "nonimmediate_operand" "r,m")
(match_operand:HI 1 "nonimmediate_operand" "m,r")))]
"(!TRULY_UNSIGNED_COMPARE_P (GET_CODE (XEXP (SET_SRC (PATTERN (NEXT_INSN (insn))), 0))))
&& (GET_CODE (operands[0]) != GET_CODE (operands[1]))"
"*
{
rtx br_insn = NEXT_INSN (insn);
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
if (which_alternative != 0)
{
cc_status.flags = CC_REVERSED;
return \"cmph %0,%1\";
}
return \"cmph %1,%0\";
}")
(define_expand "cmpqi"
[(set (cc0)
(compare (match_operand:QI 0 "nonimmediate_operand" "")
(match_operand:QI 1 "general_operand" "")))]
""
"
{
extern rtx test_op0, test_op1; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_op1 = copy_rtx (operands[1]);
test_mode = QImode;
DONE;
}")
(define_expand "tstqi"
[(set (cc0)
(match_operand:QI 0 "nonimmediate_operand" ""))]
""
"
{
extern rtx test_op0; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_mode = QImode;
DONE;
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:QI 0 "memory_operand" "m")
(match_operand:QI 1 "memory_operand" "m")))]
"weird_memory_memory (operands[0], operands[1])"
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
weird_memory_memory (operands[0], operands[1]);
if (swap_operands)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %0,%1\";
}
return \"cmpb %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %1,%0\";
}
return \"cmpb %1,%0\";
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:QI 0 "nonimmediate_operand" "r,m")
(match_operand:QI 1 "nonimmediate_operand" "m,r")))]
"(GET_CODE (operands[0]) != GET_CODE (operands[1]))"
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
if (which_alternative != 0)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %0,%1\";
}
return \"cmpb %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %1,%0\";
}
return \"cmpb %1,%0\";
}")
(define_expand "bgt"
[(set (pc) (if_then_else (gt (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "blt"
[(set (pc) (if_then_else (lt (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "bge"
[(set (pc) (if_then_else (ge (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "ble"
[(set (pc) (if_then_else (le (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "beq"
[(set (pc) (if_then_else (eq (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "bne"
[(set (pc) (if_then_else (ne (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "bgtu"
[(set (pc) (if_then_else (gtu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_expand "bltu"
[(set (pc) (if_then_else (ltu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_expand "bgeu"
[(set (pc) (if_then_else (geu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_expand "bleu"
[(set (pc) (if_then_else (leu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_insn "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "register_operand" "r")
(match_operand:DF 1 "register_operand" "r")))]
""
"cmpd %1,%0")
(define_insn "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
""
"cmpf %1,%0")
(define_insn "tstdf"
[(set (cc0)
(match_operand:DF 0 "register_operand" "r"))]
""
"mtstd %0,%0")
(define_insn "tstsf"
[(set (cc0)
(match_operand:SF 0 "register_operand" "r"))]
""
"mtstf %0,%0")
;______________________________________________________________________
;
; Fixed-point Arithmetic.
;______________________________________________________________________
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,!r")
(plus:SI (match_operand:SI 1 "general_operand" "%0,r")
(match_operand:SI 2 "general_operand" "g,rJ")))]
""
"*
{
if (which_alternative == 0)
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 32
? \"subw %n2,%0\" : \"addw %2,%0\");
else
{
forget_cc_if_dependent (operands[0]);
return \"mova %a2[%1*1],%0\";
}
}")
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(minus:SI (match_operand:SI 1 "general_operand" "0,g")
(match_operand:SI 2 "general_operand" "g,0")))]
""
"* return (which_alternative == 0) ? \"subw %2,%0\" : \"rsubw %1,%0\";")
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(mult:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))]
""
"mulw %2,%0")
(define_insn "divsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(div:SI (match_operand:SI 1 "general_operand" "0,g")
(match_operand:SI 2 "general_operand" "g,0")))]
""
"* return (which_alternative == 0) ? \"divw %2,%0\" : \"rdivw %1,%0\";")
(define_insn "udivsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(udiv:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "g")))]
""
"udivw %2,%0")
(define_insn "modsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(mod:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "g")))]
""
"modw %2,%0")
(define_insn "umodsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(umod:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "g")))]
""
"umodw %2,%0")
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"mnegw %1,%0")
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"mcomw %1,%0")
(define_insn "abssi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(abs:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"mabsw %1,%0")
;______________________________________________________________________
;
; Floating-point Arithmetic.
;______________________________________________________________________
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(plus:DF (match_operand:DF 1 "register_operand" "%0")
(match_operand:DF 2 "register_operand" "r")))]
""
"addd %2,%0")
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(plus:SF (match_operand:SF 1 "register_operand" "%0")
(match_operand:SF 2 "register_operand" "r")))]
""
"addf %2,%0")
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(minus:DF (match_operand:DF 1 "register_operand" "0")
(match_operand:DF 2 "register_operand" "r")))]
""
"subd %2,%0")
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(minus:SF (match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "register_operand" "r")))]
""
"subf %2,%0")
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(mult:DF (match_operand:DF 1 "register_operand" "%0")
(match_operand:DF 2 "register_operand" "r")))]
""
"muld %2,%0")
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(mult:SF (match_operand:SF 1 "register_operand" "%0")
(match_operand:SF 2 "register_operand" "r")))]
""
"mulf %2,%0")
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(div:DF (match_operand:DF 1 "register_operand" "0")
(match_operand:DF 2 "register_operand" "r")))]
""
"divd %2,%0")
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(div:SF (match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "register_operand" "r")))]
""
"divf %2,%0")
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=r")
(neg:DF (match_operand:DF 1 "register_operand" "r")))]
""
"mnegd %1,%0")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(neg:SF (match_operand:SF 1 "register_operand" "r")))]
""
"mnegf %1,%0")
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=r")
(abs:DF (match_operand:DF 1 "register_operand" "r")))]
""
"mabsd %1,%0")
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(abs:SF (match_operand:SF 1 "register_operand" "r")))]
""
"mabsf %1,%0")
;______________________________________________________________________
;
; Logical and Shift Instructions.
;______________________________________________________________________
(define_insn ""
[(set (cc0)
(and:SI (match_operand:SI 0 "general_operand" "%r")
(match_operand:SI 1 "general_operand" "g")))]
""
"*
{
cc_status.flags |= CC_NO_OVERFLOW;
return \"bitw %1,%0\";
}")
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(and:SI (match_operand:SI 1 "general_operand" "%0,r")
(match_operand:SI 2 "general_operand" "g,K")))]
""
"*
{
if (which_alternative == 0)
return \"andw %2,%0\";
cc_status.flags = CC_NOT_NEGATIVE;
return (INTVAL (operands[2]) == 255
? \"movzbw %1,%0\" : \"movzhw %1,%0\");
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (not:SI (match_operand:SI 1 "general_operand" "g"))
(match_operand:SI 2 "register_operand" "0")))]
""
"bicw %1,%0")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))]
""
"orw %2,%0")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(xor:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))]
""
"xorw %2,%0")
; The arithmetic left shift instructions work strangely on pyramids.
; They fail to modify the sign bit. Therefore, use logic shifts.
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"lshlw %2,%0\", operands[2], 32);
}")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"ashrw %2,%0\", operands[2], 32);
}")
(define_insn "ashrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"ashrl %2,%0\", operands[2], 64);
}")
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"lshrw %2,%0\", operands[2], 32);
}")
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotate:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"rotlw %2,%0\", operands[2], 32);
}")
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotatert:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"rotrw %2,%0\", operands[2], 32);
}")
;______________________________________________________________________
;
; Fixed and Floating Moves.
;______________________________________________________________________
;; If the destination is a memory operand, indexed source operands are
;; disallowed. Big DImode constants are always loaded into a reg pair,
;; although offsettable memory addresses really could be dealt with.
(define_insn ""
[(set (match_operand:DI 0 "memory_operand" "=m")
(match_operand:DI 1 "nonindexed_operand" "gF"))]
"(GET_CODE (operands[1]) == CONST_DOUBLE
? ((CONST_DOUBLE_HIGH (operands[1]) == 0
&& CONST_DOUBLE_LOW (operands[1]) >= 0)
|| (CONST_DOUBLE_HIGH (operands[1]) == -1
&& CONST_DOUBLE_LOW (operands[1]) < 0))
: 1)"
"*
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
operands[1] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_LOW (operands[1]));
return \"movl %1,%0\";
}")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=r")
(match_operand:DI 1 "general_operand" "gF"))]
""
"*
{
extern char *output_move_double ();
return output_move_double (operands);
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:SI 0 "memory_operand" "=m")
(match_operand:SI 1 "nonindexed_operand" "g"))]
""
"movw %1,%0")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=r")
(match_operand:SI 1 "general_operand" "g"))]
""
"movw %1,%0")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:HI 0 "memory_operand" "=m")
(match_operand:HI 1 "nonindexed_operand" "g"))]
""
"*
{
if (REG_P (operands[1]))
return \"cvtwh %1,%0\"; /* reg -> mem */
else
return \"movh %1,%0\"; /* mem imm -> mem */
}")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movhi"
[(set (match_operand:HI 0 "general_operand" "=r")
(match_operand:HI 1 "general_operand" "g"))]
""
"*
{
if (GET_CODE (operands[1]) != MEM)
return \"movw %1,%0\"; /* reg imm -> reg */
return \"cvthw %1,%0\"; /* mem -> reg */
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:QI 0 "memory_operand" "=m")
(match_operand:QI 1 "nonindexed_operand" "g"))]
""
"*
{
if (REG_P (operands[1]))
return \"cvtwb %1,%0\"; /* reg -> mem */
else
return \"movb %1,%0\"; /* mem imm -> mem */
}")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=r")
(match_operand:QI 1 "general_operand" "g"))]
""
"*
{
if (GET_CODE (operands[1]) != MEM)
return \"movw %1,%0\"; /* reg imm -> reg */
return \"cvtbw %1,%0\"; /* mem -> reg */
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:DF 0 "memory_operand" "=m")
(match_operand:DF 1 "nonindexed_operand" "g"))]
"GET_CODE (operands[1]) != CONST_DOUBLE"
"movl %1,%0")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=r")
(match_operand:DF 1 "general_operand" "gF"))]
""
"*
{
extern char *output_move_double ();
return output_move_double (operands);
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:SF 0 "memory_operand" "=m")
(match_operand:SF 1 "nonindexed_operand" "g"))]
""
"movw %1,%0")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=r")
(match_operand:SF 1 "general_operand" "g"))]
""
"movw %1,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:QI 1 "address_operand" "p"))]
""
"*
{
forget_cc_if_dependent (operands[0]);
return \"mova %a1,%0\";
}")
;______________________________________________________________________
;
; Conversion patterns.
;______________________________________________________________________
;; The trunc patterns are used only when non compile-time constants are used.
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"*
{
if (REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1]))
{
cc_status = cc_prev_status;
return \"\";
}
forget_cc_if_dependent (operands[0]);
return \"movw %1,%0\";
}")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"*
{
if (REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1]))
{
cc_status = cc_prev_status;
return \"\";
}
forget_cc_if_dependent (operands[0]);
return \"movw %1,%0\";
}")
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=r,m")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))]
""
"*
{
extern int optimize;
if (optimize && REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1])
&& already_sign_extended (insn, HImode, operands[0]))
{
cc_status = cc_prev_status;
return \"\";
}
return \"cvthw %1,%0\";
}")
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=r,m")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm,r")))]
""
"*
{
extern int optimize;
if (optimize && REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1])
&& already_sign_extended (insn, QImode, operands[0]))
{
cc_status = cc_prev_status;
return \"\";
}
return \"cvtbw %1,%0\";
}")
; Pyramid doesn't have insns *called* "cvtbh" or "movzbh".
; But we can cvtbw/movzbw into a register, where there is no distinction
; between words and halfwords.
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"cvtbw %1,%0")
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
""
"*
{
cc_status.flags = CC_NOT_NEGATIVE;
return \"movzhw %1,%0\";
}")
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"*
{
cc_status.flags = CC_NOT_NEGATIVE;
return \"movzbw %1,%0\";
}")
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"*
{
cc_status.flags = CC_NOT_NEGATIVE;
return \"movzbw %1,%0\";
}")
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "general_operand" "=&r,m")
(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "rm,r")))]
""
"cvtfd %1,%0")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "general_operand" "=&r,m")
(float_truncate:SF (match_operand:DF 1 "nonimmediate_operand" "rm,r")))]
""
"cvtdf %1,%0")
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "general_operand" "=&r,m")
(float:SF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))]
""
"cvtwf %1,%0")
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "general_operand" "=&r,m")
(float:DF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))]
""
"cvtwd %1,%0")
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "general_operand" "=&r,m")
(fix:SI (fix:SF (match_operand:SF 1 "nonimmediate_operand" "rm,r"))))]
""
"cvtfw %1,%0")
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=&r,m")
(fix:SI (fix:DF (match_operand:DF 1 "nonimmediate_operand" "rm,r"))))]
""
"cvtdw %1,%0")
;______________________________________________________________________
;
; Flow Control Patterns.
;______________________________________________________________________
;; Prefer "br" to "jump" for unconditional jumps, since it's faster.
;; (The assembler can manage with out-of-range branches.)
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"br %l0")
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
""
"*
{
extern int optimize;
if (optimize)
switch (GET_CODE (operands[0]))
{
case EQ: case NE:
break;
case LT: case LE: case GE: case GT:
if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED)
return 0;
break;
case LTU: case LEU: case GEU: case GTU:
if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED)
return 0;
break;
}
return \"b%N0 %l1\";
}")
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
""
"*
{
extern int optimize;
if (optimize)
switch (GET_CODE (operands[0]))
{
case EQ: case NE:
break;
case LT: case LE: case GE: case GT:
if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED)
return 0;
break;
case LTU: case LEU: case GEU: case GTU:
if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED)
return 0;
break;
}
return \"b%C0 %l1\";
}")
(define_insn "call"
[(call (match_operand:QI 0 "memory_operand" "m")
(match_operand:SI 1 "immediate_operand" "n"))]
""
"call %0")
(define_insn "call_value"
[(set (match_operand 0 "" "=r")
(call (match_operand:QI 1 "memory_operand" "m")
(match_operand:SI 2 "immediate_operand" "n")))]
;; Operand 2 not really used on Pyramid architecture.
""
"call %1")
(define_insn "return"
[(return)]
""
"*
{
if (get_frame_size () + current_function_pretend_args_size
+ current_function_args_size != 0
|| current_function_calls_alloca)
{
int dealloc_size = current_function_pretend_args_size;
if (current_function_pops_args)
dealloc_size += current_function_args_size;
operands[0] = gen_rtx (CONST_INT, VOIDmode, dealloc_size);
return \"retd %0\";
}
else
return \"ret\";
}")
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"jump (%0)")
(define_insn "nop"
[(const_int 0)]
""
"movw gr0,gr0 # nop")
;______________________________________________________________________
;
; Peep-hole Optimization Patterns.
;______________________________________________________________________
;; Optimize fullword move followed by a test of the moved value.
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "nonimmediate_operand" "rm"))
(set (cc0) (match_operand:SI 2 "nonimmediate_operand" "rm"))]
"rtx_equal_p (operands[2], operands[0])
|| rtx_equal_p (operands[2], operands[1])"
"*
cc_status.flags |= CC_NO_OVERFLOW;
return \"mtstw %1,%0\";
")
;; Same for HI and QI mode move-test as well.
(define_peephole
[(set (match_operand:HI 0 "register_operand" "=r")
(match_operand:HI 1 "nonimmediate_operand" "rm"))
(set (match_operand:SI 2 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 3 "nonimmediate_operand" "rm")))
(set (cc0) (match_dup 2))]
"dead_or_set_p (insn, operands[2])
&& (rtx_equal_p (operands[3], operands[0])
|| rtx_equal_p (operands[3], operands[1]))"
"*
cc_status.flags |= CC_NO_OVERFLOW;
return \"cvthw %1,%0\";
")
(define_peephole
[(set (match_operand:QI 0 "register_operand" "=r")
(match_operand:QI 1 "nonimmediate_operand" "rm"))
(set (match_operand:SI 2 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 3 "nonimmediate_operand" "rm")))
(set (cc0) (match_dup 2))]
"dead_or_set_p (insn, operands[2])
&& (rtx_equal_p (operands[3], operands[0])
|| rtx_equal_p (operands[3], operands[1]))"
"*
cc_status.flags |= CC_NO_OVERFLOW;
return \"cvtbw %1,%0\";
")
;; Optimize loops with an incremented/decremented variable.
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0)
(const_int -1)))
(set (cc0)
(compare (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "nonmemory_operand" "ri")))
(set (pc)
(if_then_else (match_operator:SI 3 "signed_comparison"
[(cc0) (const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))]
"(GET_CODE (operands[2]) == CONST_INT
? (unsigned)INTVAL (operands[2]) + 32 >= 64
: 1) && (rtx_equal_p (operands[0], operands[1])
|| rtx_equal_p (operands[0], operands[2]))"
"*
if (rtx_equal_p (operands[0], operands[1]))
{
output_asm_insn (\"dcmpw %2,%0\", operands);
return \"b%N3 %l4\";
}
else
{
output_asm_insn (\"dcmpw %1,%0\", operands);
return \"b%R3 %l4\";
}
")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0)
(const_int 1)))
(set (cc0)
(compare (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "nonmemory_operand" "ri")))
(set (pc)
(if_then_else (match_operator:SI 3 "signed_comparison"
[(cc0) (const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))]
"(GET_CODE (operands[2]) == CONST_INT
? (unsigned)INTVAL (operands[2]) + 32 >= 64
: 1) && (rtx_equal_p (operands[0], operands[1])
|| rtx_equal_p (operands[0], operands[2]))"
"*
if (rtx_equal_p (operands[0], operands[1]))
{
output_asm_insn (\"icmpw %2,%0\", operands);
return \"b%N3 %l4\";
}
else
{
output_asm_insn (\"icmpw %1,%0\", operands);
return \"b%R3 %l4\";
}
")
;; Combine two word moves with consecutive operands into one long move.
;; Also combines immediate moves, if the high-order destination operand
;; is loaded with 0 or -1 and the low-order destination operand is loaded
;; with a constant with the same sign.
(define_peephole
[(set (match_operand:SI 0 "general_operand" "=g")
(match_operand:SI 1 "general_operand" "g"))
(set (match_operand:SI 2 "general_operand" "=g")
(match_operand:SI 3 "general_operand" "g"))]
"movdi_possible (operands)"
"*
{
output_asm_insn (\"# COMBINE movw %1,%0\", operands);
output_asm_insn (\"# COMBINE movw %3,%2\", operands);
movdi_possible (operands);
if (CONSTANT_P (operands[1]))
return (swap_operands ? \"movl %3,%0\" : \"movl %1,%2\");
return (swap_operands ? \"movl %1,%0\" : \"movl %3,%2\");
}")
;; Optimize certain tests after memory stores.
(define_peephole
[(set (match_operand 0 "memory_operand" "=m")
(match_operand 1 "register_operand" "r"))
(set (match_operand:SI 2 "register_operand" "=r")
(sign_extend:SI (match_dup 1)))
(set (cc0)
(match_dup 2))]
"dead_or_set_p (insn, operands[2])"
"*
cc_status.flags |= CC_NO_OVERFLOW;
if (GET_MODE (operands[0]) == QImode)
return \"cvtwb %1,%0\";
else
return \"cvtwh %1,%0\";
")
;______________________________________________________________________
;
; DImode Patterns.
;______________________________________________________________________
(define_expand "extendsidi2"
[(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1)
(match_operand:SI 1 "general_operand" "g"))
(set (subreg:SI (match_dup 0) 0)
(subreg:SI (match_dup 0) 1))
(set (subreg:SI (match_dup 0) 0)
(ashiftrt:SI (subreg:SI (match_dup 0) 0)
(const_int 31)))]
""
"")
(define_insn "adddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_LOW (operands[2]));
operands[2] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"addw %1,%0\", xoperands);
return \"addwc %2,%0\";
}")
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_LOW (operands[2]));
operands[2] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"subw %1,%0\", xoperands);
return \"subwb %2,%0\";
}")
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_LOW (operands[2]));
operands[2] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"orw %1,%0\", xoperands);
return \"orw %2,%0\";
}")
(define_insn "anddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_LOW (operands[2]));
operands[2] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"andw %1,%0\", xoperands);
return \"andw %2,%0\";
}")
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(xor:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_LOW (operands[2]));
operands[2] = gen_rtx (CONST_INT, VOIDmode,
CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"xorw %1,%0\", xoperands);
return \"xorw %2,%0\";
}")
;; My version, modelled after Jonathan Stone's and "tablejump" - S.P.
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "general_operand" "r"))]
""
"jump (%0)")