;; GCC machine description for MMIX
|
;; GCC machine description for MMIX
|
;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
;; Free Software Foundation, Inc.
|
;; Free Software Foundation, Inc.
|
;; Contributed by Hans-Peter Nilsson (hp@bitrange.com)
|
;; Contributed by Hans-Peter Nilsson (hp@bitrange.com)
|
|
|
;; This file is part of GCC.
|
;; This file is part of GCC.
|
|
|
;; GCC is free software; you can redistribute it and/or modify
|
;; GCC is free software; you can redistribute it and/or modify
|
;; it under the terms of the GNU General Public License as published by
|
;; it under the terms of the GNU General Public License as published by
|
;; the Free Software Foundation; either version 3, or (at your option)
|
;; the Free Software Foundation; either version 3, or (at your option)
|
;; any later version.
|
;; any later version.
|
|
|
;; GCC is distributed in the hope that it will be useful,
|
;; GCC is distributed in the hope that it will be useful,
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
;; GNU General Public License for more details.
|
;; GNU General Public License for more details.
|
|
|
;; You should have received a copy of the GNU General Public License
|
;; You should have received a copy of the GNU General Public License
|
;; along with GCC; see the file COPYING3. If not see
|
;; along with GCC; see the file COPYING3. If not see
|
;; .
|
;; .
|
|
|
;; The original PO technology requires these to be ordered by speed,
|
;; The original PO technology requires these to be ordered by speed,
|
;; so that assigner will pick the fastest.
|
;; so that assigner will pick the fastest.
|
|
|
;; See file "rtl.def" for documentation on define_insn, match_*, et al.
|
;; See file "rtl.def" for documentation on define_insn, match_*, et al.
|
|
|
;; Uses of UNSPEC in this file:
|
;; Uses of UNSPEC in this file:
|
;; UNSPEC_VOLATILE:
|
;; UNSPEC_VOLATILE:
|
;;
|
;;
|
;; 0 sync_icache (sync icache before trampoline jump)
|
;; 0 sync_icache (sync icache before trampoline jump)
|
;; 1 nonlocal_goto_receiver
|
;; 1 nonlocal_goto_receiver
|
;;
|
;;
|
|
|
;; The order of insns is as in Node: Standard Names, with smaller modes
|
;; The order of insns is as in Node: Standard Names, with smaller modes
|
;; before bigger modes.
|
;; before bigger modes.
|
|
|
(define_constants
|
(define_constants
|
[(MMIX_rJ_REGNUM 259)
|
[(MMIX_rJ_REGNUM 259)
|
(MMIX_rR_REGNUM 260)
|
(MMIX_rR_REGNUM 260)
|
(MMIX_fp_rO_OFFSET -24)]
|
(MMIX_fp_rO_OFFSET -24)]
|
)
|
)
|
|
|
;; Operand and operator predicates.
|
;; Operand and operator predicates.
|
|
|
(include "predicates.md")
|
(include "predicates.md")
|
|
|
;; FIXME: Can we remove the reg-to-reg for smaller modes? Shouldn't they
|
;; FIXME: Can we remove the reg-to-reg for smaller modes? Shouldn't they
|
;; be synthesized ok?
|
;; be synthesized ok?
|
(define_insn "movqi"
|
(define_insn "movqi"
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r ,r,x ,r,r,m,??r")
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r ,r,x ,r,r,m,??r")
|
(match_operand:QI 1 "general_operand" "r,LS,K,rI,x,m,r,n"))]
|
(match_operand:QI 1 "general_operand" "r,LS,K,rI,x,m,r,n"))]
|
""
|
""
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
%s1 %0,%v1
|
%s1 %0,%v1
|
NEGU %0,0,%n1
|
NEGU %0,0,%n1
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
LDB%U0 %0,%1
|
LDB%U0 %0,%1
|
STBU %1,%0
|
STBU %1,%0
|
%r0%I1")
|
%r0%I1")
|
|
|
(define_insn "movhi"
|
(define_insn "movhi"
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r ,r ,x,r,r,m,??r")
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r ,r ,x,r,r,m,??r")
|
(match_operand:HI 1 "general_operand" "r,LS,K,r,x,m,r,n"))]
|
(match_operand:HI 1 "general_operand" "r,LS,K,r,x,m,r,n"))]
|
""
|
""
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
%s1 %0,%v1
|
%s1 %0,%v1
|
NEGU %0,0,%n1
|
NEGU %0,0,%n1
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
LDW%U0 %0,%1
|
LDW%U0 %0,%1
|
STWU %1,%0
|
STWU %1,%0
|
%r0%I1")
|
%r0%I1")
|
|
|
;; gcc.c-torture/compile/920428-2.c fails if there's no "n".
|
;; gcc.c-torture/compile/920428-2.c fails if there's no "n".
|
(define_insn "movsi"
|
(define_insn "movsi"
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r ,r,x,r,r,m,??r")
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r ,r,x,r,r,m,??r")
|
(match_operand:SI 1 "general_operand" "r,LS,K,r,x,m,r,n"))]
|
(match_operand:SI 1 "general_operand" "r,LS,K,r,x,m,r,n"))]
|
""
|
""
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
%s1 %0,%v1
|
%s1 %0,%v1
|
NEGU %0,0,%n1
|
NEGU %0,0,%n1
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
LDT%U0 %0,%1
|
LDT%U0 %0,%1
|
STTU %1,%0
|
STTU %1,%0
|
%r0%I1")
|
%r0%I1")
|
|
|
;; We assume all "s" are addresses. Does that hold?
|
;; We assume all "s" are addresses. Does that hold?
|
(define_insn "movdi"
|
(define_insn "movdi"
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r ,r,x,r,m,r,m,r,r,??r")
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r ,r,x,r,m,r,m,r,r,??r")
|
(match_operand:DI 1 "general_operand" "r,LS,K,r,x,I,m,r,R,s,n"))]
|
(match_operand:DI 1 "general_operand" "r,LS,K,r,x,I,m,r,R,s,n"))]
|
""
|
""
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
%s1 %0,%v1
|
%s1 %0,%v1
|
NEGU %0,0,%n1
|
NEGU %0,0,%n1
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
STCO %1,%0
|
STCO %1,%0
|
LDO %0,%1
|
LDO %0,%1
|
STOU %1,%0
|
STOU %1,%0
|
GETA %0,%1
|
GETA %0,%1
|
LDA %0,%1
|
LDA %0,%1
|
%r0%I1")
|
%r0%I1")
|
|
|
;; Note that we move around the float as a collection of bits; no
|
;; Note that we move around the float as a collection of bits; no
|
;; conversion to double.
|
;; conversion to double.
|
(define_insn "movsf"
|
(define_insn "movsf"
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r")
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r")
|
(match_operand:SF 1 "general_operand" "r,G,r,x,m,r,F"))]
|
(match_operand:SF 1 "general_operand" "r,G,r,x,m,r,F"))]
|
""
|
""
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
SETL %0,0
|
SETL %0,0
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
LDT %0,%1
|
LDT %0,%1
|
STTU %1,%0
|
STTU %1,%0
|
%r0%I1")
|
%r0%I1")
|
|
|
(define_insn "movdf"
|
(define_insn "movdf"
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r")
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r")
|
(match_operand:DF 1 "general_operand" "r,G,r,x,m,r,F"))]
|
(match_operand:DF 1 "general_operand" "r,G,r,x,m,r,F"))]
|
""
|
""
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
SETL %0,0
|
SETL %0,0
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
LDO %0,%1
|
LDO %0,%1
|
STOU %1,%0
|
STOU %1,%0
|
%r0%I1")
|
%r0%I1")
|
|
|
;; We need to be able to move around the values used as condition codes.
|
;; We need to be able to move around the values used as condition codes.
|
;; First spotted as reported in
|
;; First spotted as reported in
|
;; due to
|
;; due to
|
;; changes in loop optimization. The file machmode.def says they're of
|
;; changes in loop optimization. The file machmode.def says they're of
|
;; size 4 QI. Valid bit-patterns correspond to integers -1, 0 and 1, so
|
;; size 4 QI. Valid bit-patterns correspond to integers -1, 0 and 1, so
|
;; we treat them as signed entities; see mmix-modes.def. The following
|
;; we treat them as signed entities; see mmix-modes.def. The following
|
;; expanders should cover all MODE_CC modes, and expand for this pattern.
|
;; expanders should cover all MODE_CC modes, and expand for this pattern.
|
(define_insn "*movcc_expanded"
|
(define_insn "*movcc_expanded"
|
[(set (match_operand 0 "nonimmediate_operand" "=r,x,r,r,m")
|
[(set (match_operand 0 "nonimmediate_operand" "=r,x,r,r,m")
|
(match_operand 1 "nonimmediate_operand" "r,r,x,m,r"))]
|
(match_operand 1 "nonimmediate_operand" "r,r,x,m,r"))]
|
"GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_CC
|
"GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_CC
|
&& GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_CC"
|
&& GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_CC"
|
"@
|
"@
|
SET %0,%1
|
SET %0,%1
|
PUT %0,%1
|
PUT %0,%1
|
GET %0,%1
|
GET %0,%1
|
LDT %0,%1
|
LDT %0,%1
|
STT %1,%0")
|
STT %1,%0")
|
|
|
(define_expand "movcc"
|
(define_expand "movcc"
|
[(set (match_operand:CC 0 "nonimmediate_operand" "")
|
[(set (match_operand:CC 0 "nonimmediate_operand" "")
|
(match_operand:CC 1 "nonimmediate_operand" ""))]
|
(match_operand:CC 1 "nonimmediate_operand" ""))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_expand "movcc_uns"
|
(define_expand "movcc_uns"
|
[(set (match_operand:CC_UNS 0 "nonimmediate_operand" "")
|
[(set (match_operand:CC_UNS 0 "nonimmediate_operand" "")
|
(match_operand:CC_UNS 1 "nonimmediate_operand" ""))]
|
(match_operand:CC_UNS 1 "nonimmediate_operand" ""))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_expand "movcc_fp"
|
(define_expand "movcc_fp"
|
[(set (match_operand:CC_FP 0 "nonimmediate_operand" "")
|
[(set (match_operand:CC_FP 0 "nonimmediate_operand" "")
|
(match_operand:CC_FP 1 "nonimmediate_operand" ""))]
|
(match_operand:CC_FP 1 "nonimmediate_operand" ""))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_expand "movcc_fpeq"
|
(define_expand "movcc_fpeq"
|
[(set (match_operand:CC_FPEQ 0 "nonimmediate_operand" "")
|
[(set (match_operand:CC_FPEQ 0 "nonimmediate_operand" "")
|
(match_operand:CC_FPEQ 1 "nonimmediate_operand" ""))]
|
(match_operand:CC_FPEQ 1 "nonimmediate_operand" ""))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_expand "movcc_fun"
|
(define_expand "movcc_fun"
|
[(set (match_operand:CC_FUN 0 "nonimmediate_operand" "")
|
[(set (match_operand:CC_FUN 0 "nonimmediate_operand" "")
|
(match_operand:CC_FUN 1 "nonimmediate_operand" ""))]
|
(match_operand:CC_FUN 1 "nonimmediate_operand" ""))]
|
""
|
""
|
"")
|
"")
|
|
|
(define_insn "adddi3"
|
(define_insn "adddi3"
|
[(set (match_operand:DI 0 "register_operand" "=r,r,r")
|
[(set (match_operand:DI 0 "register_operand" "=r,r,r")
|
(plus:DI
|
(plus:DI
|
(match_operand:DI 1 "register_operand" "%r,r,0")
|
(match_operand:DI 1 "register_operand" "%r,r,0")
|
(match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,K,LS")))]
|
(match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,K,LS")))]
|
""
|
""
|
"@
|
"@
|
ADDU %0,%1,%2
|
ADDU %0,%1,%2
|
SUBU %0,%1,%n2
|
SUBU %0,%1,%n2
|
%i2 %0,%v2")
|
%i2 %0,%v2")
|
|
|
(define_insn "adddf3"
|
(define_insn "adddf3"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(plus:DF (match_operand:DF 1 "register_operand" "%r")
|
(plus:DF (match_operand:DF 1 "register_operand" "%r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FADD %0,%1,%2")
|
"FADD %0,%1,%2")
|
|
|
;; Insn canonicalization *should* have removed the need for an integer
|
;; Insn canonicalization *should* have removed the need for an integer
|
;; in operand 2.
|
;; in operand 2.
|
(define_insn "subdi3"
|
(define_insn "subdi3"
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
(minus:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "r,I")
|
(minus:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "r,I")
|
(match_operand:DI 2 "register_operand" "r,r")))]
|
(match_operand:DI 2 "register_operand" "r,r")))]
|
""
|
""
|
"@
|
"@
|
SUBU %0,%1,%2
|
SUBU %0,%1,%2
|
NEGU %0,%1,%2")
|
NEGU %0,%1,%2")
|
|
|
(define_insn "subdf3"
|
(define_insn "subdf3"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(minus:DF (match_operand:DF 1 "register_operand" "r")
|
(minus:DF (match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FSUB %0,%1,%2")
|
"FSUB %0,%1,%2")
|
|
|
;; FIXME: Should we define_expand and match 2, 4, 8 (etc) with shift (or
|
;; FIXME: Should we define_expand and match 2, 4, 8 (etc) with shift (or
|
;; %{something}2ADDU %0,%1,0)? Hopefully GCC should still handle it, so
|
;; %{something}2ADDU %0,%1,0)? Hopefully GCC should still handle it, so
|
;; we don't have to taint the machine description. If results are bad
|
;; we don't have to taint the machine description. If results are bad
|
;; enough, we may have to do it anyway.
|
;; enough, we may have to do it anyway.
|
(define_insn "muldi3"
|
(define_insn "muldi3"
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
(mult:DI (match_operand:DI 1 "register_operand" "%r,r")
|
(mult:DI (match_operand:DI 1 "register_operand" "%r,r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "O,rI")))
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "O,rI")))
|
(clobber (match_scratch:DI 3 "=X,z"))]
|
(clobber (match_scratch:DI 3 "=X,z"))]
|
""
|
""
|
"@
|
"@
|
%m2ADDU %0,%1,%1
|
%m2ADDU %0,%1,%1
|
MULU %0,%1,%2")
|
MULU %0,%1,%2")
|
|
|
(define_insn "muldf3"
|
(define_insn "muldf3"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(mult:DF (match_operand:DF 1 "register_operand" "r")
|
(mult:DF (match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FMUL %0,%1,%2")
|
"FMUL %0,%1,%2")
|
|
|
(define_insn "divdf3"
|
(define_insn "divdf3"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(div:DF (match_operand:DF 1 "register_operand" "r")
|
(div:DF (match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FDIV %0,%1,%2")
|
"FDIV %0,%1,%2")
|
|
|
;; FIXME: Is "frem" doing the right operation for moddf3?
|
;; FIXME: Is "frem" doing the right operation for moddf3?
|
(define_insn "moddf3"
|
(define_insn "moddf3"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(mod:DF (match_operand:DF 1 "register_operand" "r")
|
(mod:DF (match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FREM %0,%1,%2")
|
"FREM %0,%1,%2")
|
|
|
;; FIXME: Should we define_expand for smin, smax, umin, umax using a
|
;; FIXME: Should we define_expand for smin, smax, umin, umax using a
|
;; nifty conditional sequence?
|
;; nifty conditional sequence?
|
|
|
;; FIXME: The cuter andn combinations don't get here, presumably because
|
;; FIXME: The cuter andn combinations don't get here, presumably because
|
;; they ended up in the constant pool. Check: still?
|
;; they ended up in the constant pool. Check: still?
|
(define_insn "anddi3"
|
(define_insn "anddi3"
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
(and:DI
|
(and:DI
|
(match_operand:DI 1 "register_operand" "%r,0")
|
(match_operand:DI 1 "register_operand" "%r,0")
|
(match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,NT")))]
|
(match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,NT")))]
|
""
|
""
|
"@
|
"@
|
AND %0,%1,%2
|
AND %0,%1,%2
|
%A2 %0,%V2")
|
%A2 %0,%V2")
|
|
|
(define_insn "iordi3"
|
(define_insn "iordi3"
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
(ior:DI (match_operand:DI 1 "register_operand" "%r,0")
|
(ior:DI (match_operand:DI 1 "register_operand" "%r,0")
|
(match_operand:DI 2 "mmix_reg_or_constant_operand" "rH,LS")))]
|
(match_operand:DI 2 "mmix_reg_or_constant_operand" "rH,LS")))]
|
""
|
""
|
"@
|
"@
|
OR %0,%1,%2
|
OR %0,%1,%2
|
%o2 %0,%v2")
|
%o2 %0,%v2")
|
|
|
(define_insn "xordi3"
|
(define_insn "xordi3"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(xor:DI (match_operand:DI 1 "register_operand" "%r")
|
(xor:DI (match_operand:DI 1 "register_operand" "%r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"XOR %0,%1,%2")
|
"XOR %0,%1,%2")
|
|
|
;; FIXME: When TImode works for other reasons (like cross-compiling from
|
;; FIXME: When TImode works for other reasons (like cross-compiling from
|
;; a 32-bit host), add back umulditi3 and umuldi3_highpart here.
|
;; a 32-bit host), add back umulditi3 and umuldi3_highpart here.
|
|
|
;; FIXME: Check what's really reasonable for the mod part.
|
;; FIXME: Check what's really reasonable for the mod part.
|
|
|
;; One day we might persuade GCC to expand divisions with constants the
|
;; One day we might persuade GCC to expand divisions with constants the
|
;; way MMIX does; giving the remainder the sign of the divisor. But even
|
;; way MMIX does; giving the remainder the sign of the divisor. But even
|
;; then, it might be good to have an option to divide the way "everybody
|
;; then, it might be good to have an option to divide the way "everybody
|
;; else" does. Perhaps then, this option can be on by default. However,
|
;; else" does. Perhaps then, this option can be on by default. However,
|
;; it's not likely to happen because major (C, C++, Fortran) language
|
;; it's not likely to happen because major (C, C++, Fortran) language
|
;; standards in effect at 2002-04-29 reportedly demand that the sign of
|
;; standards in effect at 2002-04-29 reportedly demand that the sign of
|
;; the remainder must follow the sign of the dividend.
|
;; the remainder must follow the sign of the dividend.
|
|
|
(define_insn "divmoddi4"
|
(define_insn "divmoddi4"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(div:DI (match_operand:DI 1 "register_operand" "r")
|
(div:DI (match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))
|
(set (match_operand:DI 3 "register_operand" "=y")
|
(set (match_operand:DI 3 "register_operand" "=y")
|
(mod:DI (match_dup 1) (match_dup 2)))]
|
(mod:DI (match_dup 1) (match_dup 2)))]
|
;; Do the library stuff later.
|
;; Do the library stuff later.
|
"TARGET_KNUTH_DIVISION"
|
"TARGET_KNUTH_DIVISION"
|
"DIV %0,%1,%2")
|
"DIV %0,%1,%2")
|
|
|
(define_insn "udivmoddi4"
|
(define_insn "udivmoddi4"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(udiv:DI (match_operand:DI 1 "register_operand" "r")
|
(udiv:DI (match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))
|
(set (match_operand:DI 3 "register_operand" "=y")
|
(set (match_operand:DI 3 "register_operand" "=y")
|
(umod:DI (match_dup 1) (match_dup 2)))]
|
(umod:DI (match_dup 1) (match_dup 2)))]
|
""
|
""
|
"DIVU %0,%1,%2")
|
"DIVU %0,%1,%2")
|
|
|
(define_expand "divdi3"
|
(define_expand "divdi3"
|
[(parallel
|
[(parallel
|
[(set (match_operand:DI 0 "register_operand" "=&r")
|
[(set (match_operand:DI 0 "register_operand" "=&r")
|
(div:DI (match_operand:DI 1 "register_operand" "r")
|
(div:DI (match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "register_operand" "r")))
|
(match_operand:DI 2 "register_operand" "r")))
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (reg:DI MMIX_rR_REGNUM))])]
|
(clobber (reg:DI MMIX_rR_REGNUM))])]
|
"! TARGET_KNUTH_DIVISION"
|
"! TARGET_KNUTH_DIVISION"
|
"")
|
"")
|
|
|
;; The %2-is-%1-case is there just to make sure things don't fail. Could
|
;; The %2-is-%1-case is there just to make sure things don't fail. Could
|
;; presumably happen with optimizations off; no evidence.
|
;; presumably happen with optimizations off; no evidence.
|
(define_insn "*divdi3_nonknuth"
|
(define_insn "*divdi3_nonknuth"
|
[(set (match_operand:DI 0 "register_operand" "=&r,r")
|
[(set (match_operand:DI 0 "register_operand" "=&r,r")
|
(div:DI (match_operand:DI 1 "register_operand" "r,r")
|
(div:DI (match_operand:DI 1 "register_operand" "r,r")
|
(match_operand:DI 2 "register_operand" "1,r")))
|
(match_operand:DI 2 "register_operand" "1,r")))
|
(clobber (match_scratch:DI 3 "=1,1"))
|
(clobber (match_scratch:DI 3 "=1,1"))
|
(clobber (match_scratch:DI 4 "=2,2"))
|
(clobber (match_scratch:DI 4 "=2,2"))
|
(clobber (reg:DI MMIX_rR_REGNUM))]
|
(clobber (reg:DI MMIX_rR_REGNUM))]
|
"! TARGET_KNUTH_DIVISION"
|
"! TARGET_KNUTH_DIVISION"
|
"@
|
"@
|
SETL %0,1
|
SETL %0,1
|
XOR $255,%1,%2\;NEGU %0,0,%2\;CSN %2,%2,%0\;NEGU %0,0,%1\;CSN %1,%1,%0\;\
|
XOR $255,%1,%2\;NEGU %0,0,%2\;CSN %2,%2,%0\;NEGU %0,0,%1\;CSN %1,%1,%0\;\
|
DIVU %0,%1,%2\;NEGU %1,0,%0\;CSN %0,$255,%1")
|
DIVU %0,%1,%2\;NEGU %1,0,%0\;CSN %0,$255,%1")
|
|
|
(define_expand "moddi3"
|
(define_expand "moddi3"
|
[(parallel
|
[(parallel
|
[(set (match_operand:DI 0 "register_operand" "=&r")
|
[(set (match_operand:DI 0 "register_operand" "=&r")
|
(mod:DI (match_operand:DI 1 "register_operand" "r")
|
(mod:DI (match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "register_operand" "r")))
|
(match_operand:DI 2 "register_operand" "r")))
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (reg:DI MMIX_rR_REGNUM))])]
|
(clobber (reg:DI MMIX_rR_REGNUM))])]
|
"! TARGET_KNUTH_DIVISION"
|
"! TARGET_KNUTH_DIVISION"
|
"")
|
"")
|
|
|
;; The %2-is-%1-case is there just to make sure things don't fail. Could
|
;; The %2-is-%1-case is there just to make sure things don't fail. Could
|
;; presumably happen with optimizations off; no evidence.
|
;; presumably happen with optimizations off; no evidence.
|
(define_insn "*moddi3_nonknuth"
|
(define_insn "*moddi3_nonknuth"
|
[(set (match_operand:DI 0 "register_operand" "=&r,r")
|
[(set (match_operand:DI 0 "register_operand" "=&r,r")
|
(mod:DI (match_operand:DI 1 "register_operand" "r,r")
|
(mod:DI (match_operand:DI 1 "register_operand" "r,r")
|
(match_operand:DI 2 "register_operand" "1,r")))
|
(match_operand:DI 2 "register_operand" "1,r")))
|
(clobber (match_scratch:DI 3 "=1,1"))
|
(clobber (match_scratch:DI 3 "=1,1"))
|
(clobber (match_scratch:DI 4 "=2,2"))
|
(clobber (match_scratch:DI 4 "=2,2"))
|
(clobber (reg:DI MMIX_rR_REGNUM))]
|
(clobber (reg:DI MMIX_rR_REGNUM))]
|
"! TARGET_KNUTH_DIVISION"
|
"! TARGET_KNUTH_DIVISION"
|
"@
|
"@
|
SETL %0,0
|
SETL %0,0
|
NEGU %0,0,%2\;CSN %2,%2,%0\;NEGU $255,0,%1\;CSN %1,%1,$255\;\
|
NEGU %0,0,%2\;CSN %2,%2,%0\;NEGU $255,0,%1\;CSN %1,%1,$255\;\
|
DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
|
DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
|
|
|
(define_insn "ashldi3"
|
(define_insn "ashldi3"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(ashift:DI
|
(ashift:DI
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"SLU %0,%1,%2")
|
"SLU %0,%1,%2")
|
|
|
(define_insn "ashrdi3"
|
(define_insn "ashrdi3"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(ashiftrt:DI
|
(ashiftrt:DI
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"SR %0,%1,%2")
|
"SR %0,%1,%2")
|
|
|
(define_insn "lshrdi3"
|
(define_insn "lshrdi3"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(lshiftrt:DI
|
(lshiftrt:DI
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"SRU %0,%1,%2")
|
"SRU %0,%1,%2")
|
|
|
(define_insn "negdi2"
|
(define_insn "negdi2"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(neg:DI (match_operand:DI 1 "register_operand" "r")))]
|
(neg:DI (match_operand:DI 1 "register_operand" "r")))]
|
""
|
""
|
"NEGU %0,0,%1")
|
"NEGU %0,0,%1")
|
|
|
(define_expand "negdf2"
|
(define_expand "negdf2"
|
[(parallel [(set (match_operand:DF 0 "register_operand" "=r")
|
[(parallel [(set (match_operand:DF 0 "register_operand" "=r")
|
(neg:DF (match_operand:DF 1 "register_operand" "r")))
|
(neg:DF (match_operand:DF 1 "register_operand" "r")))
|
(use (match_dup 2))])]
|
(use (match_dup 2))])]
|
""
|
""
|
{
|
{
|
/* Emit bit-flipping sequence to be IEEE-safe wrt. -+0. */
|
/* Emit bit-flipping sequence to be IEEE-safe wrt. -+0. */
|
operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63));
|
operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63));
|
})
|
})
|
|
|
(define_insn "*expanded_negdf2"
|
(define_insn "*expanded_negdf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(neg:DF (match_operand:DF 1 "register_operand" "r")))
|
(neg:DF (match_operand:DF 1 "register_operand" "r")))
|
(use (match_operand:DI 2 "register_operand" "r"))]
|
(use (match_operand:DI 2 "register_operand" "r"))]
|
""
|
""
|
"XOR %0,%1,%2")
|
"XOR %0,%1,%2")
|
|
|
;; FIXME: define_expand for absdi2?
|
;; FIXME: define_expand for absdi2?
|
|
|
(define_insn "absdf2"
|
(define_insn "absdf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(abs:DF (match_operand:DF 1 "register_operand" "0")))]
|
(abs:DF (match_operand:DF 1 "register_operand" "0")))]
|
""
|
""
|
"ANDNH %0,#8000")
|
"ANDNH %0,#8000")
|
|
|
(define_insn "sqrtdf2"
|
(define_insn "sqrtdf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(sqrt:DF (match_operand:DF 1 "register_operand" "r")))]
|
(sqrt:DF (match_operand:DF 1 "register_operand" "r")))]
|
""
|
""
|
"FSQRT %0,%1")
|
"FSQRT %0,%1")
|
|
|
;; FIXME: define_expand for ffssi2? (not ffsdi2 since int is SImode).
|
;; FIXME: define_expand for ffssi2? (not ffsdi2 since int is SImode).
|
|
|
(define_insn "one_cmpldi2"
|
(define_insn "one_cmpldi2"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(not:DI (match_operand:DI 1 "register_operand" "r")))]
|
(not:DI (match_operand:DI 1 "register_operand" "r")))]
|
""
|
""
|
"NOR %0,%1,0")
|
"NOR %0,%1,0")
|
|
|
;; Since we don't have cc0, we do what is recommended in the manual;
|
;; Since we don't have cc0, we do what is recommended in the manual;
|
;; store away the operands for use in the branch, scc or movcc insn.
|
;; store away the operands for use in the branch, scc or movcc insn.
|
(define_expand "cmpdi"
|
(define_expand "cmpdi"
|
[(match_operand:DI 0 "register_operand" "")
|
[(match_operand:DI 0 "register_operand" "")
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "")]
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "")]
|
""
|
""
|
"
|
"
|
{
|
{
|
mmix_compare_op0 = operands[0];
|
mmix_compare_op0 = operands[0];
|
mmix_compare_op1 = operands[1];
|
mmix_compare_op1 = operands[1];
|
DONE;
|
DONE;
|
}")
|
}")
|
|
|
(define_expand "cmpdf"
|
(define_expand "cmpdf"
|
[(match_operand:DF 0 "register_operand" "")
|
[(match_operand:DF 0 "register_operand" "")
|
(match_operand:DF 1 "register_operand" "")]
|
(match_operand:DF 1 "register_operand" "")]
|
""
|
""
|
"
|
"
|
{
|
{
|
mmix_compare_op0 = operands[0];
|
mmix_compare_op0 = operands[0];
|
mmix_compare_op1 = operands[1];
|
mmix_compare_op1 = operands[1];
|
DONE;
|
DONE;
|
}")
|
}")
|
|
|
;; When the user-patterns expand, the resulting insns will match the
|
;; When the user-patterns expand, the resulting insns will match the
|
;; patterns below.
|
;; patterns below.
|
|
|
;; We can fold the signed-compare where the register value is
|
;; We can fold the signed-compare where the register value is
|
;; already equal to (compare:CCTYPE (reg) (const_int 0)).
|
;; already equal to (compare:CCTYPE (reg) (const_int 0)).
|
;; We can't do that at all for floating-point, due to NaN, +0.0
|
;; We can't do that at all for floating-point, due to NaN, +0.0
|
;; and -0.0, and we can only do it for the non/zero test of
|
;; and -0.0, and we can only do it for the non/zero test of
|
;; unsigned, so that has to be done another way.
|
;; unsigned, so that has to be done another way.
|
;; FIXME: Perhaps a peep2 changing CCcode to a new code, that
|
;; FIXME: Perhaps a peep2 changing CCcode to a new code, that
|
;; gets folded here.
|
;; gets folded here.
|
(define_insn "*cmpcc_folded"
|
(define_insn "*cmpcc_folded"
|
[(set (match_operand:CC 0 "register_operand" "=r")
|
[(set (match_operand:CC 0 "register_operand" "=r")
|
(compare:CC
|
(compare:CC
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 1 "register_operand" "r")
|
(const_int 0)))]
|
(const_int 0)))]
|
;; FIXME: Can we test equivalence any other way?
|
;; FIXME: Can we test equivalence any other way?
|
;; FIXME: Can we fold any other way?
|
;; FIXME: Can we fold any other way?
|
"REGNO (operands[1]) == REGNO (operands[0])"
|
"REGNO (operands[1]) == REGNO (operands[0])"
|
"%% folded: cmp %0,%1,0")
|
"%% folded: cmp %0,%1,0")
|
|
|
(define_insn "*cmpcc"
|
(define_insn "*cmpcc"
|
[(set (match_operand:CC 0 "register_operand" "=r")
|
[(set (match_operand:CC 0 "register_operand" "=r")
|
(compare:CC
|
(compare:CC
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"CMP %0,%1,%2")
|
"CMP %0,%1,%2")
|
|
|
(define_insn "*cmpu"
|
(define_insn "*cmpu"
|
[(set (match_operand:CC_UNS 0 "register_operand" "=r")
|
[(set (match_operand:CC_UNS 0 "register_operand" "=r")
|
(compare:CC_UNS
|
(compare:CC_UNS
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"CMPU %0,%1,%2")
|
"CMPU %0,%1,%2")
|
|
|
(define_insn "*fcmp"
|
(define_insn "*fcmp"
|
[(set (match_operand:CC_FP 0 "register_operand" "=r")
|
[(set (match_operand:CC_FP 0 "register_operand" "=r")
|
(compare:CC_FP
|
(compare:CC_FP
|
(match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FCMP%e0 %0,%1,%2")
|
"FCMP%e0 %0,%1,%2")
|
|
|
;; FIXME: for -mieee, add fsub %0,%1,%1\;fsub %0,%2,%2 before to
|
;; FIXME: for -mieee, add fsub %0,%1,%1\;fsub %0,%2,%2 before to
|
;; make signalling compliant.
|
;; make signalling compliant.
|
(define_insn "*feql"
|
(define_insn "*feql"
|
[(set (match_operand:CC_FPEQ 0 "register_operand" "=r")
|
[(set (match_operand:CC_FPEQ 0 "register_operand" "=r")
|
(compare:CC_FPEQ
|
(compare:CC_FPEQ
|
(match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FEQL%e0 %0,%1,%2")
|
"FEQL%e0 %0,%1,%2")
|
|
|
(define_insn "*fun"
|
(define_insn "*fun"
|
[(set (match_operand:CC_FUN 0 "register_operand" "=r")
|
[(set (match_operand:CC_FUN 0 "register_operand" "=r")
|
(compare:CC_FUN
|
(compare:CC_FUN
|
(match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 1 "register_operand" "r")
|
(match_operand:DF 2 "register_operand" "r")))]
|
(match_operand:DF 2 "register_operand" "r")))]
|
""
|
""
|
"FUN%e0 %0,%1,%2")
|
"FUN%e0 %0,%1,%2")
|
|
|
;; In order to get correct rounding, we have to use SFLOT and SFLOTU for
|
;; In order to get correct rounding, we have to use SFLOT and SFLOTU for
|
;; conversion. They do not convert to SFmode; they convert to DFmode,
|
;; conversion. They do not convert to SFmode; they convert to DFmode,
|
;; with rounding as of SFmode. They are not usable as is, but we pretend
|
;; with rounding as of SFmode. They are not usable as is, but we pretend
|
;; we have a single instruction but emit two.
|
;; we have a single instruction but emit two.
|
|
|
;; Note that this will (somewhat unexpectedly) create an inexact
|
;; Note that this will (somewhat unexpectedly) create an inexact
|
;; exception if rounding is necessary - has to be masked off in crt0?
|
;; exception if rounding is necessary - has to be masked off in crt0?
|
(define_expand "floatdisf2"
|
(define_expand "floatdisf2"
|
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm")
|
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm")
|
(float:SF
|
(float:SF
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
;; Let's use a DI scratch, since SF don't generally get into
|
;; Let's use a DI scratch, since SF don't generally get into
|
;; registers. Dunno what's best; it's really a DF, but that
|
;; registers. Dunno what's best; it's really a DF, but that
|
;; doesn't logically follow from operands in the pattern.
|
;; doesn't logically follow from operands in the pattern.
|
(clobber (match_scratch:DI 2 "=&r"))])]
|
(clobber (match_scratch:DI 2 "=&r"))])]
|
""
|
""
|
"
|
"
|
{
|
{
|
if (GET_CODE (operands[0]) != MEM)
|
if (GET_CODE (operands[0]) != MEM)
|
{
|
{
|
rtx stack_slot;
|
rtx stack_slot;
|
|
|
/* FIXME: This stack-slot remains even at -O3. There must be a
|
/* FIXME: This stack-slot remains even at -O3. There must be a
|
better way. */
|
better way. */
|
stack_slot
|
stack_slot
|
= validize_mem (assign_stack_temp (SFmode,
|
= validize_mem (assign_stack_temp (SFmode,
|
GET_MODE_SIZE (SFmode), 0));
|
GET_MODE_SIZE (SFmode), 0));
|
emit_insn (gen_floatdisf2 (stack_slot, operands[1]));
|
emit_insn (gen_floatdisf2 (stack_slot, operands[1]));
|
emit_move_insn (operands[0], stack_slot);
|
emit_move_insn (operands[0], stack_slot);
|
DONE;
|
DONE;
|
}
|
}
|
}")
|
}")
|
|
|
(define_insn "*floatdisf2_real"
|
(define_insn "*floatdisf2_real"
|
[(set (match_operand:SF 0 "memory_operand" "=m")
|
[(set (match_operand:SF 0 "memory_operand" "=m")
|
(float:SF
|
(float:SF
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
(clobber (match_scratch:DI 2 "=&r"))]
|
(clobber (match_scratch:DI 2 "=&r"))]
|
""
|
""
|
"SFLOT %2,%1\;STSF %2,%0")
|
"SFLOT %2,%1\;STSF %2,%0")
|
|
|
(define_expand "floatunsdisf2"
|
(define_expand "floatunsdisf2"
|
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm")
|
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm")
|
(unsigned_float:SF
|
(unsigned_float:SF
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
;; Let's use a DI scratch, since SF don't generally get into
|
;; Let's use a DI scratch, since SF don't generally get into
|
;; registers. Dunno what's best; it's really a DF, but that
|
;; registers. Dunno what's best; it's really a DF, but that
|
;; doesn't logically follow from operands in the pattern.
|
;; doesn't logically follow from operands in the pattern.
|
(clobber (scratch:DI))])]
|
(clobber (scratch:DI))])]
|
""
|
""
|
"
|
"
|
{
|
{
|
if (GET_CODE (operands[0]) != MEM)
|
if (GET_CODE (operands[0]) != MEM)
|
{
|
{
|
rtx stack_slot;
|
rtx stack_slot;
|
|
|
/* FIXME: This stack-slot remains even at -O3. Must be a better
|
/* FIXME: This stack-slot remains even at -O3. Must be a better
|
way. */
|
way. */
|
stack_slot
|
stack_slot
|
= validize_mem (assign_stack_temp (SFmode,
|
= validize_mem (assign_stack_temp (SFmode,
|
GET_MODE_SIZE (SFmode), 0));
|
GET_MODE_SIZE (SFmode), 0));
|
emit_insn (gen_floatunsdisf2 (stack_slot, operands[1]));
|
emit_insn (gen_floatunsdisf2 (stack_slot, operands[1]));
|
emit_move_insn (operands[0], stack_slot);
|
emit_move_insn (operands[0], stack_slot);
|
DONE;
|
DONE;
|
}
|
}
|
}")
|
}")
|
|
|
(define_insn "*floatunsdisf2_real"
|
(define_insn "*floatunsdisf2_real"
|
[(set (match_operand:SF 0 "memory_operand" "=m")
|
[(set (match_operand:SF 0 "memory_operand" "=m")
|
(unsigned_float:SF
|
(unsigned_float:SF
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
|
(clobber (match_scratch:DI 2 "=&r"))]
|
(clobber (match_scratch:DI 2 "=&r"))]
|
""
|
""
|
"SFLOTU %2,%1\;STSF %2,%0")
|
"SFLOTU %2,%1\;STSF %2,%0")
|
|
|
;; Note that this will (somewhat unexpectedly) create an inexact
|
;; Note that this will (somewhat unexpectedly) create an inexact
|
;; exception if rounding is necessary - has to be masked off in crt0?
|
;; exception if rounding is necessary - has to be masked off in crt0?
|
(define_insn "floatdidf2"
|
(define_insn "floatdidf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(float:DF
|
(float:DF
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"FLOT %0,%1")
|
"FLOT %0,%1")
|
|
|
(define_insn "floatunsdidf2"
|
(define_insn "floatunsdidf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(unsigned_float:DF
|
(unsigned_float:DF
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))]
|
""
|
""
|
"FLOTU %0,%1")
|
"FLOTU %0,%1")
|
|
|
(define_insn "ftruncdf2"
|
(define_insn "ftruncdf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(fix:DF (match_operand:DF 1 "register_operand" "r")))]
|
(fix:DF (match_operand:DF 1 "register_operand" "r")))]
|
""
|
""
|
;; ROUND_OFF
|
;; ROUND_OFF
|
"FINT %0,1,%1")
|
"FINT %0,1,%1")
|
|
|
;; Note that this will (somewhat unexpectedly) create an inexact
|
;; Note that this will (somewhat unexpectedly) create an inexact
|
;; exception if rounding is necessary - has to be masked off in crt0?
|
;; exception if rounding is necessary - has to be masked off in crt0?
|
(define_insn "fix_truncdfdi2"
|
(define_insn "fix_truncdfdi2"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "r"))))]
|
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "r"))))]
|
""
|
""
|
;; ROUND_OFF
|
;; ROUND_OFF
|
"FIX %0,1,%1")
|
"FIX %0,1,%1")
|
|
|
(define_insn "fixuns_truncdfdi2"
|
(define_insn "fixuns_truncdfdi2"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(unsigned_fix:DI
|
(unsigned_fix:DI
|
(fix:DF (match_operand:DF 1 "register_operand" "r"))))]
|
(fix:DF (match_operand:DF 1 "register_operand" "r"))))]
|
""
|
""
|
;; ROUND_OFF
|
;; ROUND_OFF
|
"FIXU %0,1,%1")
|
"FIXU %0,1,%1")
|
|
|
;; It doesn't seem like it's possible to have memory_operand as a
|
;; It doesn't seem like it's possible to have memory_operand as a
|
;; predicate here (testcase: libgcc2 floathisf). FIXME: Shouldn't it be
|
;; predicate here (testcase: libgcc2 floathisf). FIXME: Shouldn't it be
|
;; possible to do that? Bug in GCC? Anyway, this used to be a simple
|
;; possible to do that? Bug in GCC? Anyway, this used to be a simple
|
;; pattern with a memory_operand predicate, but was split up with a
|
;; pattern with a memory_operand predicate, but was split up with a
|
;; define_expand with the old pattern as "anonymous".
|
;; define_expand with the old pattern as "anonymous".
|
;; FIXME: Perhaps with SECONDARY_MEMORY_NEEDED?
|
;; FIXME: Perhaps with SECONDARY_MEMORY_NEEDED?
|
(define_expand "truncdfsf2"
|
(define_expand "truncdfsf2"
|
[(set (match_operand:SF 0 "memory_operand" "")
|
[(set (match_operand:SF 0 "memory_operand" "")
|
(float_truncate:SF (match_operand:DF 1 "register_operand" "")))]
|
(float_truncate:SF (match_operand:DF 1 "register_operand" "")))]
|
""
|
""
|
"
|
"
|
{
|
{
|
if (GET_CODE (operands[0]) != MEM)
|
if (GET_CODE (operands[0]) != MEM)
|
{
|
{
|
/* FIXME: There should be a way to say: 'put this in operands[0]
|
/* FIXME: There should be a way to say: 'put this in operands[0]
|
but *after* the expanded insn'. */
|
but *after* the expanded insn'. */
|
rtx stack_slot;
|
rtx stack_slot;
|
|
|
/* There is no sane destination but a register here, if it wasn't
|
/* There is no sane destination but a register here, if it wasn't
|
already MEM. (It's too hard to get fatal_insn to work here.) */
|
already MEM. (It's too hard to get fatal_insn to work here.) */
|
if (! REG_P (operands[0]))
|
if (! REG_P (operands[0]))
|
internal_error (\"MMIX Internal: Bad truncdfsf2 expansion\");
|
internal_error (\"MMIX Internal: Bad truncdfsf2 expansion\");
|
|
|
/* FIXME: This stack-slot remains even at -O3. Must be a better
|
/* FIXME: This stack-slot remains even at -O3. Must be a better
|
way. */
|
way. */
|
stack_slot
|
stack_slot
|
= validize_mem (assign_stack_temp (SFmode,
|
= validize_mem (assign_stack_temp (SFmode,
|
GET_MODE_SIZE (SFmode), 0));
|
GET_MODE_SIZE (SFmode), 0));
|
emit_insn (gen_truncdfsf2 (stack_slot, operands[1]));
|
emit_insn (gen_truncdfsf2 (stack_slot, operands[1]));
|
emit_move_insn (operands[0], stack_slot);
|
emit_move_insn (operands[0], stack_slot);
|
DONE;
|
DONE;
|
}
|
}
|
}")
|
}")
|
|
|
(define_insn "*truncdfsf2_real"
|
(define_insn "*truncdfsf2_real"
|
[(set (match_operand:SF 0 "memory_operand" "=m")
|
[(set (match_operand:SF 0 "memory_operand" "=m")
|
(float_truncate:SF (match_operand:DF 1 "register_operand" "r")))]
|
(float_truncate:SF (match_operand:DF 1 "register_operand" "r")))]
|
""
|
""
|
"STSF %1,%0")
|
"STSF %1,%0")
|
|
|
;; Same comment as for truncdfsf2.
|
;; Same comment as for truncdfsf2.
|
(define_expand "extendsfdf2"
|
(define_expand "extendsfdf2"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(float_extend:DF (match_operand:SF 1 "memory_operand" "m")))]
|
(float_extend:DF (match_operand:SF 1 "memory_operand" "m")))]
|
""
|
""
|
"
|
"
|
{
|
{
|
if (GET_CODE (operands[1]) != MEM)
|
if (GET_CODE (operands[1]) != MEM)
|
{
|
{
|
rtx stack_slot;
|
rtx stack_slot;
|
|
|
/* There is no sane destination but a register here, if it wasn't
|
/* There is no sane destination but a register here, if it wasn't
|
already MEM. (It's too hard to get fatal_insn to work here.) */
|
already MEM. (It's too hard to get fatal_insn to work here.) */
|
if (! REG_P (operands[0]))
|
if (! REG_P (operands[0]))
|
internal_error (\"MMIX Internal: Bad extendsfdf2 expansion\");
|
internal_error (\"MMIX Internal: Bad extendsfdf2 expansion\");
|
|
|
/* FIXME: This stack-slot remains even at -O3. There must be a
|
/* FIXME: This stack-slot remains even at -O3. There must be a
|
better way. */
|
better way. */
|
stack_slot
|
stack_slot
|
= validize_mem (assign_stack_temp (SFmode,
|
= validize_mem (assign_stack_temp (SFmode,
|
GET_MODE_SIZE (SFmode), 0));
|
GET_MODE_SIZE (SFmode), 0));
|
emit_move_insn (stack_slot, operands[1]);
|
emit_move_insn (stack_slot, operands[1]);
|
emit_insn (gen_extendsfdf2 (operands[0], stack_slot));
|
emit_insn (gen_extendsfdf2 (operands[0], stack_slot));
|
DONE;
|
DONE;
|
}
|
}
|
}")
|
}")
|
|
|
(define_insn "*extendsfdf2_real"
|
(define_insn "*extendsfdf2_real"
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
[(set (match_operand:DF 0 "register_operand" "=r")
|
(float_extend:DF (match_operand:SF 1 "memory_operand" "m")))]
|
(float_extend:DF (match_operand:SF 1 "memory_operand" "m")))]
|
""
|
""
|
"LDSF %0,%1")
|
"LDSF %0,%1")
|
|
|
;; Neither sign-extend nor zero-extend are necessary; gcc knows how to
|
;; Neither sign-extend nor zero-extend are necessary; gcc knows how to
|
;; synthesize using shifts or and, except with a memory source and not
|
;; synthesize using shifts or and, except with a memory source and not
|
;; completely optimal. FIXME: Actually, other bugs surface when those
|
;; completely optimal. FIXME: Actually, other bugs surface when those
|
;; patterns are defined; fix later.
|
;; patterns are defined; fix later.
|
|
|
;; There are no sane values with the bit-patterns of (int) 0..255 except
|
;; There are no sane values with the bit-patterns of (int) 0..255 except
|
;; 0 to use in movdfcc.
|
;; 0 to use in movdfcc.
|
|
|
(define_expand "movdfcc"
|
(define_expand "movdfcc"
|
[(set (match_operand:DF 0 "register_operand" "")
|
[(set (match_operand:DF 0 "register_operand" "")
|
(if_then_else:DF
|
(if_then_else:DF
|
(match_operand 1 "comparison_operator" "")
|
(match_operand 1 "comparison_operator" "")
|
(match_operand:DF 2 "mmix_reg_or_0_operand" "")
|
(match_operand:DF 2 "mmix_reg_or_0_operand" "")
|
(match_operand:DF 3 "mmix_reg_or_0_operand" "")))]
|
(match_operand:DF 3 "mmix_reg_or_0_operand" "")))]
|
""
|
""
|
"
|
"
|
{
|
{
|
enum rtx_code code = GET_CODE (operands[1]);
|
enum rtx_code code = GET_CODE (operands[1]);
|
rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0,
|
rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0,
|
mmix_compare_op1);
|
mmix_compare_op1);
|
if (cc_reg == NULL_RTX)
|
if (cc_reg == NULL_RTX)
|
FAIL;
|
FAIL;
|
operands[1] = gen_rtx_fmt_ee (code, VOIDmode, cc_reg, const0_rtx);
|
operands[1] = gen_rtx_fmt_ee (code, VOIDmode, cc_reg, const0_rtx);
|
}")
|
}")
|
|
|
(define_expand "movdicc"
|
(define_expand "movdicc"
|
[(set (match_operand:DI 0 "register_operand" "")
|
[(set (match_operand:DI 0 "register_operand" "")
|
(if_then_else:DI
|
(if_then_else:DI
|
(match_operand 1 "comparison_operator" "")
|
(match_operand 1 "comparison_operator" "")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "")
|
(match_operand:DI 3 "mmix_reg_or_8bit_operand" "")))]
|
(match_operand:DI 3 "mmix_reg_or_8bit_operand" "")))]
|
""
|
""
|
"
|
"
|
{
|
{
|
enum rtx_code code = GET_CODE (operands[1]);
|
enum rtx_code code = GET_CODE (operands[1]);
|
rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0,
|
rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0,
|
mmix_compare_op1);
|
mmix_compare_op1);
|
if (cc_reg == NULL_RTX)
|
if (cc_reg == NULL_RTX)
|
FAIL;
|
FAIL;
|
operands[1] = gen_rtx_fmt_ee (code, VOIDmode, cc_reg, const0_rtx);
|
operands[1] = gen_rtx_fmt_ee (code, VOIDmode, cc_reg, const0_rtx);
|
}")
|
}")
|
|
|
;; FIXME: Is this the right way to do "folding" of CCmode -> DImode?
|
;; FIXME: Is this the right way to do "folding" of CCmode -> DImode?
|
(define_insn "*movdicc_real_foldable"
|
(define_insn "*movdicc_real_foldable"
|
[(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
|
[(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
|
(if_then_else:DI
|
(if_then_else:DI
|
(match_operator 2 "mmix_foldable_comparison_operator"
|
(match_operator 2 "mmix_foldable_comparison_operator"
|
[(match_operand:DI 3 "register_operand" "r,r,r,r")
|
[(match_operand:DI 3 "register_operand" "r,r,r,r")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM")
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM")
|
(match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))]
|
(match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))]
|
""
|
""
|
"@
|
"@
|
CS%d2 %0,%3,%1
|
CS%d2 %0,%3,%1
|
CS%D2 %0,%3,%4
|
CS%D2 %0,%3,%4
|
ZS%d2 %0,%3,%1
|
ZS%d2 %0,%3,%1
|
ZS%D2 %0,%3,%4")
|
ZS%D2 %0,%3,%4")
|
|
|
(define_insn "*movdicc_real_reversible"
|
(define_insn "*movdicc_real_reversible"
|
[(set
|
[(set
|
(match_operand:DI 0 "register_operand" "=r ,r ,r ,r")
|
(match_operand:DI 0 "register_operand" "=r ,r ,r ,r")
|
(if_then_else:DI
|
(if_then_else:DI
|
(match_operator
|
(match_operator
|
2 "mmix_comparison_operator"
|
2 "mmix_comparison_operator"
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r")
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM")
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM")
|
(match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))]
|
(match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))]
|
"REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"@
|
"@
|
CS%d2 %0,%3,%1
|
CS%d2 %0,%3,%1
|
CS%D2 %0,%3,%4
|
CS%D2 %0,%3,%4
|
ZS%d2 %0,%3,%1
|
ZS%d2 %0,%3,%1
|
ZS%D2 %0,%3,%4")
|
ZS%D2 %0,%3,%4")
|
|
|
(define_insn "*movdicc_real_nonreversible"
|
(define_insn "*movdicc_real_nonreversible"
|
[(set
|
[(set
|
(match_operand:DI 0 "register_operand" "=r ,r")
|
(match_operand:DI 0 "register_operand" "=r ,r")
|
(if_then_else:DI
|
(if_then_else:DI
|
(match_operator
|
(match_operator
|
2 "mmix_comparison_operator"
|
2 "mmix_comparison_operator"
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r")
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,rI")
|
(match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,rI")
|
(match_operand:DI 4 "mmix_reg_or_0_operand" "0 ,GM")))]
|
(match_operand:DI 4 "mmix_reg_or_0_operand" "0 ,GM")))]
|
"!REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"!REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"@
|
"@
|
CS%d2 %0,%3,%1
|
CS%d2 %0,%3,%1
|
ZS%d2 %0,%3,%1")
|
ZS%d2 %0,%3,%1")
|
|
|
(define_insn "*movdfcc_real_foldable"
|
(define_insn "*movdfcc_real_foldable"
|
[(set
|
[(set
|
(match_operand:DF 0 "register_operand" "=r ,r ,r ,r")
|
(match_operand:DF 0 "register_operand" "=r ,r ,r ,r")
|
(if_then_else:DF
|
(if_then_else:DF
|
(match_operator
|
(match_operator
|
2 "mmix_foldable_comparison_operator"
|
2 "mmix_foldable_comparison_operator"
|
[(match_operand:DI 3 "register_operand" "r ,r ,r ,r")
|
[(match_operand:DI 3 "register_operand" "r ,r ,r ,r")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0 ,rGM,GM")
|
(match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0 ,rGM,GM")
|
(match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,rGM,GM ,rGM")))]
|
(match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,rGM,GM ,rGM")))]
|
""
|
""
|
"@
|
"@
|
CS%d2 %0,%3,%1
|
CS%d2 %0,%3,%1
|
CS%D2 %0,%3,%4
|
CS%D2 %0,%3,%4
|
ZS%d2 %0,%3,%1
|
ZS%d2 %0,%3,%1
|
ZS%D2 %0,%3,%4")
|
ZS%D2 %0,%3,%4")
|
|
|
(define_insn "*movdfcc_real_reversible"
|
(define_insn "*movdfcc_real_reversible"
|
[(set
|
[(set
|
(match_operand:DF 0 "register_operand" "=r ,r ,r ,r")
|
(match_operand:DF 0 "register_operand" "=r ,r ,r ,r")
|
(if_then_else:DF
|
(if_then_else:DF
|
(match_operator
|
(match_operator
|
2 "mmix_comparison_operator"
|
2 "mmix_comparison_operator"
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r")
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0 ,rGM,GM")
|
(match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0 ,rGM,GM")
|
(match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,rGM,GM ,rGM")))]
|
(match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,rGM,GM ,rGM")))]
|
"REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"@
|
"@
|
CS%d2 %0,%3,%1
|
CS%d2 %0,%3,%1
|
CS%D2 %0,%3,%4
|
CS%D2 %0,%3,%4
|
ZS%d2 %0,%3,%1
|
ZS%d2 %0,%3,%1
|
ZS%D2 %0,%3,%4")
|
ZS%D2 %0,%3,%4")
|
|
|
(define_insn "*movdfcc_real_nonreversible"
|
(define_insn "*movdfcc_real_nonreversible"
|
[(set
|
[(set
|
(match_operand:DF 0 "register_operand" "=r ,r")
|
(match_operand:DF 0 "register_operand" "=r ,r")
|
(if_then_else:DF
|
(if_then_else:DF
|
(match_operator
|
(match_operator
|
2 "mmix_comparison_operator"
|
2 "mmix_comparison_operator"
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r")
|
[(match_operand 3 "mmix_reg_cc_operand" "r ,r")
|
(const_int 0)])
|
(const_int 0)])
|
(match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,rGM")
|
(match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,rGM")
|
(match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,GM")))]
|
(match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,GM")))]
|
"!REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"!REVERSIBLE_CC_MODE (GET_MODE (operands[3]))"
|
"@
|
"@
|
CS%d2 %0,%3,%1
|
CS%d2 %0,%3,%1
|
ZS%d2 %0,%3,%1")
|
ZS%d2 %0,%3,%1")
|
|
|
;; FIXME: scc patterns will probably help, I just skip them
|
;; FIXME: scc patterns will probably help, I just skip them
|
;; right now. Revisit.
|
;; right now. Revisit.
|
|
|
(define_expand "beq"
|
(define_expand "beq"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (eq (match_dup 1) (const_int 0))
|
(if_then_else (eq (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (EQ, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (EQ, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bne"
|
(define_expand "bne"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (ne (match_dup 1) (const_int 0))
|
(if_then_else (ne (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (NE, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (NE, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bgt"
|
(define_expand "bgt"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (gt (match_dup 1) (const_int 0))
|
(if_then_else (gt (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (GT, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (GT, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "ble"
|
(define_expand "ble"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (le (match_dup 1) (const_int 0))
|
(if_then_else (le (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (LE, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (LE, mmix_compare_op0, mmix_compare_op1);
|
|
|
/* The head comment of optabs.c:can_compare_p says we're required to
|
/* The head comment of optabs.c:can_compare_p says we're required to
|
implement this, so we have to clean up the mess here. */
|
implement this, so we have to clean up the mess here. */
|
if (operands[1] == NULL_RTX)
|
if (operands[1] == NULL_RTX)
|
{
|
{
|
/* FIXME: Watch out for sharing/unsharing of rtx:es. */
|
/* FIXME: Watch out for sharing/unsharing of rtx:es. */
|
emit_jump_insn ((*bcc_gen_fctn[(int) LT]) (operands[0]));
|
emit_jump_insn ((*bcc_gen_fctn[(int) LT]) (operands[0]));
|
emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0]));
|
emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0]));
|
DONE;
|
DONE;
|
}
|
}
|
}")
|
}")
|
|
|
(define_expand "bge"
|
(define_expand "bge"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (ge (match_dup 1) (const_int 0))
|
(if_then_else (ge (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (GE, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (GE, mmix_compare_op0, mmix_compare_op1);
|
|
|
/* The head comment of optabs.c:can_compare_p says we're required to
|
/* The head comment of optabs.c:can_compare_p says we're required to
|
implement this, so we have to clean up the mess here. */
|
implement this, so we have to clean up the mess here. */
|
if (operands[1] == NULL_RTX)
|
if (operands[1] == NULL_RTX)
|
{
|
{
|
/* FIXME: Watch out for sharing/unsharing of rtx:es. */
|
/* FIXME: Watch out for sharing/unsharing of rtx:es. */
|
emit_jump_insn ((*bcc_gen_fctn[(int) GT]) (operands[0]));
|
emit_jump_insn ((*bcc_gen_fctn[(int) GT]) (operands[0]));
|
emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0]));
|
emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0]));
|
DONE;
|
DONE;
|
}
|
}
|
}")
|
}")
|
|
|
(define_expand "blt"
|
(define_expand "blt"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (lt (match_dup 1) (const_int 0))
|
(if_then_else (lt (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (LT, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (LT, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bgtu"
|
(define_expand "bgtu"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (gtu (match_dup 1) (const_int 0))
|
(if_then_else (gtu (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (GTU, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (GTU, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bleu"
|
(define_expand "bleu"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (leu (match_dup 1) (const_int 0))
|
(if_then_else (leu (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (LEU, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (LEU, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bgeu"
|
(define_expand "bgeu"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (geu (match_dup 1) (const_int 0))
|
(if_then_else (geu (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (GEU, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (GEU, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bltu"
|
(define_expand "bltu"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (ltu (match_dup 1) (const_int 0))
|
(if_then_else (ltu (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (LTU, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (LTU, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
(define_expand "bunordered"
|
(define_expand "bunordered"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (unordered (match_dup 1) (const_int 0))
|
(if_then_else (unordered (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (UNORDERED, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (UNORDERED, mmix_compare_op0, mmix_compare_op1);
|
|
|
if (operands[1] == NULL_RTX)
|
if (operands[1] == NULL_RTX)
|
FAIL;
|
FAIL;
|
}")
|
}")
|
|
|
(define_expand "bordered"
|
(define_expand "bordered"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else (ordered (match_dup 1) (const_int 0))
|
(if_then_else (ordered (match_dup 1) (const_int 0))
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[1]
|
operands[1]
|
= mmix_gen_compare_reg (ORDERED, mmix_compare_op0, mmix_compare_op1);
|
= mmix_gen_compare_reg (ORDERED, mmix_compare_op0, mmix_compare_op1);
|
}")
|
}")
|
|
|
;; FIXME: we can emit an unordered-or-*not*-equal compare in one insn, but
|
;; FIXME: we can emit an unordered-or-*not*-equal compare in one insn, but
|
;; there's no RTL code for it. Maybe revisit in future.
|
;; there's no RTL code for it. Maybe revisit in future.
|
|
|
;; FIXME: Odd/Even matchers?
|
;; FIXME: Odd/Even matchers?
|
(define_insn "*bCC_foldable"
|
(define_insn "*bCC_foldable"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "mmix_foldable_comparison_operator"
|
(match_operator 1 "mmix_foldable_comparison_operator"
|
[(match_operand:DI 2 "register_operand" "r")
|
[(match_operand:DI 2 "register_operand" "r")
|
(const_int 0)])
|
(const_int 0)])
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"%+B%d1 %2,%0")
|
"%+B%d1 %2,%0")
|
|
|
(define_insn "*bCC"
|
(define_insn "*bCC"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "mmix_comparison_operator"
|
(match_operator 1 "mmix_comparison_operator"
|
[(match_operand 2 "mmix_reg_cc_operand" "r")
|
[(match_operand 2 "mmix_reg_cc_operand" "r")
|
(const_int 0)])
|
(const_int 0)])
|
(label_ref (match_operand 0 "" ""))
|
(label_ref (match_operand 0 "" ""))
|
(pc)))]
|
(pc)))]
|
""
|
""
|
"%+B%d1 %2,%0")
|
"%+B%d1 %2,%0")
|
|
|
(define_insn "*bCC_inverted_foldable"
|
(define_insn "*bCC_inverted_foldable"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "mmix_foldable_comparison_operator"
|
(match_operator 1 "mmix_foldable_comparison_operator"
|
[(match_operand:DI 2 "register_operand" "r")
|
[(match_operand:DI 2 "register_operand" "r")
|
(const_int 0)])
|
(const_int 0)])
|
(pc)
|
(pc)
|
(label_ref (match_operand 0 "" ""))))]
|
(label_ref (match_operand 0 "" ""))))]
|
;; REVERSIBLE_CC_MODE is checked by mmix_foldable_comparison_operator.
|
;; REVERSIBLE_CC_MODE is checked by mmix_foldable_comparison_operator.
|
""
|
""
|
"%+B%D1 %2,%0")
|
"%+B%D1 %2,%0")
|
|
|
(define_insn "*bCC_inverted"
|
(define_insn "*bCC_inverted"
|
[(set (pc)
|
[(set (pc)
|
(if_then_else
|
(if_then_else
|
(match_operator 1 "mmix_comparison_operator"
|
(match_operator 1 "mmix_comparison_operator"
|
[(match_operand 2 "mmix_reg_cc_operand" "r")
|
[(match_operand 2 "mmix_reg_cc_operand" "r")
|
(const_int 0)])
|
(const_int 0)])
|
(pc)
|
(pc)
|
(label_ref (match_operand 0 "" ""))))]
|
(label_ref (match_operand 0 "" ""))))]
|
"REVERSIBLE_CC_MODE (GET_MODE (operands[2]))"
|
"REVERSIBLE_CC_MODE (GET_MODE (operands[2]))"
|
"%+B%D1 %2,%0")
|
"%+B%D1 %2,%0")
|
|
|
(define_expand "call"
|
(define_expand "call"
|
[(parallel [(call (match_operand:QI 0 "memory_operand" "")
|
[(parallel [(call (match_operand:QI 0 "memory_operand" "")
|
(match_operand 1 "general_operand" ""))
|
(match_operand 1 "general_operand" ""))
|
(use (match_operand 2 "general_operand" ""))
|
(use (match_operand 2 "general_operand" ""))
|
(clobber (match_dup 4))])
|
(clobber (match_dup 4))])
|
(set (match_dup 4) (match_dup 3))]
|
(set (match_dup 4) (match_dup 3))]
|
""
|
""
|
"
|
"
|
{
|
{
|
/* The caller checks that the operand is generally valid as an
|
/* The caller checks that the operand is generally valid as an
|
address, but at -O0 nothing makes sure that it's also a valid
|
address, but at -O0 nothing makes sure that it's also a valid
|
call address for a *call*; a mmix_symbolic_or_address_operand.
|
call address for a *call*; a mmix_symbolic_or_address_operand.
|
Force into a register if it isn't. */
|
Force into a register if it isn't. */
|
if (!mmix_symbolic_or_address_operand (XEXP (operands[0], 0),
|
if (!mmix_symbolic_or_address_operand (XEXP (operands[0], 0),
|
GET_MODE (XEXP (operands[0], 0))))
|
GET_MODE (XEXP (operands[0], 0))))
|
operands[0]
|
operands[0]
|
= replace_equiv_address (operands[0],
|
= replace_equiv_address (operands[0],
|
force_reg (Pmode, XEXP (operands[0], 0)));
|
force_reg (Pmode, XEXP (operands[0], 0)));
|
|
|
/* Since the epilogue 'uses' the return address, and it is clobbered
|
/* Since the epilogue 'uses' the return address, and it is clobbered
|
in the call, and we set it back after every call (all but one setting
|
in the call, and we set it back after every call (all but one setting
|
will be optimized away), integrity is maintained. */
|
will be optimized away), integrity is maintained. */
|
operands[3]
|
operands[3]
|
= mmix_get_hard_reg_initial_val (Pmode,
|
= mmix_get_hard_reg_initial_val (Pmode,
|
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
|
|
/* FIXME: There's a bug in gcc which causes NULL to be passed as
|
/* FIXME: There's a bug in gcc which causes NULL to be passed as
|
operand[2] when we get out of registers, which later confuses gcc.
|
operand[2] when we get out of registers, which later confuses gcc.
|
Work around it by replacing it with const_int 0. Possibly documentation
|
Work around it by replacing it with const_int 0. Possibly documentation
|
error too. */
|
error too. */
|
if (operands[2] == NULL_RTX)
|
if (operands[2] == NULL_RTX)
|
operands[2] = const0_rtx;
|
operands[2] = const0_rtx;
|
|
|
operands[4] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
operands[4] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
}")
|
}")
|
|
|
(define_expand "call_value"
|
(define_expand "call_value"
|
[(parallel [(set (match_operand 0 "" "")
|
[(parallel [(set (match_operand 0 "" "")
|
(call (match_operand:QI 1 "memory_operand" "")
|
(call (match_operand:QI 1 "memory_operand" "")
|
(match_operand 2 "general_operand" "")))
|
(match_operand 2 "general_operand" "")))
|
(use (match_operand 3 "general_operand" ""))
|
(use (match_operand 3 "general_operand" ""))
|
(clobber (match_dup 5))])
|
(clobber (match_dup 5))])
|
(set (match_dup 5) (match_dup 4))]
|
(set (match_dup 5) (match_dup 4))]
|
""
|
""
|
"
|
"
|
{
|
{
|
/* The caller checks that the operand is generally valid as an
|
/* The caller checks that the operand is generally valid as an
|
address, but at -O0 nothing makes sure that it's also a valid
|
address, but at -O0 nothing makes sure that it's also a valid
|
call address for a *call*; a mmix_symbolic_or_address_operand.
|
call address for a *call*; a mmix_symbolic_or_address_operand.
|
Force into a register if it isn't. */
|
Force into a register if it isn't. */
|
if (!mmix_symbolic_or_address_operand (XEXP (operands[1], 0),
|
if (!mmix_symbolic_or_address_operand (XEXP (operands[1], 0),
|
GET_MODE (XEXP (operands[1], 0))))
|
GET_MODE (XEXP (operands[1], 0))))
|
operands[1]
|
operands[1]
|
= replace_equiv_address (operands[1],
|
= replace_equiv_address (operands[1],
|
force_reg (Pmode, XEXP (operands[1], 0)));
|
force_reg (Pmode, XEXP (operands[1], 0)));
|
|
|
/* Since the epilogue 'uses' the return address, and it is clobbered
|
/* Since the epilogue 'uses' the return address, and it is clobbered
|
in the call, and we set it back after every call (all but one setting
|
in the call, and we set it back after every call (all but one setting
|
will be optimized away), integrity is maintained. */
|
will be optimized away), integrity is maintained. */
|
operands[4]
|
operands[4]
|
= mmix_get_hard_reg_initial_val (Pmode,
|
= mmix_get_hard_reg_initial_val (Pmode,
|
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
|
|
/* FIXME: See 'call'. */
|
/* FIXME: See 'call'. */
|
if (operands[3] == NULL_RTX)
|
if (operands[3] == NULL_RTX)
|
operands[3] = const0_rtx;
|
operands[3] = const0_rtx;
|
|
|
/* FIXME: Documentation bug: operands[3] (operands[2] for 'call') is the
|
/* FIXME: Documentation bug: operands[3] (operands[2] for 'call') is the
|
*next* argument register, not the number of arguments in registers.
|
*next* argument register, not the number of arguments in registers.
|
(There used to be code here where that mattered.) */
|
(There used to be code here where that mattered.) */
|
|
|
operands[5] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
operands[5] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
}")
|
}")
|
|
|
;; Don't use 'p' here. A 'p' must stand first in constraints, or reload
|
;; Don't use 'p' here. A 'p' must stand first in constraints, or reload
|
;; messes up, not registering the address for reload. Several C++
|
;; messes up, not registering the address for reload. Several C++
|
;; testcases, including g++.brendan/crash40.C. FIXME: This is arguably a
|
;; testcases, including g++.brendan/crash40.C. FIXME: This is arguably a
|
;; bug in gcc. Note line ~2612 in reload.c, that does things on the
|
;; bug in gcc. Note line ~2612 in reload.c, that does things on the
|
;; condition <> and the comment on
|
;; condition <> and the comment on
|
;; ~3017 that says:
|
;; ~3017 that says:
|
;; << case 'p':
|
;; << case 'p':
|
;; /* All necessary reloads for an address_operand
|
;; /* All necessary reloads for an address_operand
|
;; were handled in find_reloads_address. */>>
|
;; were handled in find_reloads_address. */>>
|
;; Sorry, I have not dug deeper. If symbolic addresses are used
|
;; Sorry, I have not dug deeper. If symbolic addresses are used
|
;; rarely compared to addresses in registers, disparaging the
|
;; rarely compared to addresses in registers, disparaging the
|
;; first ("p") alternative by adding ? in the first operand
|
;; first ("p") alternative by adding ? in the first operand
|
;; might do the trick. We define 'U' as a synonym to 'p', but without the
|
;; might do the trick. We define 'U' as a synonym to 'p', but without the
|
;; caveats (and very small advantages) of 'p'.
|
;; caveats (and very small advantages) of 'p'.
|
(define_insn "*call_real"
|
(define_insn "*call_real"
|
[(call (mem:QI
|
[(call (mem:QI
|
(match_operand:DI 0 "mmix_symbolic_or_address_operand" "s,rU"))
|
(match_operand:DI 0 "mmix_symbolic_or_address_operand" "s,rU"))
|
(match_operand 1 "" ""))
|
(match_operand 1 "" ""))
|
(use (match_operand 2 "" ""))
|
(use (match_operand 2 "" ""))
|
(clobber (reg:DI MMIX_rJ_REGNUM))]
|
(clobber (reg:DI MMIX_rJ_REGNUM))]
|
""
|
""
|
"@
|
"@
|
PUSHJ $%p2,%0
|
PUSHJ $%p2,%0
|
PUSHGO $%p2,%a0")
|
PUSHGO $%p2,%a0")
|
|
|
(define_insn "*call_value_real"
|
(define_insn "*call_value_real"
|
[(set (match_operand 0 "register_operand" "=r,r")
|
[(set (match_operand 0 "register_operand" "=r,r")
|
(call (mem:QI
|
(call (mem:QI
|
(match_operand:DI 1 "mmix_symbolic_or_address_operand" "s,rU"))
|
(match_operand:DI 1 "mmix_symbolic_or_address_operand" "s,rU"))
|
(match_operand 2 "" "")))
|
(match_operand 2 "" "")))
|
(use (match_operand 3 "" ""))
|
(use (match_operand 3 "" ""))
|
(clobber (reg:DI MMIX_rJ_REGNUM))]
|
(clobber (reg:DI MMIX_rJ_REGNUM))]
|
""
|
""
|
"@
|
"@
|
PUSHJ $%p3,%1
|
PUSHJ $%p3,%1
|
PUSHGO $%p3,%a1")
|
PUSHGO $%p3,%a1")
|
|
|
;; I hope untyped_call and untyped_return are not needed for MMIX.
|
;; I hope untyped_call and untyped_return are not needed for MMIX.
|
;; Users of Objective-C will notice.
|
;; Users of Objective-C will notice.
|
|
|
; Generated by GCC.
|
; Generated by GCC.
|
(define_expand "return"
|
(define_expand "return"
|
[(return)]
|
[(return)]
|
"mmix_use_simple_return ()"
|
"mmix_use_simple_return ()"
|
"")
|
"")
|
|
|
; Generated by the epilogue expander.
|
; Generated by the epilogue expander.
|
(define_insn "*expanded_return"
|
(define_insn "*expanded_return"
|
[(return)]
|
[(return)]
|
""
|
""
|
"POP %.,0")
|
"POP %.,0")
|
|
|
(define_expand "prologue"
|
(define_expand "prologue"
|
[(const_int 0)]
|
[(const_int 0)]
|
""
|
""
|
"mmix_expand_prologue (); DONE;")
|
"mmix_expand_prologue (); DONE;")
|
|
|
; Note that the (return) from the expander itself is always the last insn
|
; Note that the (return) from the expander itself is always the last insn
|
; in the epilogue.
|
; in the epilogue.
|
(define_expand "epilogue"
|
(define_expand "epilogue"
|
[(return)]
|
[(return)]
|
""
|
""
|
"mmix_expand_epilogue ();")
|
"mmix_expand_epilogue ();")
|
|
|
(define_insn "nop"
|
(define_insn "nop"
|
[(const_int 0)]
|
[(const_int 0)]
|
""
|
""
|
"SWYM 0,0,0")
|
"SWYM 0,0,0")
|
|
|
(define_insn "jump"
|
(define_insn "jump"
|
[(set (pc) (label_ref (match_operand 0 "" "")))]
|
[(set (pc) (label_ref (match_operand 0 "" "")))]
|
""
|
""
|
"JMP %0")
|
"JMP %0")
|
|
|
(define_insn "indirect_jump"
|
(define_insn "indirect_jump"
|
[(set (pc) (match_operand 0 "address_operand" "p"))]
|
[(set (pc) (match_operand 0 "address_operand" "p"))]
|
""
|
""
|
"GO $255,%a0")
|
"GO $255,%a0")
|
|
|
;; FIXME: This is just a jump, and should be expanded to one.
|
;; FIXME: This is just a jump, and should be expanded to one.
|
(define_insn "tablejump"
|
(define_insn "tablejump"
|
[(set (pc) (match_operand:DI 0 "address_operand" "p"))
|
[(set (pc) (match_operand:DI 0 "address_operand" "p"))
|
(use (label_ref (match_operand 1 "" "")))]
|
(use (label_ref (match_operand 1 "" "")))]
|
""
|
""
|
"GO $255,%a0")
|
"GO $255,%a0")
|
|
|
;; The only peculiar thing is that the register stack has to be unwound at
|
;; The only peculiar thing is that the register stack has to be unwound at
|
;; nonlocal_goto_receiver. At each function that has a nonlocal label, we
|
;; nonlocal_goto_receiver. At each function that has a nonlocal label, we
|
;; save at function entry the location of the "alpha" register stack
|
;; save at function entry the location of the "alpha" register stack
|
;; pointer, rO, in a stack slot known to that function (right below where
|
;; pointer, rO, in a stack slot known to that function (right below where
|
;; the frame-pointer would be located).
|
;; the frame-pointer would be located).
|
;; In the nonlocal goto receiver, we unwind the register stack by a series
|
;; In the nonlocal goto receiver, we unwind the register stack by a series
|
;; of "pop 0,0" until rO equals the saved value. (If it goes lower, we
|
;; of "pop 0,0" until rO equals the saved value. (If it goes lower, we
|
;; should die with a trap.)
|
;; should die with a trap.)
|
(define_expand "nonlocal_goto_receiver"
|
(define_expand "nonlocal_goto_receiver"
|
[(parallel [(unspec_volatile [(const_int 0)] 1)
|
[(parallel [(unspec_volatile [(const_int 0)] 1)
|
(clobber (scratch:DI))
|
(clobber (scratch:DI))
|
(clobber (reg:DI MMIX_rJ_REGNUM))])
|
(clobber (reg:DI MMIX_rJ_REGNUM))])
|
(set (reg:DI MMIX_rJ_REGNUM) (match_dup 0))]
|
(set (reg:DI MMIX_rJ_REGNUM) (match_dup 0))]
|
""
|
""
|
"
|
"
|
{
|
{
|
operands[0]
|
operands[0]
|
= mmix_get_hard_reg_initial_val (Pmode,
|
= mmix_get_hard_reg_initial_val (Pmode,
|
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
|
|
|
/* Mark this function as containing a landing-pad. */
|
/* Mark this function as containing a landing-pad. */
|
cfun->machine->has_landing_pad = 1;
|
cfun->machine->has_landing_pad = 1;
|
}")
|
}")
|
|
|
;; GCC can insist on using saved registers to keep the slot address in
|
;; GCC can insist on using saved registers to keep the slot address in
|
;; "across" the exception, or (perhaps) to use saved registers in the
|
;; "across" the exception, or (perhaps) to use saved registers in the
|
;; address and re-use them after the register stack unwind, so it's best
|
;; address and re-use them after the register stack unwind, so it's best
|
;; to form the address ourselves.
|
;; to form the address ourselves.
|
(define_insn "*nonlocal_goto_receiver_expanded"
|
(define_insn "*nonlocal_goto_receiver_expanded"
|
[(unspec_volatile [(const_int 0)] 1)
|
[(unspec_volatile [(const_int 0)] 1)
|
(clobber (match_scratch:DI 0 "=&r"))
|
(clobber (match_scratch:DI 0 "=&r"))
|
(clobber (reg:DI MMIX_rJ_REGNUM))]
|
(clobber (reg:DI MMIX_rJ_REGNUM))]
|
""
|
""
|
{
|
{
|
rtx temp_reg = operands[0];
|
rtx temp_reg = operands[0];
|
rtx my_operands[2];
|
rtx my_operands[2];
|
HOST_WIDEST_INT offs;
|
HOST_WIDEST_INT offs;
|
const char *my_template
|
const char *my_template
|
= "GETA $255,0f\;PUT rJ,$255\;LDOU $255,%a0\n\
|
= "GETA $255,0f\;PUT rJ,$255\;LDOU $255,%a0\n\
|
0:\;GET %1,rO\;CMPU %1,%1,$255\;BNP %1,1f\;POP 0,0\n1:";
|
0:\;GET %1,rO\;CMPU %1,%1,$255\;BNP %1,1f\;POP 0,0\n1:";
|
|
|
my_operands[1] = temp_reg;
|
my_operands[1] = temp_reg;
|
|
|
/* If we have a frame-pointer (hence unknown stack-pointer offset),
|
/* If we have a frame-pointer (hence unknown stack-pointer offset),
|
just use the frame-pointer and the known offset. */
|
just use the frame-pointer and the known offset. */
|
if (frame_pointer_needed)
|
if (frame_pointer_needed)
|
{
|
{
|
my_operands[0] = GEN_INT (-MMIX_fp_rO_OFFSET);
|
my_operands[0] = GEN_INT (-MMIX_fp_rO_OFFSET);
|
|
|
output_asm_insn ("NEGU %1,0,%0", my_operands);
|
output_asm_insn ("NEGU %1,0,%0", my_operands);
|
my_operands[0] = gen_rtx_PLUS (Pmode, frame_pointer_rtx, temp_reg);
|
my_operands[0] = gen_rtx_PLUS (Pmode, frame_pointer_rtx, temp_reg);
|
}
|
}
|
else
|
else
|
{
|
{
|
/* We know the fp-based offset, so "eliminate" it to be sp-based. */
|
/* We know the fp-based offset, so "eliminate" it to be sp-based. */
|
offs
|
offs
|
= (mmix_initial_elimination_offset (MMIX_FRAME_POINTER_REGNUM,
|
= (mmix_initial_elimination_offset (MMIX_FRAME_POINTER_REGNUM,
|
MMIX_STACK_POINTER_REGNUM)
|
MMIX_STACK_POINTER_REGNUM)
|
+ MMIX_fp_rO_OFFSET);
|
+ MMIX_fp_rO_OFFSET);
|
|
|
if (offs >= 0 && offs <= 255)
|
if (offs >= 0 && offs <= 255)
|
my_operands[0]
|
my_operands[0]
|
= gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offs));
|
= gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offs));
|
else
|
else
|
{
|
{
|
mmix_output_register_setting (asm_out_file, REGNO (temp_reg),
|
mmix_output_register_setting (asm_out_file, REGNO (temp_reg),
|
offs, 1);
|
offs, 1);
|
my_operands[0] = gen_rtx_PLUS (Pmode, stack_pointer_rtx, temp_reg);
|
my_operands[0] = gen_rtx_PLUS (Pmode, stack_pointer_rtx, temp_reg);
|
}
|
}
|
}
|
}
|
|
|
output_asm_insn (my_template, my_operands);
|
output_asm_insn (my_template, my_operands);
|
return "";
|
return "";
|
})
|
})
|
|
|
(define_insn "*Naddu"
|
(define_insn "*Naddu"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(plus:DI (mult:DI (match_operand:DI 1 "register_operand" "r")
|
(plus:DI (mult:DI (match_operand:DI 1 "register_operand" "r")
|
(match_operand:DI 2 "const_int_operand" "n"))
|
(match_operand:DI 2 "const_int_operand" "n"))
|
(match_operand:DI 3 "mmix_reg_or_8bit_operand" "rI")))]
|
(match_operand:DI 3 "mmix_reg_or_8bit_operand" "rI")))]
|
"GET_CODE (operands[2]) == CONST_INT
|
"GET_CODE (operands[2]) == CONST_INT
|
&& (INTVAL (operands[2]) == 2
|
&& (INTVAL (operands[2]) == 2
|
|| INTVAL (operands[2]) == 4
|
|| INTVAL (operands[2]) == 4
|
|| INTVAL (operands[2]) == 8
|
|| INTVAL (operands[2]) == 8
|
|| INTVAL (operands[2]) == 16)"
|
|| INTVAL (operands[2]) == 16)"
|
"%2ADDU %0,%1,%3")
|
"%2ADDU %0,%1,%3")
|
|
|
(define_insn "*andn"
|
(define_insn "*andn"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(and:DI
|
(and:DI
|
(not:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))
|
(not:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))
|
(match_operand:DI 2 "register_operand" "r")))]
|
(match_operand:DI 2 "register_operand" "r")))]
|
""
|
""
|
"ANDN %0,%2,%1")
|
"ANDN %0,%2,%1")
|
|
|
(define_insn "*nand"
|
(define_insn "*nand"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(ior:DI
|
(ior:DI
|
(not:DI (match_operand:DI 1 "register_operand" "%r"))
|
(not:DI (match_operand:DI 1 "register_operand" "%r"))
|
(not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
|
(not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
|
""
|
""
|
"NAND %0,%1,%2")
|
"NAND %0,%1,%2")
|
|
|
(define_insn "*nor"
|
(define_insn "*nor"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(and:DI
|
(and:DI
|
(not:DI (match_operand:DI 1 "register_operand" "%r"))
|
(not:DI (match_operand:DI 1 "register_operand" "%r"))
|
(not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
|
(not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
|
""
|
""
|
"NOR %0,%1,%2")
|
"NOR %0,%1,%2")
|
|
|
(define_insn "*nxor"
|
(define_insn "*nxor"
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
[(set (match_operand:DI 0 "register_operand" "=r")
|
(not:DI
|
(not:DI
|
(xor:DI (match_operand:DI 1 "register_operand" "%r")
|
(xor:DI (match_operand:DI 1 "register_operand" "%r")
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
|
(match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
|
""
|
""
|
"NXOR %0,%1,%2")
|
"NXOR %0,%1,%2")
|
|
|
(define_insn "sync_icache"
|
(define_insn "sync_icache"
|
[(unspec_volatile [(match_operand:DI 0 "memory_operand" "m")
|
[(unspec_volatile [(match_operand:DI 0 "memory_operand" "m")
|
(match_operand:DI 1 "const_int_operand" "I")] 0)]
|
(match_operand:DI 1 "const_int_operand" "I")] 0)]
|
""
|
""
|
"SYNCID %1,%0")
|
"SYNCID %1,%0")
|
|
|
;; Local Variables:
|
;; Local Variables:
|
;; mode: lisp
|
;; mode: lisp
|
;; indent-tabs-mode: t
|
;; indent-tabs-mode: t
|
;; End:
|
;; End:
|
|
|