From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/config/mmix/mmix.md | 1240 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1240 insertions(+) create mode 100644 gcc/config/mmix/mmix.md (limited to 'gcc/config/mmix/mmix.md') diff --git a/gcc/config/mmix/mmix.md b/gcc/config/mmix/mmix.md new file mode 100644 index 000000000..97ab5e131 --- /dev/null +++ b/gcc/config/mmix/mmix.md @@ -0,0 +1,1240 @@ +;; GCC machine description for MMIX +;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010 +;; Free Software Foundation, Inc. +;; Contributed by Hans-Peter Nilsson (hp@bitrange.com) + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; The original PO technology requires these to be ordered by speed, +;; so that assigner will pick the fastest. + +;; See file "rtl.def" for documentation on define_insn, match_*, et al. + +;; Uses of UNSPEC in this file: +;; UNSPEC_VOLATILE: +;; +;; 0 sync_icache (sync icache before trampoline jump) +;; 1 nonlocal_goto_receiver +;; + +;; The order of insns is as in Node: Standard Names, with smaller modes +;; before bigger modes. + +(define_constants + [(MMIX_rJ_REGNUM 259) + (MMIX_rR_REGNUM 260) + (MMIX_fp_rO_OFFSET -24)] +) + +;; Operand and operator predicates. + +(include "predicates.md") + +;; FIXME: Can we remove the reg-to-reg for smaller modes? Shouldn't they +;; be synthesized ok? +(define_insn "movqi" + [(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"))] + "" + "@ + SET %0,%1 + %s1 %0,%v1 + NEGU %0,0,%n1 + PUT %0,%1 + GET %0,%1 + LDB%U0 %0,%1 + STBU %1,%0 + %r0%I1") + +(define_insn "movhi" + [(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"))] + "" + "@ + SET %0,%1 + %s1 %0,%v1 + NEGU %0,0,%n1 + PUT %0,%1 + GET %0,%1 + LDW%U0 %0,%1 + STWU %1,%0 + %r0%I1") + +;; gcc.c-torture/compile/920428-2.c fails if there's no "n". +(define_insn "movsi" + [(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"))] + "" + "@ + SET %0,%1 + %s1 %0,%v1 + NEGU %0,0,%n1 + PUT %0,%1 + GET %0,%1 + LDT%U0 %0,%1 + STTU %1,%0 + %r0%I1") + +;; We assume all "s" are addresses. Does that hold? +(define_insn "movdi" + [(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"))] + "" + "@ + SET %0,%1 + %s1 %0,%v1 + NEGU %0,0,%n1 + PUT %0,%1 + GET %0,%1 + STCO %1,%0 + LDO %0,%1 + STOU %1,%0 + GETA %0,%1 + LDA %0,%1 + %r0%I1") + +;; Note that we move around the float as a collection of bits; no +;; conversion to double. +(define_insn "movsf" + [(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"))] + "" + "@ + SET %0,%1 + SETL %0,0 + PUT %0,%1 + GET %0,%1 + LDT %0,%1 + STTU %1,%0 + %r0%I1") + +(define_insn "movdf" + [(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"))] + "" + "@ + SET %0,%1 + SETL %0,0 + PUT %0,%1 + GET %0,%1 + LDO %0,%1 + STOU %1,%0 + %r0%I1") + +;; We need to be able to move around the values used as condition codes. +;; First spotted as reported in +;; due to +;; 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 +;; we treat them as signed entities; see mmix-modes.def. The following +;; expanders should cover all MODE_CC modes, and expand for this pattern. +(define_insn "*movcc_expanded" + [(set (match_operand 0 "nonimmediate_operand" "=r,x,r,r,m") + (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[1])) == MODE_CC" + "@ + SET %0,%1 + PUT %0,%1 + GET %0,%1 + LDT %0,%1 + STT %1,%0") + +(define_expand "movcc" + [(set (match_operand:CC 0 "nonimmediate_operand" "") + (match_operand:CC 1 "nonimmediate_operand" ""))] + "" + "") + +(define_expand "movcc_uns" + [(set (match_operand:CC_UNS 0 "nonimmediate_operand" "") + (match_operand:CC_UNS 1 "nonimmediate_operand" ""))] + "" + "") + +(define_expand "movcc_fp" + [(set (match_operand:CC_FP 0 "nonimmediate_operand" "") + (match_operand:CC_FP 1 "nonimmediate_operand" ""))] + "" + "") + +(define_expand "movcc_fpeq" + [(set (match_operand:CC_FPEQ 0 "nonimmediate_operand" "") + (match_operand:CC_FPEQ 1 "nonimmediate_operand" ""))] + "" + "") + +(define_expand "movcc_fun" + [(set (match_operand:CC_FUN 0 "nonimmediate_operand" "") + (match_operand:CC_FUN 1 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (plus:DI + (match_operand:DI 1 "register_operand" "%r,r,0") + (match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,K,LS")))] + "" + "@ + ADDU %0,%1,%2 + SUBU %0,%1,%n2 + %i2 %0,%v2") + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FADD %0,%1,%2") + +;; Insn canonicalization *should* have removed the need for an integer +;; in operand 2. +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (minus:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "r,I") + (match_operand:DI 2 "register_operand" "r,r")))] + "" + "@ + SUBU %0,%1,%2 + NEGU %0,%1,%2") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FSUB %0,%1,%2") + +;; 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 +;; we don't have to taint the machine description. If results are bad +;; enough, we may have to do it anyway. +(define_insn "muldi3" + [(set (match_operand:DI 0 "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"))) + (clobber (match_scratch:DI 3 "=X,z"))] + "" + "@ + %m2ADDU %0,%1,%1 + MULU %0,%1,%2") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FMUL %0,%1,%2") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FDIV %0,%1,%2") + +;; FIXME: Is "frem" doing the right operation for moddf3? +(define_insn "moddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mod:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FREM %0,%1,%2") + +;; FIXME: Should we define_expand for smin, smax, umin, umax using a +;; nifty conditional sequence? + +;; FIXME: The cuter andn combinations don't get here, presumably because +;; they ended up in the constant pool. Check: still? +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (and:DI + (match_operand:DI 1 "register_operand" "%r,0") + (match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,NT")))] + "" + "@ + AND %0,%1,%2 + %A2 %0,%V2") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (ior:DI (match_operand:DI 1 "register_operand" "%r,0") + (match_operand:DI 2 "mmix_reg_or_constant_operand" "rH,LS")))] + "" + "@ + OR %0,%1,%2 + %o2 %0,%v2") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (match_operand:DI 1 "register_operand" "%r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] + "" + "XOR %0,%1,%2") + +;; FIXME: When TImode works for other reasons (like cross-compiling from +;; a 32-bit host), add back umulditi3 and umuldi3_highpart here. + +;; FIXME: Check what's really reasonable for the mod part. + +;; 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 +;; 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, +;; 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 +;; the remainder must follow the sign of the dividend. + +(define_insn "divmoddi4" + [(set (match_operand:DI 0 "register_operand" "=r") + (div:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))) + (set (match_operand:DI 3 "register_operand" "=y") + (mod:DI (match_dup 1) (match_dup 2)))] + ;; Do the library stuff later. + "TARGET_KNUTH_DIVISION" + "DIV %0,%1,%2") + +(define_insn "udivmoddi4" + [(set (match_operand:DI 0 "register_operand" "=r") + (udiv:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))) + (set (match_operand:DI 3 "register_operand" "=y") + (umod:DI (match_dup 1) (match_dup 2)))] + "" + "DIVU %0,%1,%2") + +(define_expand "divdi3" + [(parallel + [(set (match_operand:DI 0 "register_operand" "=&r") + (div:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r"))) + (clobber (scratch:DI)) + (clobber (scratch:DI)) + (clobber (reg:DI MMIX_rR_REGNUM))])] + "! TARGET_KNUTH_DIVISION" + "") + +;; The %2-is-%1-case is there just to make sure things don't fail. Could +;; presumably happen with optimizations off; no evidence. +(define_insn "*divdi3_nonknuth" + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (div:DI (match_operand:DI 1 "register_operand" "r,r") + (match_operand:DI 2 "register_operand" "1,r"))) + (clobber (match_scratch:DI 3 "=1,1")) + (clobber (match_scratch:DI 4 "=2,2")) + (clobber (reg:DI MMIX_rR_REGNUM))] + "! TARGET_KNUTH_DIVISION" + "@ + SETL %0,1 + 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") + +(define_expand "moddi3" + [(parallel + [(set (match_operand:DI 0 "register_operand" "=&r") + (mod:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r"))) + (clobber (scratch:DI)) + (clobber (scratch:DI)) + (clobber (reg:DI MMIX_rR_REGNUM))])] + "! TARGET_KNUTH_DIVISION" + "") + +;; The %2-is-%1-case is there just to make sure things don't fail. Could +;; presumably happen with optimizations off; no evidence. +(define_insn "*moddi3_nonknuth" + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (mod:DI (match_operand:DI 1 "register_operand" "r,r") + (match_operand:DI 2 "register_operand" "1,r"))) + (clobber (match_scratch:DI 3 "=1,1")) + (clobber (match_scratch:DI 4 "=2,2")) + (clobber (reg:DI MMIX_rR_REGNUM))] + "! TARGET_KNUTH_DIVISION" + "@ + SETL %0,0 + 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") + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI + (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] + "" + "SLU %0,%1,%2") + +(define_insn "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI + (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] + "" + "SR %0,%1,%2") + +(define_insn "lshrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI + (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] + "" + "SRU %0,%1,%2") + +(define_insn "negdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (neg:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "NEGU %0,0,%1") + +(define_expand "negdf2" + [(parallel [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r"))) + (use (match_dup 2))])] + "" +{ + /* Emit bit-flipping sequence to be IEEE-safe wrt. -+0. */ + operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63)); +}) + +(define_insn "*expanded_negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r"))) + (use (match_operand:DI 2 "register_operand" "r"))] + "" + "XOR %0,%1,%2") + +;; FIXME: define_expand for absdi2? + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (abs:DF (match_operand:DF 1 "register_operand" "0")))] + "" + "ANDNH %0,#8000") + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (sqrt:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "FSQRT %0,%1") + +;; FIXME: define_expand for ffssi2? (not ffsdi2 since int is SImode). + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (not:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "NOR %0,%1,0") + +;; When the user-patterns expand, the resulting insns will match the +;; patterns below. + +;; We can fold the signed-compare where the register value is +;; already equal to (compare:CCTYPE (reg) (const_int 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 +;; unsigned, so that has to be done another way. +;; FIXME: Perhaps a peep2 changing CCcode to a new code, that +;; gets folded here. +(define_insn "*cmpdi_folded" + [(set (match_operand:CC 0 "register_operand" "=r") + (compare:CC + (match_operand:DI 1 "register_operand" "r") + (const_int 0)))] + ;; FIXME: Can we test equivalence any other way? + ;; FIXME: Can we fold any other way? + "REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[1]) == REGNO (operands[0])" + "%% folded: cmp %0,%1,0") + +(define_insn "*cmps" + [(set (match_operand:CC 0 "register_operand" "=r") + (compare:CC + (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] + "" + "CMP %0,%1,%2") + +(define_insn "*cmpu" + [(set (match_operand:CC_UNS 0 "register_operand" "=r") + (compare:CC_UNS + (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] + "" + "CMPU %0,%1,%2") + +(define_insn "*fcmp" + [(set (match_operand:CC_FP 0 "register_operand" "=r") + (compare:CC_FP + (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FCMP%e0 %0,%1,%2") + +;; FIXME: for -mieee, add fsub %0,%1,%1\;fsub %0,%2,%2 before to +;; make signalling compliant. +(define_insn "*feql" + [(set (match_operand:CC_FPEQ 0 "register_operand" "=r") + (compare:CC_FPEQ + (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FEQL%e0 %0,%1,%2") + +(define_insn "*fun" + [(set (match_operand:CC_FUN 0 "register_operand" "=r") + (compare:CC_FUN + (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "FUN%e0 %0,%1,%2") + +;; 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, +;; with rounding as of SFmode. They are not usable as is, but we pretend +;; we have a single instruction but emit two. + +;; Note that this will (somewhat unexpectedly) create an inexact +;; exception if rounding is necessary - has to be masked off in crt0? +(define_expand "floatdisf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm") + (float:SF + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) + ;; 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 + ;; doesn't logically follow from operands in the pattern. + (clobber (match_scratch:DI 2 "=&r"))])] + "" + " +{ + if (GET_CODE (operands[0]) != MEM) + { + rtx stack_slot; + + /* FIXME: This stack-slot remains even at -O3. There must be a + better way. */ + stack_slot + = validize_mem (assign_stack_temp (SFmode, + GET_MODE_SIZE (SFmode), 0)); + emit_insn (gen_floatdisf2 (stack_slot, operands[1])); + emit_move_insn (operands[0], stack_slot); + DONE; + } +}") + +(define_insn "*floatdisf2_real" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float:SF + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "SFLOT %2,%1\;STSF %2,%0") + +(define_expand "floatunsdisf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm") + (unsigned_float:SF + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) + ;; 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 + ;; doesn't logically follow from operands in the pattern. + (clobber (scratch:DI))])] + "" + " +{ + if (GET_CODE (operands[0]) != MEM) + { + rtx stack_slot; + + /* FIXME: This stack-slot remains even at -O3. Must be a better + way. */ + stack_slot + = validize_mem (assign_stack_temp (SFmode, + GET_MODE_SIZE (SFmode), 0)); + emit_insn (gen_floatunsdisf2 (stack_slot, operands[1])); + emit_move_insn (operands[0], stack_slot); + DONE; + } +}") + +(define_insn "*floatunsdisf2_real" + [(set (match_operand:SF 0 "memory_operand" "=m") + (unsigned_float:SF + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "SFLOTU %2,%1\;STSF %2,%0") + +;; Note that this will (somewhat unexpectedly) create an inexact +;; exception if rounding is necessary - has to be masked off in crt0? +(define_insn "floatdidf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float:DF + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))] + "" + "FLOT %0,%1") + +(define_insn "floatunsdidf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unsigned_float:DF + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))] + "" + "FLOTU %0,%1") + +(define_insn "ftruncdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (fix:DF (match_operand:DF 1 "register_operand" "r")))] + "" + ;; ROUND_OFF + "FINT %0,1,%1") + +;; Note that this will (somewhat unexpectedly) create an inexact +;; exception if rounding is necessary - has to be masked off in crt0? +(define_insn "fix_truncdfdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "r"))))] + "" + ;; ROUND_OFF + "FIX %0,1,%1") + +(define_insn "fixuns_truncdfdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (unsigned_fix:DI + (fix:DF (match_operand:DF 1 "register_operand" "r"))))] + "" + ;; ROUND_OFF + "FIXU %0,1,%1") + +;; It doesn't seem like it's possible to have memory_operand as a +;; predicate here (testcase: libgcc2 floathisf). FIXME: Shouldn't it be +;; 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 +;; define_expand with the old pattern as "anonymous". +;; FIXME: Perhaps with SECONDARY_MEMORY_NEEDED? +(define_expand "truncdfsf2" + [(set (match_operand:SF 0 "memory_operand" "") + (float_truncate:SF (match_operand:DF 1 "register_operand" "")))] + "" + " +{ + if (GET_CODE (operands[0]) != MEM) + { + /* FIXME: There should be a way to say: 'put this in operands[0] + but *after* the expanded insn'. */ + rtx stack_slot; + + /* 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.) */ + if (! REG_P (operands[0])) + internal_error (\"MMIX Internal: Bad truncdfsf2 expansion\"); + + /* FIXME: This stack-slot remains even at -O3. Must be a better + way. */ + stack_slot + = validize_mem (assign_stack_temp (SFmode, + GET_MODE_SIZE (SFmode), 0)); + emit_insn (gen_truncdfsf2 (stack_slot, operands[1])); + emit_move_insn (operands[0], stack_slot); + DONE; + } +}") + +(define_insn "*truncdfsf2_real" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_truncate:SF (match_operand:DF 1 "register_operand" "r")))] + "" + "STSF %1,%0") + +;; Same comment as for truncdfsf2. +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float_extend:DF (match_operand:SF 1 "memory_operand" "m")))] + "" + " +{ + if (GET_CODE (operands[1]) != MEM) + { + rtx stack_slot; + + /* 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.) */ + if (! REG_P (operands[0])) + internal_error (\"MMIX Internal: Bad extendsfdf2 expansion\"); + + /* FIXME: This stack-slot remains even at -O3. There must be a + better way. */ + stack_slot + = validize_mem (assign_stack_temp (SFmode, + GET_MODE_SIZE (SFmode), 0)); + emit_move_insn (stack_slot, operands[1]); + emit_insn (gen_extendsfdf2 (operands[0], stack_slot)); + DONE; + } +}") + +(define_insn "*extendsfdf2_real" + [(set (match_operand:DF 0 "register_operand" "=r") + (float_extend:DF (match_operand:SF 1 "memory_operand" "m")))] + "" + "LDSF %0,%1") + +;; Neither sign-extend nor zero-extend are necessary; gcc knows how to +;; synthesize using shifts or and, except with a memory source and not +;; completely optimal. FIXME: Actually, other bugs surface when those +;; patterns are defined; fix later. + +;; There are no sane values with the bit-patterns of (int) 0..255 except +;; 0 to use in movdfcc. + +(define_expand "movdfcc" + [(set (match_dup 4) (match_dup 5)) + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF + (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "mmix_reg_or_0_operand" "") + (match_operand:DF 3 "mmix_reg_or_0_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + if (code == LE || code == GE) + FAIL; + + operands[4] = mmix_gen_compare_reg (code, XEXP (operands[1], 0), + XEXP (operands[1], 1)); + operands[5] = gen_rtx_COMPARE (GET_MODE (operands[4]), + XEXP (operands[1], 0), + XEXP (operands[1], 1)); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, operands[4], const0_rtx); +}") + +(define_expand "movdicc" + [(set (match_dup 4) (match_dup 5)) + (set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI + (match_operand 1 "comparison_operator" "") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "") + (match_operand:DI 3 "mmix_reg_or_8bit_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + if (code == LE || code == GE) + FAIL; + + operands[4] = mmix_gen_compare_reg (code, XEXP (operands[1], 0), + XEXP (operands[1], 1)); + operands[5] = gen_rtx_COMPARE (GET_MODE (operands[4]), + XEXP (operands[1], 0), + XEXP (operands[1], 1)); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, operands[4], const0_rtx); +}") + +;; FIXME: Is this the right way to do "folding" of CCmode -> DImode? +(define_insn "*movdicc_real_foldable" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") + (if_then_else:DI + (match_operator 2 "mmix_foldable_comparison_operator" + [(match_operand:DI 3 "register_operand" "r,r,r,r") + (const_int 0)]) + (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")))] + "" + "@ + CS%d2 %0,%3,%1 + CS%D2 %0,%3,%4 + ZS%d2 %0,%3,%1 + ZS%D2 %0,%3,%4") + +(define_insn "*movdicc_real_reversible" + [(set + (match_operand:DI 0 "register_operand" "=r ,r ,r ,r") + (if_then_else:DI + (match_operator + 2 "mmix_comparison_operator" + [(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r") + (const_int 0)]) + (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")))] + "REVERSIBLE_CC_MODE (GET_MODE (operands[3]))" + "@ + CS%d2 %0,%3,%1 + CS%D2 %0,%3,%4 + ZS%d2 %0,%3,%1 + ZS%D2 %0,%3,%4") + +(define_insn "*movdicc_real_nonreversible" + [(set + (match_operand:DI 0 "register_operand" "=r ,r") + (if_then_else:DI + (match_operator + 2 "mmix_comparison_operator" + [(match_operand 3 "mmix_reg_cc_operand" "r ,r") + (const_int 0)]) + (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,rI") + (match_operand:DI 4 "mmix_reg_or_0_operand" "0 ,GM")))] + "!REVERSIBLE_CC_MODE (GET_MODE (operands[3]))" + "@ + CS%d2 %0,%3,%1 + ZS%d2 %0,%3,%1") + +(define_insn "*movdfcc_real_foldable" + [(set + (match_operand:DF 0 "register_operand" "=r ,r ,r ,r") + (if_then_else:DF + (match_operator + 2 "mmix_foldable_comparison_operator" + [(match_operand:DI 3 "register_operand" "r ,r ,r ,r") + (const_int 0)]) + (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")))] + "" + "@ + CS%d2 %0,%3,%1 + CS%D2 %0,%3,%4 + ZS%d2 %0,%3,%1 + ZS%D2 %0,%3,%4") + +(define_insn "*movdfcc_real_reversible" + [(set + (match_operand:DF 0 "register_operand" "=r ,r ,r ,r") + (if_then_else:DF + (match_operator + 2 "mmix_comparison_operator" + [(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r") + (const_int 0)]) + (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")))] + "REVERSIBLE_CC_MODE (GET_MODE (operands[3]))" + "@ + CS%d2 %0,%3,%1 + CS%D2 %0,%3,%4 + ZS%d2 %0,%3,%1 + ZS%D2 %0,%3,%4") + +(define_insn "*movdfcc_real_nonreversible" + [(set + (match_operand:DF 0 "register_operand" "=r ,r") + (if_then_else:DF + (match_operator + 2 "mmix_comparison_operator" + [(match_operand 3 "mmix_reg_cc_operand" "r ,r") + (const_int 0)]) + (match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,rGM") + (match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,GM")))] + "!REVERSIBLE_CC_MODE (GET_MODE (operands[3]))" + "@ + CS%d2 %0,%3,%1 + ZS%d2 %0,%3,%1") + +;; FIXME: scc insns will probably help, I just skip them +;; right now. Revisit. + +(define_expand "cbranchdi4" + [(set (match_dup 4) + (match_op_dup 5 + [(match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "")])) + (set (pc) + (if_then_else + (match_operator 0 "ordered_comparison_operator" + [(match_dup 4) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + " +{ + operands[4] = mmix_gen_compare_reg (GET_CODE (operands[0]), + operands[1], operands[2]); + operands[5] = gen_rtx_fmt_ee (COMPARE, + GET_MODE (operands[4]), + operands[1], operands[2]); +}") + +(define_expand "cbranchdf4" + [(set (match_dup 4) + (match_op_dup 5 + [(match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "register_operand" "")])) + (set (pc) + (if_then_else + (match_operator 0 "float_comparison_operator" + [(match_dup 4) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + " +{ + /* 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. */ + if (GET_CODE (operands[0]) == LE || GET_CODE (operands[0]) == GE) + { + enum rtx_code ltgt_code = GET_CODE (operands[0]) == LE ? LT : GT; + emit_cmp_and_jump_insns (operands[1], operands[2], ltgt_code, NULL_RTX, + DFmode, 0, operands[3]); + emit_cmp_and_jump_insns (operands[1], operands[2], EQ, NULL_RTX, + DFmode, 0, operands[3]); + DONE; + } + + operands[4] = mmix_gen_compare_reg (GET_CODE (operands[0]), + operands[1], operands[2]); + operands[5] = gen_rtx_fmt_ee (COMPARE, + GET_MODE (operands[4]), + operands[1], operands[2]); +}") + + +;; 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. + +;; FIXME: Odd/Even matchers? +(define_insn "*bCC_foldable" + [(set (pc) + (if_then_else + (match_operator 1 "mmix_foldable_comparison_operator" + [(match_operand:DI 2 "register_operand" "r") + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "%+B%d1 %2,%0") + +(define_insn "*bCC" + [(set (pc) + (if_then_else + (match_operator 1 "mmix_comparison_operator" + [(match_operand 2 "mmix_reg_cc_operand" "r") + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "%+B%d1 %2,%0") + +(define_insn "*bCC_inverted_foldable" + [(set (pc) + (if_then_else + (match_operator 1 "mmix_foldable_comparison_operator" + [(match_operand:DI 2 "register_operand" "r") + (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] +;; REVERSIBLE_CC_MODE is checked by mmix_foldable_comparison_operator. + "" + "%+B%D1 %2,%0") + +(define_insn "*bCC_inverted" + [(set (pc) + (if_then_else + (match_operator 1 "mmix_comparison_operator" + [(match_operand 2 "mmix_reg_cc_operand" "r") + (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "REVERSIBLE_CC_MODE (GET_MODE (operands[2]))" + "%+B%D1 %2,%0") + +(define_expand "call" + [(parallel [(call (match_operand:QI 0 "memory_operand" "") + (match_operand 1 "general_operand" "")) + (use (match_operand 2 "general_operand" "")) + (clobber (match_dup 4))]) + (set (match_dup 4) (match_dup 3))] + "" + " +{ + /* The caller checks that the operand is generally valid as an + address, but at -O0 nothing makes sure that it's also a valid + call address for a *call*; a mmix_symbolic_or_address_operand. + Force into a register if it isn't. */ + if (!mmix_symbolic_or_address_operand (XEXP (operands[0], 0), + GET_MODE (XEXP (operands[0], 0)))) + operands[0] + = replace_equiv_address (operands[0], + force_reg (Pmode, XEXP (operands[0], 0))); + + /* 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 + will be optimized away), integrity is maintained. */ + operands[3] + = mmix_get_hard_reg_initial_val (Pmode, + MMIX_INCOMING_RETURN_ADDRESS_REGNUM); + + /* 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. + Work around it by replacing it with const_int 0. Possibly documentation + error too. */ + if (operands[2] == NULL_RTX) + operands[2] = const0_rtx; + + operands[4] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM); +}") + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand 2 "general_operand" ""))) + (use (match_operand 3 "general_operand" "")) + (clobber (match_dup 5))]) + (set (match_dup 5) (match_dup 4))] + "" + " +{ + /* The caller checks that the operand is generally valid as an + address, but at -O0 nothing makes sure that it's also a valid + call address for a *call*; a mmix_symbolic_or_address_operand. + Force into a register if it isn't. */ + if (!mmix_symbolic_or_address_operand (XEXP (operands[1], 0), + GET_MODE (XEXP (operands[1], 0)))) + operands[1] + = replace_equiv_address (operands[1], + force_reg (Pmode, XEXP (operands[1], 0))); + + /* 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 + will be optimized away), integrity is maintained. */ + operands[4] + = mmix_get_hard_reg_initial_val (Pmode, + MMIX_INCOMING_RETURN_ADDRESS_REGNUM); + + /* FIXME: See 'call'. */ + if (operands[3] == NULL_RTX) + operands[3] = const0_rtx; + + /* FIXME: Documentation bug: operands[3] (operands[2] for 'call') is the + *next* argument register, not the number of arguments in registers. + (There used to be code here where that mattered.) */ + + 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 +;; messes up, not registering the address for reload. Several C++ +;; 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 +;; condition <> and the comment on +;; ~3017 that says: +;; << case 'p': +;; /* All necessary reloads for an address_operand +;; were handled in find_reloads_address. */>> +;; Sorry, I have not dug deeper. If symbolic addresses are used +;; rarely compared to addresses in registers, disparaging the +;; first ("p") alternative by adding ? in the first operand +;; might do the trick. We define 'U' as a synonym to 'p', but without the +;; caveats (and very small advantages) of 'p'. +(define_insn "*call_real" + [(call (mem:QI + (match_operand:DI 0 "mmix_symbolic_or_address_operand" "s,rU")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (reg:DI MMIX_rJ_REGNUM))] + "" + "@ + PUSHJ $%p2,%0 + PUSHGO $%p2,%a0") + +(define_insn "*call_value_real" + [(set (match_operand 0 "register_operand" "=r,r") + (call (mem:QI + (match_operand:DI 1 "mmix_symbolic_or_address_operand" "s,rU")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:DI MMIX_rJ_REGNUM))] + "" + "@ + PUSHJ $%p3,%1 + PUSHGO $%p3,%a1") + +;; I hope untyped_call and untyped_return are not needed for MMIX. +;; Users of Objective-C will notice. + +; Generated by GCC. +(define_expand "return" + [(return)] + "mmix_use_simple_return ()" + "") + +; Generated by the epilogue expander. +(define_insn "*expanded_return" + [(return)] + "" + "POP %.,0") + +(define_expand "prologue" + [(const_int 0)] + "" + "mmix_expand_prologue (); DONE;") + +; Note that the (return) from the expander itself is always the last insn +; in the epilogue. +(define_expand "epilogue" + [(return)] + "" + "mmix_expand_epilogue ();") + +(define_insn "nop" + [(const_int 0)] + "" + "SWYM 0,0,0") + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "JMP %0") + +(define_insn "indirect_jump" + [(set (pc) (match_operand 0 "address_operand" "p"))] + "" + "GO $255,%a0") + +;; FIXME: This is just a jump, and should be expanded to one. +(define_insn "tablejump" + [(set (pc) (match_operand:DI 0 "address_operand" "p")) + (use (label_ref (match_operand 1 "" "")))] + "" + "GO $255,%a0") + +;; 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 +;; save at function entry the location of the "alpha" register stack +;; pointer, rO, in a stack slot known to that function (right below where +;; the frame-pointer would be located). +;; 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 +;; should die with a trap.) +(define_expand "nonlocal_goto_receiver" + [(parallel [(unspec_volatile [(const_int 0)] 1) + (clobber (scratch:DI)) + (clobber (reg:DI MMIX_rJ_REGNUM))]) + (set (reg:DI MMIX_rJ_REGNUM) (match_dup 0))] + "" + " +{ + operands[0] + = mmix_get_hard_reg_initial_val (Pmode, + MMIX_INCOMING_RETURN_ADDRESS_REGNUM); + + /* Mark this function as containing a landing-pad. */ + cfun->machine->has_landing_pad = 1; +}") + +;; GCC can insist on using saved registers to keep the slot address in +;; "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 +;; to form the address ourselves. +(define_insn "*nonlocal_goto_receiver_expanded" + [(unspec_volatile [(const_int 0)] 1) + (clobber (match_scratch:DI 0 "=&r")) + (clobber (reg:DI MMIX_rJ_REGNUM))] + "" +{ + rtx temp_reg = operands[0]; + rtx my_operands[2]; + HOST_WIDEST_INT offs; + const char *my_template + = "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:"; + + my_operands[1] = temp_reg; + + /* If we have a frame-pointer (hence unknown stack-pointer offset), + just use the frame-pointer and the known offset. */ + if (frame_pointer_needed) + { + my_operands[0] = GEN_INT (-MMIX_fp_rO_OFFSET); + + output_asm_insn ("NEGU %1,0,%0", my_operands); + my_operands[0] = gen_rtx_PLUS (Pmode, frame_pointer_rtx, temp_reg); + } + else + { + /* We know the fp-based offset, so "eliminate" it to be sp-based. */ + offs + = (mmix_initial_elimination_offset (MMIX_FRAME_POINTER_REGNUM, + MMIX_STACK_POINTER_REGNUM) + + MMIX_fp_rO_OFFSET); + + if (offs >= 0 && offs <= 255) + my_operands[0] + = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offs)); + else + { + mmix_output_register_setting (asm_out_file, REGNO (temp_reg), + offs, 1); + my_operands[0] = gen_rtx_PLUS (Pmode, stack_pointer_rtx, temp_reg); + } + } + + output_asm_insn (my_template, my_operands); + return ""; +}) + +(define_insn "*Naddu" + [(set (match_operand:DI 0 "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 3 "mmix_reg_or_8bit_operand" "rI")))] + "GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 2 + || INTVAL (operands[2]) == 4 + || INTVAL (operands[2]) == 8 + || INTVAL (operands[2]) == 16)" + "%2ADDU %0,%1,%3") + +(define_insn "*andn" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI + (not:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")) + (match_operand:DI 2 "register_operand" "r")))] + "" + "ANDN %0,%2,%1") + +(define_insn "*nand" + [(set (match_operand:DI 0 "register_operand" "=r") + (ior:DI + (not:DI (match_operand:DI 1 "register_operand" "%r")) + (not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))] + "" + "NAND %0,%1,%2") + +(define_insn "*nor" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI + (not:DI (match_operand:DI 1 "register_operand" "%r")) + (not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))] + "" + "NOR %0,%1,%2") + +(define_insn "*nxor" + [(set (match_operand:DI 0 "register_operand" "=r") + (not:DI + (xor:DI (match_operand:DI 1 "register_operand" "%r") + (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))] + "" + "NXOR %0,%1,%2") + +(define_insn "sync_icache" + [(unspec_volatile [(match_operand:DI 0 "memory_operand" "m") + (match_operand:DI 1 "const_int_operand" "I")] 0)] + "" + "SYNCID %1,%0") + +;; Local Variables: +;; mode: lisp +;; indent-tabs-mode: t +;; End: -- cgit v1.2.3