diff options
Diffstat (limited to 'gcc-1.40/config')
123 files changed, 62053 insertions, 0 deletions
diff --git a/gcc-1.40/config/alliant.md b/gcc-1.40/config/alliant.md new file mode 100644 index 0000000..0dffea3 --- /dev/null +++ b/gcc-1.40/config/alliant.md @@ -0,0 +1,2784 @@ +;;- Machine description for GNU C compiler for Alliant FX systems +;; Copyright (C) 1989 Free Software Foundation, Inc. +;; Adapted from m68k.md by Paul Petersen (petersen@uicsrd.csrd.uiuc.edu) +;; and Joe Weening (weening@gang-of-four.stanford.edu). + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- instruction definitions + +;;- @@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. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' one of the address registers can be used. +;;- 'd' one of the data registers can be used. +;;- 'f' one of the CE floating point registers can be used +;;- 'r' either a data or an address register can be used. + +;;- Immediate integer operand constraints: +;;- 'I' 1 .. 8 +;;- 'J' -32768 .. 32767 +;;- 'K' -128 .. 127 +;;- 'L' -8 .. -1 + +;;- Some remnants of constraint codes for the m68k ('x','y','G','H') +;;- may remain in the insn definitions. + +;;- Some of these insn's are composites of several Alliant op codes. +;;- The assembler (or final @@??) insures that the appropriate one is +;;- selected. + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +{ + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) + return \"tst%.l %0\"; + /* If you think that the 68020 does not support tstl a0, + reread page B-167 of the 68020 manual more carefully. */ + /* On an address reg, cmpw may replace cmpl. */ + return \"cmp%.w %#0,%0\"; +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "rm"))] + "" + "* +{ + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) + return \"tst%.w %0\"; + return \"cmp%.w %#0,%0\"; +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "dm"))] + "" + "tst%.b %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "nonimmediate_operand" "fm"))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + return \"ftest%.s %0\"; +}") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "nonimmediate_operand" "fm"))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + return \"ftest%.d %0\"; +}") + +;; compare instructions. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +;; A composite of the cmp, cmpa, & cmpi m68000 op codes. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "rKs,mr,>") + (match_operand:SI 1 "general_operand" "mr,Ksr,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.l %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return \"cmp%.l %d0,%d1\"; + } + return \"cmp%.l %d1,%d0\"; +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "rnm,d,n,m") + (match_operand:HI 1 "general_operand" "d,rnm,m,n")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.w %1,%0\"; + if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1])) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; + return \"cmp%.w %d0,%d1\"; + } + return \"cmp%.w %d1,%d0\"; +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "dn,md,>") + (match_operand:QI 1 "general_operand" "dm,nd,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.b %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return \"cmp%.b %d0,%d1\"; + } + return \"cmp%.b %d1,%d0\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "nonimmediate_operand" "f,m") + (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + if (FP_REG_P (operands[0])) + return \"fcmp%.d %1,%0\"; + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %0,%1\"; +}") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonimmediate_operand" "f,m") + (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + if (FP_REG_P (operands[0])) + return \"fcmp%.s %1,%0\"; + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %0,%1\"; +}") + +;; Recognizers for btst instructions. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; The following two patterns are like the previous two +;; except that they use the fact that bit-number operands +;; are automatically masked to 3 or 5 bits. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 7)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 31)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; Nonoffsettable mem refs are ok in this one pattern +;; since we don't try to adjust them. +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "md") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 8" + "* +{ + operands[1] = gen_rtx (CONST_INT, VOIDmode, 7 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +(define_insn "" + ;; The constraint "o,d" here means that a nonoffsettable memref + ;; will match the first alternative, and its address will be reloaded. + ;; Copying the memory contents into a reg would be incorrect if the + ;; bit position is over 7. + [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "o,d") + (const_int 1) + (match_operand:SI 1 "general_operand" "i,i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 15 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 15); +}") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "do") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 31 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 31); +}") + +(define_insn "" + [(set (cc0) (subreg:SI (lshiftrt:QI (match_operand:QI 0 "nonimmediate_operand" "dm") + (const_int 7)) + 0))] + "" + "* +{ + cc_status.flags = CC_Z_IN_NOT_N | CC_NOT_NEGATIVE; + return \"tst%.b %0\"; +}") + +(define_insn "" + [(set (cc0) (and:SI (sign_extend:SI (sign_extend:HI (match_operand:QI 0 "nonimmediate_operand" "dm"))) + (match_operand:SI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 0x100 + && exact_log2 (INTVAL (operands[1])) >= 0)" + "* +{ register int log = exact_log2 (INTVAL (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, log); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +;; move instructions + +;; A special case in which it is not desirable +;; to reload the constant into a data register. +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "general_operand" "J"))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -0x8000 + && INTVAL (operands[1]) < 0x8000" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.l %0\"; + return \"pea %a1\"; +}") + +;This is never used. +;(define_insn "swapsi" +; [(set (match_operand:SI 0 "general_operand" "r") +; (match_operand:SI 1 "general_operand" "r")) +; (set (match_dup 1) (match_dup 0))] +; "" +; "exg %1,%0") + +;; Special case of fullword move when source is zero. +;; The reason this is special is to avoid loading a zero +;; into a data reg with moveq in order to store it elsewhere. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (const_int 0))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"sub%.l %0,%0\"; + return \"clr%.l %0\"; +}") + +;; General case of fullword move. The register constraints +;; force integer constants in range for a moveq to be reloaded +;; if they are headed for memory. +(define_insn "movsi" + ;; Notes: make sure no alternative allows g vs g. + ;; We don't allow f-regs since fixed point cannot go in them. + ;; We do allow y and x regs since fixed point is allowed in them. + [(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m") + (match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM)) + return \"clr%.l %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + return \"moveq %1,%0\"; + else if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"mov%.w %1,%0\"; + else if (push_operand (operands[0], SImode) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"pea %a1\"; + } + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && push_operand (operands[0], SImode)) + return \"pea %a1\"; + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && ADDRESS_REG_P (operands[0])) + return \"lea %a1,%0\"; + return \"mov%.l %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM)) + return \"clr%.w %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { + return \"moveq %1,%0\"; + } + else if (INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"mov%.w %1,%0\"; + } + else if (CONSTANT_P (operands[1])) + return \"mov%.l %1,%0\"; + /* Recognize the insn before a tablejump, one that refers + to a table of offsets. Such an insn will need to refer + to a label on the insn. So output one. Use the label-number + of the table of offsets to generate this label. */ + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + || GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF) + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) != PLUS) + { + rtx labelref; + if (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF) + labelref = XEXP (XEXP (operands[1], 0), 0); + else + labelref = XEXP (XEXP (operands[1], 0), 1); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); + } + return \"mov%.w %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (match_operand:HI 1 "general_operand" "rmn"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM)) + return \"clr%.w %0\"; + } + return \"mov%.w %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=d,*a,m,m,?*a") + (match_operand:QI 1 "general_operand" "dmi*a,d*a,dmi,?*a,m"))] + "" + "* +{ + rtx xoperands[4]; + if (ADDRESS_REG_P (operands[0]) && GET_CODE (operands[1]) == MEM) + { + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + /* Just pushing a byte puts it in the high byte of the halfword. */ + /* We must put it in the low half, the second byte. */ + output_asm_insn (\"subq%.w %#2,%3\;mov%.b %1,%2\", xoperands); + return \"mov%.w %+,%0\"; + } + if (ADDRESS_REG_P (operands[1]) && GET_CODE (operands[0]) == MEM) + { + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + output_asm_insn (\"mov%.w %1,%-\;mov%.b %2,%0\;addq%.w %#2,%3\", xoperands); + return \"\"; + } + if (operands[1] == const0_rtx) + return \"clr%.b %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"st %0\"; + if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) + return \"mov%.l %1,%0\"; + if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) + return \"mov%.w %1,%0\"; + return \"mov%.b %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (match_operand:QI 1 "general_operand" "dmn"))] + "" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.b %0\"; + return \"mov%.b %1,%0\"; +}") + +;; Floating-point moves on a CE are faster using an FP register than +;; with movl instructions. (Especially for double floats, but also +;; for single floats, even though it takes an extra instruction.) But +;; on an IP, the FP registers are simulated and so should be avoided. +;; We do this by using define_expand for movsf and movdf, and using +;; different constraints for each target type. The constraints for +;; TARGET_CE allow general registers because they sometimes need to +;; hold floats, but they are not preferable. + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f,m,!*r,!f*m") + (match_operand:SF 1 "nonimmediate_operand" "fm,f,f*r*m,*r"))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.s %1,%0\"; + if (REG_P (operands[1])) + return \"mov%.l %1,%-\;fmove%.s %+,%0\"; + return \"fmove%.s %1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"fmove%.s %1,%-\;mov%.l %+,%0\"; + return \"fmove%.s %1,%0\"; + } + return \"mov%.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=frm") + (match_operand:SF 1 "nonimmediate_operand" "frm"))] + "!TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.s %1,%0\"; + if (REG_P (operands[1])) + return \"mov%.l %1,%-\;fmove%.s %+,%0\"; + return \"fmove%.s %1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"fmove%.s %1,%-\;mov%.l %+,%0\"; + return \"fmove%.s %1,%0\"; + } + return \"mov%.l %1,%0\"; +}") + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f,m,!*r,!f*m") + (match_operand:DF 1 "nonimmediate_operand" "fm,f,f*r*m,*r"))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov%.l %1,%-\", xoperands); + output_asm_insn (\"mov%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %1,%-\;mov%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov%.l %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=frm") + (match_operand:DF 1 "nonimmediate_operand" "frm"))] + "!TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov%.l %1,%-\", xoperands); + output_asm_insn (\"mov%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %1,%-\;mov%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov%.l %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>") + (match_operand:DI 1 "general_operand" "r,m,roi<>"))] + "" + "* +{ + return output_move_double (operands); +} +") + +;; This goes after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. It goes before the add/sub insns +;; so we will prefer it to them. + +(define_insn "pushasi" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "address_operand" "p"))] + "" + "pea %a1") + +;; truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:SI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"mov%.l %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 3); + return \"mov%.b %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:HI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG + && (GET_CODE (operands[1]) == MEM + || GET_CODE (operands[1]) == CONST_INT)) + return \"mov%.w %1,%0\"; + if (GET_CODE (operands[0]) == REG) + return \"mov%.l %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 1); + return \"mov%.b %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=dm,d") + (truncate:HI + (match_operand:SI 1 "general_operand" "roJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"mov%.l %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 2); + return \"mov%.w %1,%0\"; +}") + +;; zero extension instructions + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:HI (match_dup 0) 0)) + (match_operand:HI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + " operands[1] = make_safe_from (operands[1], operands[0]); ") + +;; Patterns to recognize zero-extend insns produced by the combiner. + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "rmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFFFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.w %1,%0\;and%.l %#0xFFFF,%0\"; + return \"clr%.l %0\;mov%.w %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"mov%.w %1,%0\;clr%.w %0\"; + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.w %0\;mov%.w %1,%0\"; + else + { + output_asm_insn (\"clr%.w %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 2); + return \"mov%.w %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=do<>") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.w %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.b %1,%0\;and%.w %#0xFF,%0\"; + return \"clr%.w %0\;mov%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + if (REGNO (XEXP (XEXP (operands[0], 0), 0)) + == STACK_POINTER_REGNUM) + return \"clr%.w %-\;mov%.b %1,%0\"; + else + return \"mov%.b %1,%0\;clr%.b %0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.b %0\;mov%.b %1,%0\"; + else + { + output_asm_insn (\"clr%.b %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 1); + return \"mov%.b %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;mov%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + return \"clr%.l %0@-\;mov%.b %1,%0@(3)\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + return \"clr%.l %0@+\;mov%.b %1,%0@(-1)\"; + } + else + { + output_asm_insn (\"clr%.l %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 3); + return \"mov%.b %1,%0\"; + } +}") + +;; sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "0,rmn")))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"mov%.w %1,%0\"; + return \"ext%.l %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=d") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "0")))] + "" + "ext%.w %0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "0")))] + "TARGET_68020" + "extb%.l %0") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=f,m") + (float_extend:DF + (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "fmovesd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=f,m") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "fmoveds %1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovels %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmoveld %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovews %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovewd %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:QI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovebs %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:QI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovebd %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovesb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovesw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovesl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovedb %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovedw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovedl %1,%0") + +;; add instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,!a") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0,a,rJK") + (match_operand:SI 2 "general_operand" "dIKLs,mrIKLs,rJK,a")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (!ADDRESS_REG_P (operands[1])) + { + rtx tmp = operands[1]; + + operands[1] = operands[2]; + operands[2] = tmp; + } + + /* These insns can result from reloads to access + stack slots over 64k from the frame pointer. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000) + return \"mov%.l %2,%0\;add%.l %1,%0\"; + if (GET_CODE (operands[2]) == REG) + return \"lea %1@[%2:L:B],%0\"; + else + return \"lea %1@(%c2),%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return (ADDRESS_REG_P (operands[0]) + ? \"addq%.w %2,%0\" + : \"addq%.l %2,%0\"); + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return (ADDRESS_REG_P (operands[0]) + ? \"subq%.w %2,%0\" + : \"subq%.l %2,%0\"); + } + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"add%.w %2,%0\"; + } + return \"add%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "add%.w %2,%0") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return \"subq%.w %2,%0\"; + } + } + return \"add%.w %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "add%.w %1,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.b %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); + return \"subq%.b %2,%0\"; + } + } + return \"add%.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "add%.b %1,%0") + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%f") + (match_operand:DF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fadd%.d %2,%1,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%f") + (match_operand:SF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fadd%.s %2,%1,%0") + +;; subtract instructions + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,?d") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,a,mrIKs") + (match_operand:SI 2 "general_operand" "dIKs,mrIKs,J,0")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (operands_match_p (operands[0], operands[2])) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"subq%.l %1,%0\;neg%.l %0\"; + } + return \"sub%.l %1,%0\;neg%.l %0\"; + } + /* This case is matched by J, but negating -0x8000 + in an lea would give an invalid displacement. + So do this specially. */ + if (INTVAL (operands[2]) == -0x8000) + return \"mov%.l %1,%0\;sub%.l %2,%0\"; + return \"lea %1@(%n2),%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"subq%.l %2,%0\"; + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"sub%.w %2,%0\"; + } + return \"sub%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "sub%.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "sub%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (minus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "sub%.w %1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "sub%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (minus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "sub%.b %1,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "nonimmediate_operand" "f,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fsub%.d %2,%1,%0\"; + return \"frsub%.d %1,%2,%0\"; +}") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (minus:SF (match_operand:SF 1 "nonimmediate_operand" "f,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fsub%.s %2,%1,%0\"; + return \"frsub%.s %1,%2,%0\"; +}") + +;; multiply instructions + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "muls %2,%0") + +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "muls %2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "muls%.l %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "mulu %2,%0") + +(define_insn "umulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "mulu %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "mulu%.l %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%f") + (match_operand:DF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fmul%.d %2,%1,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%f") + (match_operand:SF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fmul%.s %2,%1,%0") + +;; divide instructions + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "extl %0\;divs %2,%0") + +(define_insn "divhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "divs %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divs%.l %2,%0,%0") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "and%.l %#0xFFFF,%0\;divu %2,%0") + +(define_insn "udivhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "divu %2,%0") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divu%.l %2,%0,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (div:DF (match_operand:DF 1 "nonimmediate_operand" "f,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fdiv%.d %2,%1,%0\"; + return \"frdiv%.d %1,%2,%0\"; +}") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (div:SF (match_operand:SF 1 "nonimmediate_operand" "f,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fdiv%.s %2,%1,%0\"; + return \"frdiv%.s %1,%2,%0\"; +}") + +;; Remainder instructions. + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"extl %0\;divs %2,%0\;swap %0\"; +}") + +(define_insn "modhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"divs %2,%0\;swap %0\"; +}") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"and%.l %#0xFFFF,%0\;divu %2,%0\;swap %0\"; +}") + +(define_insn "umodhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"divu %2,%0\;swap %0\"; +}") + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divs%.l %2,%0,%3") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divu%.l %2,%0,%3") + +;; logical-and instructions + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xffff) == 0xffffffff + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (operands[2] == const0_rtx) + return \"clr%.w %0\"; + return \"and%.w %2,%0\"; + } + return \"and%.l %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (and:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "and%.w %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "and%.b %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%.w %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%.b %1,%0") + +;; inclusive-or instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"or%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval); + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval % 8); + } + return \"bset %1,%0\"; + } + return \"or%.l %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "or%.w %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "or%.b %2,%0") + +;; xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=do,m") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "di,dKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))) + { + if (! DATA_REG_P (operands[0])) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"eor%.w %2,%0\"; + } + return \"eor%.l %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=dm") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dn")))] + "" + "eor%.w %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=dm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "dn")))] + "" + "eor%.b %2,%0") + +;; negation instructions + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "neg%.l %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "neg%.w %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg%.b %0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fneg%.s %1,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fneg%.d %1,%0") + +;; Absolute value instructions + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fabs%.s %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fabs%.d %1,%0") + +;; Square root instructions + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fsqrt%.s %1,%0") + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fsqrt%.d %1,%0") + +;; one complement instructions + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "not%.l %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "not%.w %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not%.b %0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (TARGET_68020) + return \"mov%.b %1,%0\;extb%.l %0\"; + return \"mov%.b %1,%0\;ext%.w %0\;ext%.l %0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;mov%.b %1,%0\"; +}") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && (INTVAL (operands[0]) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; + return \"cmp%.b %0,%1\"; +") + +(define_insn "" + [(set (cc0) (compare (lshiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & ~0xff) == 0)" + "* + return \"cmp%.b %1,%0\"; +") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && ((INTVAL (operands[0]) + 0x80) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; + return \"cmp%.b %0,%1\"; +") + +(define_insn "" + [(set (cc0) (compare (ashiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && ((INTVAL (operands[1]) + 0x80) & ~0xff) == 0)" + "* + return \"cmp%.b %1,%0\"; +") + +;; arithmetic shift instructions +;; We don't need the shift memory by 1 bit instruction + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asl%.l %2,%0") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asl%.w %2,%0") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asl%.b %2,%0") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asr%.l %2,%0") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asr%.w %2,%0") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asr%.b %2,%0") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsl%.l %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsl%.w %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsl%.b %2,%0") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsr%.l %2,%0") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsr%.w %2,%0") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsr%.b %2,%0") + +;; rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "rol%.l %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "rol%.w %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "rol%.b %2,%0") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "ror%.l %2,%0") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "ror%.w %2,%0") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "ror%.b %2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+do") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"bfins %3,[%c2,%c1]%0\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"mov%.b %3,%0\"; + return \"mov%.w %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfextu [%c3,%c2]%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + output_asm_insn (\"clrl %0\", operands); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"mov%.b %1,%0\"; + return \"mov%.w %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfexts [%c3,%c2]%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"mov%.b %1,%0\;extb%.l %0\"; + return \"mov%.w %1,%0\;ext%.l %0\"; +}") + +;; Bit field instructions, general cases. +;; "o,d" constraint causes a nonoffsettable memref to match the "o" +;; so that its address is reloaded. + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts [%c3,%c2]%1,%0") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfextu [%c3,%c2]%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) + (match_operand 3 "immediate_operand" "i,i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[3]) == -1 + || (GET_CODE (operands[1]) == CONST_INT + && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" + "* +{ + CC_STATUS_INIT; + return \"bfchg [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset [%c2,%c1]%0\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (match_operand:SI 3 "general_operand" "d,d"))] + "TARGET_68020 && TARGET_BITFIELD" + "bfins %3,[%c2,%c1]%0") + +;; Now recognize bit field insns that operate on registers +;; (or at least were intended to do so). + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts [%c3,%c2]%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfextu [%c3,%c2]%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + return \"bfins %3,[%c2,%c1]%0\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +;;; now handle the register cases +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "seq" + [(set (match_operand:QI 0 "general_operand" "=d") + (eq (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\"); +") + +(define_insn "sne" + [(set (match_operand:QI 0 "general_operand" "=d") + (ne (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sne %0\", \"fsneq %0\", \"sne %0\"); +") + +(define_insn "sgt" + [(set (match_operand:QI 0 "general_operand" "=d") + (gt (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", \"and%.b %#0xc,%!\;sgt %0\"); +") + +(define_insn "sgtu" + [(set (match_operand:QI 0 "general_operand" "=d") + (gtu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"shi %0\"; ") + +(define_insn "slt" + [(set (match_operand:QI 0 "general_operand" "=d") + (lt (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ") + +(define_insn "sltu" + [(set (match_operand:QI 0 "general_operand" "=d") + (ltu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scs %0\"; ") + +(define_insn "sge" + [(set (match_operand:QI 0 "general_operand" "=d") + (ge (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ") + +(define_insn "sgeu" + [(set (match_operand:QI 0 "general_operand" "=d") + (geu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scc %0\"; ") + +(define_insn "sle" + [(set (match_operand:QI 0 "general_operand" "=d") + (le (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sle %0\", \"fsle %0\", \"and%.b %#0xc,%!\;sle %0\"); +") + +(define_insn "sleu" + [(set (match_operand:QI 0 "general_operand" "=d") + (leu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"sls %0\"; ") + +;; Basic conditional jump instructions. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"jeq %l0\", \"fbeq %l0\", \"jeq %l0\"); +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"jne %l0\", \"fbneq %l0\", \"jne %l0\"); +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jgt %l0\", \"fbgt %l0\", \"and%.b %#0xc,%!\;jgt %l0\"); +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jhi %l0\"; +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jlt %l0\", \"fblt %l0\", \"jmi %l0\"); +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jcs %l0\"; +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jge %l0\", \"fbge %l0\", \"jpl %l0\"); +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jcc %l0\"; +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jle %l0\", \"fble %l0\", \"and%.b %#0xc,%!\;jle %l0\"); +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jls %l0\"; +") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + OUTPUT_JUMP (\"jne %l0\", \"fbneq %l0\", \"jne %l0\"); +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + OUTPUT_JUMP (\"jeq %l0\", \"fbeq %l0\", \"jeq %l0\"); +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jle %l0\", \"fbngt %l0\", \"and%.b %#0xc,%!\;jle %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jls %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jge %l0\", \"fbnlt %l0\", \"jpl %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jcc %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jlt %l0\", \"fbnge %l0\", \"jmi %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jcs %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jgt %l0\", \"fbnle %l0\", \"and%.b %#0xc,%!\;jgt %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jhi %l0\"; +") + +;; Subroutines of "casesi". + +(define_expand "casesi_1" + [(set (match_operand:SI 3 "general_operand" "") + (plus:SI (match_operand:SI 0 "general_operand" "") + ;; Note operand 1 has been negated! + (match_operand:SI 1 "immediate_operand" ""))) + (set (cc0) (compare (match_operand:SI 2 "general_operand" "") + (match_dup 3))) + (set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 4 "" "")) (pc)))] + "" + "") + +(define_expand "casesi_2" + [(set (match_operand:SI 0 "" "") (mem:HI (match_operand:SI 1 "" ""))) + ;; The USE here is so that at least one jump-insn will refer to the label, + ;; to keep it alive in jump_optimize. + (parallel [(set (pc) + (plus:SI (pc) (match_dup 0))) + (use (label_ref (match_operand 2 "" "")))])] + "" + "") + +;; Operand 0 is index (in bytes); operand 1 is minimum, operand 2 the maximum; +;; operand 3 is CODE_LABEL for the table; +;; operand 4 is the CODE_LABEL to go to if index out of range. +(define_expand "casesi" + ;; We don't use these for generating the RTL, but we must describe + ;; the operands here. + [(match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "general_operand" "") + (match_operand 3 "" "") + (match_operand 4 "" "")] + "" + " +{ + rtx table_elt_addr; + rtx index_diff; + + operands[1] = negate_rtx (SImode, operands[1]); + index_diff = gen_reg_rtx (SImode); + /* Emit the first few insns. */ + emit_insn (gen_casesi_1 (operands[0], operands[1], operands[2], + index_diff, operands[4])); + /* Construct a memory address. This may emit some insns. */ + table_elt_addr + = memory_address_noforce + (HImode, + gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, index_diff, + gen_rtx (CONST_INT, VOIDmode, 2)), + gen_rtx (LABEL_REF, VOIDmode, operands[3]))); + /* Emit the last few insns. */ + emit_insn (gen_casesi_2 (gen_reg_rtx (HImode), table_elt_addr, operands[3])); + DONE; +}") + +;; Recognize one of the insns resulting from casesi_2. +(define_insn "" + [(set (pc) + (plus:SI (pc) (match_operand:HI 0 "general_operand" "r"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* + return \"jmp pc@(2:B)[%0:W:B]\"; +") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* + return \"jra %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:HI (match_operand:HI 0 "general_operand" "g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + { + return \"subq%.w %#1,%0\;jcc %l1\"; + } + return \"subq%.w %#1,%0\;cmp%.w %#-1,%0\;jne %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:SI (match_operand:SI 0 "general_operand" "g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;subq%.l %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.l %#1,%0\;jcc %l1\"; + return \"subq%.l %#1,%0\;cmp%.l %#-1,%0\;jne %l1\"; +}") + +;; dbra patterns that use REG_NOTES info generated by strength_reduce. + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.l %#1,%0\;jcc %l1\"; + return \"subq%.l %#1,%0\;cmp%.l %#-1,%0\;jne %l1\"; +}") + +;; Call subroutine with no return value. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "o") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + rtx xoperands[2]; + int size = XINT(operands[1],0); + + if (size == 0) + output_asm_insn (\"sub%.l a0,a0\;jbsr %0\", operands); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, size/4); + output_asm_insn (\"mov%.l sp,a0\;pea %a1\", xoperands); + output_asm_insn (\"jbsr %0\", operands); + size = size + 4; + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, size); + if (size <= 8) + output_asm_insn (\"addq%.l %1,sp\", xoperands); + else if (size < 0x8000) + output_asm_insn (\"add%.w %1,sp\", xoperands); + else + output_asm_insn (\"add%.l %1,sp\", xoperands); + } + return \"mov%.l a6@(-4),a0\"; +}") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "general_operand" "o") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + rtx xoperands[3]; + int size = XINT(operands[2],0); + + if (size == 0) + output_asm_insn(\"sub%.l a0,a0\;jbsr %1\", operands); + else + { + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, size/4); + output_asm_insn (\"mov%.l sp,a0\;pea %a2\", xoperands); + output_asm_insn (\"jbsr %1\", operands); + size = size + 4; + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, size); + if (size <= 8) + output_asm_insn (\"addq%.l %2,sp\", xoperands); + else if (size < 0x8000) + output_asm_insn (\"add%.w %2,sp\", xoperands); + else + output_asm_insn (\"add%.l %2,sp\", xoperands); + } + return \"mov%.l a6@(-4),a0\"; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This should not be used unless the add/sub insns can't be. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (match_operand:QI 1 "address_operand" "p"))] + "" + "lea %a1,%0") + +;; This is the first machine-dependent peephole optimization. +;; It is useful when a floating value is returned from a function call +;; and then is moved into an FP register. +;; But it is mainly intended to test the support for these optimizations. + +;Not applicable to Alliant -- floating results are returned in fp0 +;(define_peephole +; [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) +; (set (match_operand:DF 0 "register_operand" "f") +; (match_operand:DF 1 "register_operand" "ad"))] +; "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" +; "* +;{ +; rtx xoperands[2]; +; xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); +; output_asm_insn (\"mov%.l %1,%@\", xoperands); +; output_asm_insn (\"mov%.l %1,%-\", operands); +; return \"fmove%.d %+,%0\"; +;} +;") + + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- comment-start-skip: ";+- *" +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/convex.md b/gcc-1.40/config/convex.md new file mode 100644 index 0000000..97d874d --- /dev/null +++ b/gcc-1.40/config/convex.md @@ -0,0 +1,1266 @@ +;;- Machine description for GNU compiler +;;- Convex Version +;; Copyright (C) 1989 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "* return set_cmp (operands[0], const0_rtx, 'w');") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "register_operand" "r"))] + "" + "* return set_cmp (operands[0], const0_rtx, 'h');") + +(define_expand "tstqi" + [(set (match_dup 1) + (sign_extend:SI (match_operand:QI 0 "register_operand" "r"))) + (set (cc0) + (match_dup 1))] + "" + "operands[1] = gen_reg_rtx (SImode);") + +(define_insn "tstdi" + [(set (cc0) + (match_operand:DI 0 "register_operand" "d")) + (clobber (reg:DI 1))] + "" + "* +{ + output_asm_insn (\"ld.l #0,s1\"); + return set_cmp (operands[0], gen_rtx (REG, DImode, 1), 'l'); +}") + +(define_expand "tstdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "d") + (match_dup 1)))] + "" + "operands[1] = force_reg (DFmode, dconst0_rtx);") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "d"))] + "" + "* return set_cmp (operands[0], fconst0_rtx, 's');") + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonmemory_operand" "d,a,i,r") + (match_operand:SI 1 "nonmemory_operand" "d,a,r,i")))] + "" + "* return set_cmp (operands[0], operands[1], 'w');") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonmemory_operand" "d,a,r,i") + (match_operand:HI 1 "nonmemory_operand" "d,a,i,r")))] + "" + "* return set_cmp (operands[0], operands[1], 'h');") + +(define_insn "" + [(set (cc0) + (compare (sign_extend:SI (match_operand:QI 0 "register_operand" "d")) + (sign_extend:SI (match_operand:QI 1 "register_operand" "d"))))] + "" + "* return set_cmp (operands[0], operands[1], 'b');") + +(define_insn "cmpdi" + [(set (cc0) + (compare (match_operand:DI 0 "register_operand" "d") + (match_operand:DI 1 "register_operand" "d")))] + "" + "* return set_cmp (operands[0], operands[1], 'l');") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "d") + (match_operand:DF 1 "register_operand" "d")))] + "" + "* return set_cmp (operands[0], operands[1], 'd');") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "dF,d") + (match_operand:SF 1 "nonmemory_operand" "d,F")))] + "" + "* return set_cmp (operands[0], operands[1], 's');") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=g,d") + (match_operand:DF 1 "general_operand" "d,gG"))] + "" + "* +{ + if (push_operand (operands[0], DFmode)) + return \"psh.l %1\"; + else if (GET_CODE (operands[0]) == MEM) + return \"st.l %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + return \"mov %1,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE && LD_D_P (operands[1])) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + const_double_high_int (operands[1])); + return \"ld.d %1,%0\"; + } + else + return \"ld.l %1,%0\"; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g,d") + (match_operand:SF 1 "general_operand" "d,gF"))] + "" + "* +{ + if (push_operand (operands[0], SFmode)) + return \"psh.w %1\"; + else if (GET_CODE (operands[0]) == MEM) + return \"st.s %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + return \"mov.s %1,%0\"; + else + return \"ld.s %1,%0\"; +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g,d") + (match_operand:DI 1 "general_operand" "d,gG"))] + "" + "* +{ + if (push_operand (operands[0], DImode)) + return \"psh.l %1\"; + else if (GET_CODE (operands[0]) == MEM) + return \"st.l %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + return \"mov %1,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE && LD_D_P (operands[1])) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + const_double_high_int (operands[1])); + return \"ld.d %1,%0\"; + } + else + return \"ld.l %1,%0\"; +}") + +;; Special case of movsi, needed to express A-reg preference. + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (plus:SI (match_operand:SI 1 "register_operand" "a") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] != stack_pointer_rtx" + "pshea %a2(%1)") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g,r,<") + (match_operand:SI 1 "general_operand" "r,g,io"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + { + if (GET_CODE (operands[1]) == REG) + return \"psh.w %1\"; + else + return \"pshea %a1\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st.w %1,%0\"; + if (GET_CODE (operands[1]) != REG) + return \"ld.w %1,%0\"; + if (S_REG_P (operands[0]) && S_REG_P (operands[1])) + return \"mov.w %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "r,g"))] + "" + "* +{ + if (push_operand (operands[0], HImode)) + abort (); + else if (GET_CODE (operands[0]) == MEM) + return \"st.h %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + { + if (S_REG_P (operands[0]) && S_REG_P (operands[1])) + return \"mov.w %1,%0\"; + else + return \"mov %1,%0\"; + } + else if (GET_CODE (operands[1]) == CONST_INT) + return \"ld.w %1,%0\"; + else + return \"ld.h %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g,r") + (match_operand:QI 1 "general_operand" "r,g"))] + "" + "* +{ + if (push_operand (operands[0], QImode)) + abort (); + else if (GET_CODE (operands[0]) == MEM) + return \"st.b %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + { + if (S_REG_P (operands[0]) && S_REG_P (operands[1])) + return \"mov.w %1,%0\"; + else + return \"mov %1,%0\"; + } + else if (GET_CODE (operands[1]) == CONST_INT) + return \"ld.w %1,%0\"; + else + return \"ld.b %1,%0\"; +}") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (truncate:QI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "cvtw.b %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (truncate:HI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "cvtw.h %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:HI 1 "register_operand" "0")))] + "" + "") + +(define_insn "truncdisi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (match_operand:DI 1 "register_operand" "d")))] + "" + "cvtl.w %1,%0") + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (match_operand:SI 1 "register_operand" "d")))] + "" + "cvtw.l %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (sign_extend:SI (match_operand:HI 1 "register_operand" "d,a")))] + "" + "cvth.w %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (sign_extend:HI (match_operand:QI 1 "register_operand" "d,a")))] + "" + "cvtb.w %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (sign_extend:SI (match_operand:QI 1 "register_operand" "d,a")))] + "" + "cvtb.w %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (float_extend:DF (match_operand:SF 1 "register_operand" "d")))] + "" + "cvts.d %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (float_truncate:SF (match_operand:DF 1 "register_operand" "d")))] + "" + "cvtd.s %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))] + "" + "and #0xffff,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "register_operand" "0")))] + "" + "and #0xff,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "register_operand" "0")))] + "" + "and #0xff,%0") + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (zero_extend:DI (match_operand:SI 1 "register_operand" "0")))] + "" + "ld.u #0,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (float:SF (match_operand:SI 1 "register_operand" "d")))] + "" + "cvtw.s %1,%0") + +(define_insn "floatdisf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (float:SF (match_operand:DI 1 "register_operand" "d")))] + "" + "cvtl.s %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (float:DF (match_operand:SI 1 "register_operand" "d")))] + "TARGET_C2" + "cvtw.d %1,%0") + +(define_insn "floatdidf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (float:DF (match_operand:DI 1 "register_operand" "d")))] + "" + "cvtl.d %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "d"))))] + "" + "cvts.w %1,%0") + +(define_insn "fix_truncsfdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "d"))))] + "" + "cvts.l %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "d"))))] + "" + "* +{ + if (TARGET_C2) + return \"cvtd.w %1,%0\"; + return \"cvtd.l %1,%0\"; +}") + +(define_insn "fix_truncdfdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "d"))))] + "" + "cvtd.l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "add.d %2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "add.s %2,%0") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (plus:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "add.l %2,%0") + +;; special case of addsi3, needed to specify an A reg for the destination +;; when the source is a sum involving FP or AP. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=a") + (plus:SI (match_operand:SI 1 "register_operand" "%a") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] == frame_pointer_rtx || operands[1] == arg_pointer_rtx" + "ldea %a2(%1),%0") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a,a") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%0,0,a") + (match_operand:SI 2 "nonmemory_operand" "di,ri,i")))] + "" + "* switch (which_alternative) +{ + case 0: + case 1: + return \"add.w %2,%0\"; + case 2: + if ((TARGET_C2 || A_REG_P (operands[0])) + && operands[1] != stack_pointer_rtx) + return \"ldea %a2(%1),%0\"; + else + return \"mov %1,%0\;add.w %2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (plus:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "add.h %2,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (plus:QI (match_operand:QI 1 "register_operand" "%0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "add.b %2,%0") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "sub.d %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "sub.s %2,%0") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "sub.l %2,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (minus:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "sub.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (minus:HI (match_operand:HI 1 "register_operand" "0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "sub.h %2,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (minus:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "sub.b %2,%0") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "mul.d %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "mul.s %2,%0") + +(define_insn "muldi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (mult:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "mul.l %2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (mult:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "mul.w %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (mult:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "mul.h %2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (mult:QI (match_operand:QI 1 "register_operand" "%0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "mul.b %2,%0") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "div.d %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "div.s %2,%0") + +(define_insn "divdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (div:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "div.l %2,%0") + +(define_insn "udivdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (udiv:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d")))] + "" + "psh.l %2\;psh.l %1\;callq udiv64\;pop.l %0\;add.w #8,sp") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (div:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "div.w %2,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (div:HI (match_operand:HI 1 "register_operand" "0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "div.h %2,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (div:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "div.b %2,%0") + +;; - and, or, xor + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (and:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "and %2,%0") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (and:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "and %2,%0") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (and:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "and %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (and:QI (match_operand:QI 1 "register_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "di,ai")))] + "" + "and %2,%0") + +;;- Bit set instructions. + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (ior:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "or %2,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "or %2,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (ior:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "or %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (ior:QI (match_operand:QI 1 "register_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "di,ai")))] + "" + "or %2,%0") + +;;- xor instructions. + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (xor:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "xor %2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "xor %2,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (xor:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "xor %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (xor:QI (match_operand:QI 1 "register_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "di,ai")))] + "" + "xor %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (neg:DF (match_operand:DF 1 "register_operand" "d")))] + "" + "neg.d %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (neg:SF (match_operand:SF 1 "register_operand" "d")))] + "" + "neg.s %1,%0") + +(define_insn "negdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (neg:DI (match_operand:DI 1 "register_operand" "d")))] + "" + "neg.l %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (neg:SI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "neg.w %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (neg:HI (match_operand:HI 1 "register_operand" "d,a")))] + "" + "neg.h %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "register_operand" "=d") + (neg:QI (match_operand:QI 1 "register_operand" "d")))] + "" + "neg.b %1,%0") + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (not:DI (match_operand:DI 1 "register_operand" "d")))] + "" + "not %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (not:SI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "not %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (not:HI (match_operand:HI 1 "register_operand" "d,a")))] + "" + "not %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (not:QI (match_operand:QI 1 "register_operand" "d,a")))] + "" + "not %1,%0") + +;;- shifts +;; +;; Convex shift instructions are unsigned. +;; To make signed right shifts: +;; for SImode, sign extend to DImode and shift, works for 0..32 +;; for DImode, shift and then extend the sign, works for 0..63 +;; +;; It is very sad that DImode right shift 64 fails, but I don't see +;; any reasonable way to handle it. ANSI only requires up to 63. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "INTVAL (operands[2]) >= 0" + "* +{ + if (operands[2] == const1_rtx) + return \"add.w %0,%0\"; + else if (TARGET_C2 && S_REG_P (operands[0])) + return \"shf.w %2,%0\"; + else + return \"shf %2,%0\"; +}") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "* +{ + if (operands[2] == const1_rtx) + return \"add.w %0,%0\"; + else if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0) + return TARGET_C2 ? \"shf.w %2,%0\" : \"shf %2,%0\"; + else + return \"cvtw.l %0,%0\;shf %2,%0\"; +}") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "operands[2] = negate_rtx (SImode, operands[2]);") + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (lshift:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "* +{ + if (operands[2] == const1_rtx) + return \"add.w %0,%0\"; + if (S_REG_P (operands[0])) + { + if (TARGET_C2) + return \"shf.w %2,%0\"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 0) + return \"shf %2,%0\"; + else + return \"ld.u #0,%0\;shf %2,%0\"; + } + return \"shf %2,%0\"; +}") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "operands[2] = negate_rtx (SImode, operands[2]);") + +;; signed a >> b is +;; ((a >> b) ^ signbit) - signbit +;; where signbit is (1 << 63) >> b + +(define_expand "ashldi3" + [(match_operand:DI 0 "register_operand" "=d") + (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di") + (match_dup 3)] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0) + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (LSHIFT, DImode, operands[1], operands[2]))); + else if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + { + int rshift = - INTVAL (operands[2]); + operands[3] = force_reg + (DImode, + immed_double_const (1 << (63 - rshift), 1 << (31 - rshift), DImode)); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (LSHIFT, DImode, operands[1], operands[2]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (XOR, DImode, operands[0], operands[3]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (MINUS, DImode, operands[0], operands[3]))); + } + else + { + operands[3] = + force_reg (DImode, immed_double_const (0, 1 << 31, DImode)); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (LSHIFT, DImode, operands[1], operands[2]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[3], + gen_rtx (LSHIFT, DImode, operands[3], operands[2]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (XOR, DImode, operands[0], operands[3]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (MINUS, DImode, operands[0], operands[3]))); + } + DONE; +}") + +(define_expand "ashrdi3" + [(match_operand:DI 0 "register_operand" "=d") + (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")] + "" + " +{ + emit_insn (gen_ashldi3 (operands[0], operands[1], + negate_rtx (SImode, operands[2]))); + DONE; +}") + +(define_insn "lshldi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (lshift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "shf %2,%0") + +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (lshift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "operands[2] = negate_rtx (SImode, operands[2]);") + +;; __builtin instructions + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (sqrt:DF (match_operand:DF 1 "register_operand" "0")))] + "TARGET_C2" + "sqrt.d %0") + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "TARGET_C2" + "sqrt.s %0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (minus:SI (ffs:SI (match_operand:SI 1 "register_operand" "d")) + (const_int 1)))] + "" + "tzc %1,%0\;le.w #32,%0\;jbrs.f .+6\;ld.w #-1,%0") + +(define_expand "ffssi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (minus:SI (ffs:SI (match_operand:SI 1 "register_operand" "d")) + (const_int 1))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "" + "") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (abs:SF (match_operand:SF 1 "register_operand" "0")))] + "" + "and #0x7fffffff,%0") + +(define_expand "absdf2" + [(set (subreg:DI (match_operand:DF 0 "register_operand" "=d") 0) + (and:DI (subreg:DI (match_operand:DF 1 "register_operand" "d") 0) + (match_dup 2)))] + "" + "operands[2] = force_reg (DImode, + immed_double_const (-1, 0x7fffffff, DImode));") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"eq\", 't'); ") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"eq\", 'f'); ") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"le\", 'f'); ") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"leu\", 'f'); ") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"lt\", 't'); ") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"ltu\", 't'); ") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"lt\", 'f'); ") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"ltu\", 'f'); ") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"le\", 't'); ") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"leu\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"eq\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"eq\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"le\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"leu\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"lt\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"ltu\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"lt\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"ltu\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"le\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"leu\", 'f'); ") + +;; - Calls +;; +;; arg count word may be omitted to save a push and let gcc try to +;; combine the arg list pop. RETURN_POPS_ARGS from tm.h decides this. + +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + if (! RETURN_POPS_ARGS (ignoreme)) + { + if (operands[1] == const0_rtx) + return \"calls %0\"; + if (! reg_mentioned_p (arg_pointer_rtx, operands[0])) + return \"mov sp,ap\;calls %0\;ld.w 12(fp),ap\"; + operands[0] = XEXP (operands[0], 0); + return \"ld.w %0,a1\;mov sp,ap\;calls (a1)\;ld.w 12(fp),ap\"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 3)/ 4); + if (! reg_mentioned_p (arg_pointer_rtx, operands[0])) + return \"mov sp,ap\;pshea %a1\;calls %0\;ld.w 12(fp),ap\;add.w #4*%a1+4,sp\"; + operands[0] = XEXP (operands[0], 0); + return \"ld.w %0,a1\;mov sp,ap\;pshea %a1\;calls (a1)\;ld.w 12(fp),ap\;add.w #4*%a1+4,sp\"; +}") + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (! RETURN_POPS_ARGS (ignoreme)) + { + if (operands[2] == const0_rtx) + return \"calls %1\"; + if (! reg_mentioned_p (arg_pointer_rtx, operands[1])) + return \"mov sp,ap\;calls %1\;ld.w 12(fp),ap\"; + operands[1] = XEXP (operands[1], 0); + return \"ld.w %1,a1\;mov sp,ap\;calls (a1)\;ld.w 12(fp),ap\"; + } + operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 3) / 4); + if (! reg_mentioned_p (arg_pointer_rtx, operands[1])) + return \"mov sp,ap\;pshea %a2\;calls %1\;ld.w 12(fp),ap\;add.w #4*%a2+4,sp\"; + operands[1] = XEXP (operands[1], 0); + return \"ld.w %1,a1\;mov sp,ap\;pshea %a2\;calls (a1)\;ld.w 12(fp),ap\;add.w #4*%a2+4,sp\"; +}") + +(define_insn "return" + [(return)] + "" + "rtn") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "address_operand" "p")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %a0") + +;; - fix up the code generated for bit field tests + +;; cc0 = (x >> k1) & k2 --> cc0 = x & (k2 << k1) +;; cc0 = (x << k1) & k2 --> cc0 = x & (k2 >> k1) +;; provided k2 and (k2 << k1) don't include the sign bit + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "r") + (lshift:SI (match_dup 0) + (match_operand 1 "immediate_operand" "i"))) + (set (match_dup 0) + (and:SI (match_dup 0) + (match_operand 2 "immediate_operand" "i"))) + (set (cc0) (match_dup 0))] + "dead_or_set_p (insn, operands[0]) + && GET_CODE (operands[1]) == CONST_INT + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 0 + && (INTVAL (operands[2]) << INTVAL (operands[1])) >= 0" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) >> INTVAL (operands[1])); + output_asm_insn (\"and %2,%0\", operands); + return set_cmp (operands[0], const0_rtx, 'w'); +}") + +;; same as above where x is (y & 0xff...) caused by a zero extend + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "r") + (zero_extend:SI (match_operand 1 "register_operand" "0"))) + (set (match_dup 0) + (lshift:SI (match_dup 0) + (match_operand 2 "immediate_operand" "i"))) + (set (match_dup 0) + (and:SI (match_dup 0) + (match_operand 3 "immediate_operand" "i"))) + (set (cc0) (match_dup 0))] + "dead_or_set_p (insn, operands[0]) + && REGNO (operands[0]) == REGNO (operands[1]) + && GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[3]) << INTVAL (operands[2])) >= 0" + "* +{ + operands[3] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[3]) >> INTVAL (operands[2])) & + ~((-1) << GET_MODE_BITSIZE (GET_MODE (operands[1])))); + output_asm_insn (\"and %3,%0\", operands); + return set_cmp (operands[0], const0_rtx, 'w'); +}") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/i386.md b/gcc-1.40/config/i386.md new file mode 100644 index 0000000..df467e3 --- /dev/null +++ b/gcc-1.40/config/i386.md @@ -0,0 +1,2021 @@ +;; GCC machine description for Intel 80386. +;; Copyright (C) 1988 Free Software Foundation, Inc. +;; Mostly by William Schelter. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- instruction definitions + +;;- @@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. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' for eax +;;- 'd' for edx +;;- 'c' for ecx +;;- 'b' for ebx +;;- 'f' for anything in FLOAT_REGS +;;- 'r' any (non-floating-point) register +;;- 'q' regs that allow byte operations (A, B, C and D) +;;- 'A' A and D registers + +;; the special asm out single letter directives following a '%' are: +;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of operands[1] +;; 's' output a '*' +;; 'w' If the operand is a REG, it uses the mode size to determine the +;; printing of the reg + + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +{ + operands[1] = const0_rtx; + if (REG_P (operands[0])) + return AS2 (test%L0,%0,%0); + return AS2 (cmp%L0,%1,%0); +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "rm"))] + "" + "* +{ + operands[1] = const0_rtx; + if (REG_P (operands[0])) + return AS2 (test%W0,%0,%0); + return AS2 (cmp%W0,%1,%0); +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "qm"))] + "" + "* +{ + operands[1] = const0_rtx; + if (REG_P (operands[0])) + return AS2 (test%B0,%0,%0); + return AS2 (cmp%B0,%1,%0); +}") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "rm,f")) + (clobber (reg:SI 0))] + "TARGET_80387" + "* +{ + rtx xops[1]; + if (!FP_REG_P (operands[0])) + fp_push_sf (operands[0]); +/* fp_pop_level--; */ + xops[0] = FP_TOP; + cc_status.flags |= CC_IN_80387; + if (FP_REG_P (operands[0]) && ! top_dead_p (insn)) + output_asm_insn (\"ftst\;fnstsw %R0ax\;sahf\", xops); + else + output_asm_insn (\"ftst\;fstp %0(0)\;fnstsw %R0ax\;sahf\", xops); + RETCOM (testsf); +}") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "rm,f")) + (clobber (reg:SI 0)) + ] + "TARGET_80387" + "* +{ + rtx xops[1]; + if (!FP_REG_P (operands[0])) + fp_push_df (operands[0]); +/* fp_pop_level--; */ + xops[0] = FP_TOP; + cc_status.flags |= CC_IN_80387; + if (FP_REG_P (operands[0]) && ! top_dead_p (insn)) + output_asm_insn (\"ftst\;fnstsw %R0ax\;sahf\", xops); + else + output_asm_insn (\"ftst\;fstp %0(0)\;fnstsw %R0ax\;sahf\", xops); + RETCOM (testdf); +}") + +;;- compare instructions + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "mr,ri") + (match_operand:SI 1 "general_operand" "ri,mr")))] + "" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return AS2 (cmp%L0,%0,%1); + } + return AS2 (cmp%L0,%1,%0); +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "mr,ri") + (match_operand:HI 1 "general_operand" "ri,mr")))] + "" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return AS2 (cmp%W0,%0,%1); + } + return AS2 (cmp%W0,%1,%0); +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "qn,mq") + (match_operand:QI 1 "general_operand" "qm,nq")))] + "" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return AS2 (cmp%B0,%0,%1); + } + return AS2 (cmp%B0,%1,%0); +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "m,f*r,m,f,r,!*r") + (match_operand:DF 1 "general_operand" "m,m,f*r,r,f,*r"))) + (clobber (reg:SI 0))] + "TARGET_80387" + "* +{ + if (FP_REG_P (operands[0])) + { + rtx tem = operands[1]; + operands[1] = operands[0]; + operands[0] = tem; + cc_status.flags |= CC_REVERSED; + } + if (! FP_REG_P (operands[1])) + output_movdf (FP_TOP, operands[1]); + output_movdf (FP_TOP, operands[0]); +/* fp_pop_level--; + fp_pop_level--; */ + cc_status.flags |= CC_IN_80387; + return \"fcompp\;fnstsw %R0ax\;sahf\"; +}") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "m,f*r,m,f,r,!*r") + (match_operand:SF 1 "general_operand" "m,m,f*r,r,f,*r"))) + (clobber (reg:SI 0))] + "TARGET_80387" + "* +{ + if (FP_REG_P (operands[0])) + { + rtx tem = operands[1]; + operands[1] = operands[0]; + operands[0] = tem; + cc_status.flags |= CC_REVERSED; + } + if (! FP_REG_P (operands[1])) + output_movsf (FP_TOP, operands[1]); + output_movsf (FP_TOP, operands[0]); +/* fp_pop_level--; + fp_pop_level--; */ + cc_status.flags |= CC_IN_80387; + return \"fcompp\;fnstsw %R0ax\;sahf\"; +}") + +;; logical compare +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "rm,ri") + (match_operand:SI 1 "general_operand" "ri,rm")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%L0,%1,%0); + return AS2 (test%L0,%0,%1); +}") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "rm,ri") + (match_operand:HI 1 "general_operand" "ri,rm")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%W0,%1,%0); + return AS2 (test%W0,%0,%1); +}") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "qm,qi") + (match_operand:QI 1 "general_operand" "qi,qm")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%B0,%1,%0); + return AS2 (test%B0,%0,%1); +}") + +;; move instructions. +;; There is one for each machine mode, +;; and each is preceded by a corresponding push-insn pattern +;; (since pushes are not general_operands on the 386). + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "general_operand" "g"))] + "" + "push%L0 %1") + +;; General case of fullword move. +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g,r") + (match_operand:SI 1 "general_operand" "ri,m"))] + "" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return \"xor%L0 %0,%0\"; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"inc%L0 %0\"; + return \"mov%L0 %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "push_operand" "=<") + (match_operand:HI 1 "general_operand" "g"))] + "" + "push%W0 %1") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "ri,m"))] + "" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return \"xor%W0 %0,%0\"; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"inc%W0 %0\"; + return \"mov%W0 %1,%0\"; +}") + +;; emit_push_insn when it calls move_by_pieces +;; requires an insn to "push a byte". +;; But actually we use pushw, which has the effect of rounding +;; the amount pushed up to a halfword. +(define_insn "" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "general_operand" "q"))] + "" + "* +{ + operands[1] = gen_rtx (REG, HImode, REGNO (operands[1])); + return \"push%W0 %1\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=q,*r,m") + (match_operand:QI 1 "general_operand" "*g,q,qi"))] + "" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return \"xor%B0 %0,%0\"; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"inc%B0 %0\"; + /* If mov%B0 isn't allowed for one of these regs, use mov%W0. */ + if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) + return (AS2 (mov%W0,%w1,%w0)); + return (AS2 (mov%B0,%1,%0)); +}") + +; I suspect nothing can ever match this ??? +;(define_insn "" +; [(set (match_operand:SF 0 "general_operand" "rm") +; (match_operand:SF 1 "general_operand" "f")) +; (clobber (reg:SF 8))] +; "" +; "* +;{ +; output_asm_insn ("???", operands); +; fpop_sf (operands[0]); +; RETCOM (movsf_clobber); +;}") + +(define_insn "" + [(set (match_operand:SF 0 "push_operand" "=<,<") + (match_operand:SF 1 "general_operand" "gF,f"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + { + rtx xops[3]; + xops[0] = AT_SP (SFmode); + xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + xops[2] = stack_pointer_rtx; +/* fp_pop_level--; */ + output_asm_insn (AS2 (sub%L0,%1,%2), xops); + if (top_dead_p (insn)) + output_asm_insn (\"fstp%S0 %0\", xops); + else + output_asm_insn (\"fst%S0 %0\", xops); + RET; + } + return \"push%L0 %1\"; +}") + +(define_insn "movsf" + ;; `rf' is duplicated in the second alternative + ;; to make sure an optional reload is generated + ;; for the memref in operand 0. Otherwise + ;; we could use too many hard regs. + [(set (match_operand:SF 0 "general_operand" "=rf,mrf,!rm") + (match_operand:SF 1 "general_operand" "mrf,rf,F"))] + "" + "* +{ + if (FP_REG_P (operands[1]) + && !FP_REG_P (operands[0]) + && !top_dead_p (insn)) + fp_store_sf (operands[0]); + else + output_movsf (operands[0], operands[1]); + RETCOM (movsf); +}") + +;;should change to handle the memory operands[1] without doing df push.. +(define_insn "" + [(set (match_operand:DF 0 "push_operand" "=<,<") + (match_operand:DF 1 "general_operand" "gF,f"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + { + rtx xops[3]; + xops[0] = AT_SP (DFmode); + xops[1] = gen_rtx (CONST_INT, VOIDmode, 8); + xops[2] = stack_pointer_rtx; +/* fp_pop_level--; */ + output_asm_insn (AS2 (sub%L0,%1,%2), xops); + if (top_dead_p(insn)) + output_asm_insn (\"fstp%Q0 %0\", xops); + else + output_asm_insn (\"fst%Q0 %0\", xops); + RETCOM (pushdf); + } + else + return output_move_double (operands); +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=rmf,&fr,!rm") + ;; `rf' is duplicated in the second alternative + ;; to make sure that optional reloads are generated + ;; for the memory reference in operand 1. + (match_operand:DF 1 "general_operand" "fr,mrf,F"))] + "" + "* +{ + if (FP_REG_P (operands[1]) + && ! FP_REG_P (operands[0]) + && ! top_dead_p (insn)) + fp_store_df (operands[0]); + else + output_movdf (operands[0], operands[1]); + RETCOM (movdf); +}") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_operand" "roiF"))] + "" + "* +{ + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=&r,rm") + (match_operand:DI 1 "general_operand" "m,riF"))] + "" + "* +{ + return output_move_double (operands); +}") + +;; These go after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. But these go before the add and subtract insns +;; because it is often shorter to use these when both apply. + +;Lennart Augustsson <augustss@cs.chalmers.se> +;says this pattern just makes slower code: +; pushl %ebp +; addl $-80,(%esp) +;instead of +; leal -80(%ebp),%eax +; pushl %eax +; +;(define_insn "" +; [(set (match_operand:SI 0 "push_operand" "=<") +; (plus:SI (match_operand:SI 1 "general_operand" "%r") +; (match_operand:SI 2 "general_operand" "ri")))] +; "" +; "* +;{ +; rtx xops[4]; +; xops[0] = operands[0]; +; xops[1] = operands[1]; +; xops[2] = operands[2]; +; xops[3] = gen_rtx (MEM, SImode, stack_pointer_rtx); +; output_asm_insn (\"push%z1 %1\", xops); +; output_asm_insn (AS2 (add%z3,%2,%3), xops); +; RET; +;}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1)))] + "" + "inc%L0 %0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (const_int -1)))] + "" + "dec%L0 %0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1)))] + "" + "dec%L0 %0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + CC_STATUS_INIT; + /* Adding a constant to a register is faster with an add. */ + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && rtx_equal_p (operands[0], XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 1); + return AS2 (add%L0,%1,%0); + } + return \"lea%L0 %a1,%0\"; +}") + +;;- conversion instructions +;;- NONE + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=q,m") + (truncate:QI + (match_operand:SI 1 "general_operand" "qim,qn")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) + return \"mov%L0 %1,%k0\"; + return \"mov%B0 %b1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=q,m") + (truncate:QI + (match_operand:HI 1 "general_operand" "qim,qn")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) + return \"mov%W0 %1,%w0\"; + return \"mov%B0 %b1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=r,m") + (truncate:HI + (match_operand:SI 1 "general_operand" "rim,rn")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) + return \"mov%L0 %1,%k0\"; + return \"mov%W0 %w1,%0\"; +}") + +;;- zero extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "rm")))] + "" + "movz%W0%L0 %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movz%B0%W0 %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movz%B0%L0 %1,%0") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +/* +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "general_operand" "=a") + (sign_extend:DI + (match_operand:SI 1 "general_operand" "a")))] + "" + "clq") +*/ + +;; Note that the i386 programmers' manual says that the opcodes +;; are named movsx..., but the assembler on Unix does not accept that. +;; We use what the Unix assembler expects. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "rm")))] + "" + "movs%W0%L0 %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movs%B0%W0 %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movs%B0%L0 %1,%0" + ) + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=fm,f,fm,fm") + (float_extend:DF + (match_operand:SF 1 "general_operand" "m,0,f,!*r")))] + "TARGET_80387" + "* +{ + if (FP_REG_P (operands[0])) + { + output_movsf (operands[0], operands[1]); + RET; + } + if (FP_REG_P (operands[1])) + { + if (top_dead_p (insn)) + fp_pop_df (operands[0]); + else + fp_store_df (operands[0]); + RET; + } + output_movsf (FP_TOP, operands[1]); + fp_pop_df (operands[0]); + RETCOM (extendsfdf2); +}") + +;; This cannot output into an f-reg because there is no way to be +;; sure of truncating in that case. +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=m,!*r") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "f,f")))] + "TARGET_80387" + "* +{ + if (top_dead_p (insn)) + fp_pop_sf (operands[0]); + else + fp_store_sf (operands[0]); + RETCOM (truncdfsf2); +}") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. The 80387 would not know +;; what to do with the smaller sizes anyway. (I think). + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=fm,fm") + (float:SF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ +/* fp_pop_level++; */ + + if (GET_CODE (operands[1]) != MEM) + { + rtx xops[2]; + output_asm_insn (\"push%L0 %1\", operands); + operands[1] = AT_SP (SImode); + output_asm_insn (\"fild%L0 %1\", operands); + xops[0] = stack_pointer_rtx; + xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } + else + output_asm_insn (\"fild%L0 %1\", operands); + + if (! FP_REG_P (operands[0])) + { +/* fp_pop_level--; */ + return \"fstp%S0 %0\"; + } + RET; +}") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=fm,fm") + (float:DF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ +/* fp_pop_level++; */ + if (GET_CODE (operands[1]) != MEM) + { + rtx xops[2]; + output_asm_insn (\"push%L0 %1\", operands); + operands[1] = AT_SP (SImode); + output_asm_insn (\"fild%L0 %1\", operands); + xops[0] = stack_pointer_rtx; + xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } + else + output_asm_insn (\"fild%L0 %1\", operands); + if (! FP_REG_P (operands[0])) + { +/* fp_pop_level--; */ + return \"fstp%Q0 %0\"; + } + RET; +}") + +;; Convert a float to a float whose value is an integer. +;; This is the first stage of converting it to an integer type. + +;; On the 387 truncating doub to an short integer shor can be performed: + +; fstcw -4(%esp) ;save cw +; movw -4(%esp),%ax +; orw $0x0c00,%ax ;set rounding to chop towards zero +; movw %ax,-2(%esp) ; +; fldcw -2(%esp) ; +; fldl doubl +; fistpl -12(%esp) ;store the round value +; fldcw -4(%esp) ;restore cw +; movl -12(%esp),%eax +; movw %ax,shor ; move the result into shor. + +;; but it is probably better to have a call, rather than waste this +;; space. The last instruction would have been a movl if were +;; going to an int instead of a short. +;; For the moment we will go with the soft float for these. + +/* These are incorrect since they don't set the rounding bits of CW flag. + The proper way to do that is to make the function prologue save the CW + and also construct the alternate CW value needed for these insns. + Then these insns can output two fldcw's, referring to fixed places in + the stack frame. + +;; Convert a float whose value is an integer +;; to an actual integer. Second stage of converting float to integer type. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=m,?*q") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=m,?*r") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=m,?*r") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=m,?*q") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))] + + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=m,?*r") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=m,?*r") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") +*/ + + +;;- add instructions +;;moved incl to above leal + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "add%L0 %2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1)))] + "" + "inc%W0 %0") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=rm,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "add%W0 %2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=qm") + (plus:QI (match_operand:QI 1 "general_operand" "0") + (const_int 1)))] + "" + "inc%B0 %0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "add%B0 %2,%0") + +;;had "fmF,m" + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f") + (plus:DF (match_operand:DF 1 "general_operand" "%0,0,0") + (match_operand:DF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fadd%z0 %0\", \"fadd%z0 %0\", 2)") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f") + (plus:SF (match_operand:SF 1 "general_operand" "%0,0,0") + (match_operand:SF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fadd%z0 %0\", \"fadd%z0 %0\", 2)") + +;;- subtract instructions + +;;moved decl above leal + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (minus:SI (match_operand:SI 1 "general_operand" "0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "sub%L0 %2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1)))] + "" + "dec%W0 %0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=rm,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "sub%W0 %2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=qm") + (minus:QI (match_operand:QI 1 "general_operand" "0") + (const_int 1)))] + "" + "dec%B0 %0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "sub%B0 %2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f,f") + (minus:DF (match_operand:DF 1 "general_operand" "0,0,0,m") + (match_operand:DF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fsub%z0 %0\", \"fsubr%z0 %0\", 2)") + + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f,f") + (minus:SF (match_operand:SF 1 "general_operand" "0,0,0,m") + (match_operand:SF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fsub%z0 %0\", \"fsubr%z0 %0\", 2)") + +;;- multiply instructions + +;(define_insn "mulqi3" +; [(set (match_operand:QI 0 "general_operand" "=a") +; (mult:QI (match_operand:QI 1 "general_operand" "%0") +; (match_operand:QI 2 "general_operand" "qm")))] +; "" +; "mul%B0 %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=r,r") + (mult:SI (match_operand:HI 1 "general_operand" "%0,rm") + (match_operand:HI 2 "general_operand" "g,i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[0]) + && (GET_CODE (operands[2]) == MEM + || GET_CODE (operands[2]) == REG)) + /* Assembler has weird restrictions. */ + return AS2 (imul%W0,%2,%0); + return AS3 (imul%W0,%2,%1,%0); +}") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (mult:SI (match_operand:SI 1 "general_operand" "%0,rm") + (match_operand:SI 2 "general_operand" "g,i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[0]) + && (GET_CODE (operands[2]) == MEM + || GET_CODE (operands[2]) == REG)) + /* Assembler has weird restrictions. */ + return AS2 (imul%L0,%2,%0); + return AS3 (imul%L0,%2,%1,%0); +}") + +;; Turned off due to possible assembler bug. +;(define_insn "umulqi3" +; [(set (match_operand:QI 0 "general_operand" "=a") +; (umult:QI (match_operand:QI 1 "general_operand" "%0") +; (match_operand:QI 2 "general_operand" "qm")))] +; "" +; "mul%B0 %2,%0") + +;(define_insn "umulqihi3" +; [(set (match_operand:HI 0 "general_operand" "=a") +; (umult:HI (match_operand:QI 1 "general_operand" "%0") +; (match_operand:QI 2 "general_operand" "qm")))] +; "" +; "mul%B0 %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=a") + (umult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rm"))) + (clobber (reg:HI 1))] + "" + "mul%W0 %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=a") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rm"))) + (clobber (reg:SI 1))] + "" + "mul%L0 %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f") + (mult:DF (match_operand:DF 1 "general_operand" "%0,0,0") + (match_operand:DF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fmul%z0 %0\", \"fmul%z0 %0\", 2) +") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f") + (mult:SF (match_operand:SF 1 "general_operand" "%0,0,0") + (match_operand:SF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fmul%z0 %0\", \"fmul%z0 %0\", 2) +") + +;;- divide instructions +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f,f") + (div:DF (match_operand:DF 1 "general_operand" "0,0,0,m") + (match_operand:DF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fdiv%z0 %0\", \"fdivr%z0 %0\", 2) +") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f,f") + (div:SF (match_operand:SF 1 "general_operand" "0,0,0,m") + (match_operand:SF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fdiv%z0 %0\", \"fdivr%z0 %0\", 2) +") + +;; Divide and Remainder instructions. + +;; Copy operands 1 and 2 to new registers, so that there's no +;; danger that put_var_into_stack will mess up the sharing match_dup needs. +;; CSE will get rid of the extra pseudo regs. +;; No problem if not optimizing, since then only `register' vars +;; will get pseudo regs, and they aren't allowed to have address taken. + +(define_expand "divmodsi4" + [(parallel [(set (match_operand:SI 0 "general_operand" "=a") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (mod:SI (match_dup 1) (match_dup 2)))])] + "" + " +{ + extern int optimize; + if (optimize) + { + if (GET_CODE (operands[1]) == REG && REG_USERVAR_P (operands[1])) + operands[1] = copy_to_mode_reg (SImode, operands[1]); + if (GET_CODE (operands[2]) == REG && REG_USERVAR_P (operands[2])) + operands[2] = copy_to_mode_reg (SImode, operands[2]); + } +}") + +(define_expand "udivmodsi4" + [(parallel [(set (match_operand:SI 0 "general_operand" "=a") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (umod:SI (match_dup 1) (match_dup 2)))])] + "" + " +{ + extern int optimize; + if (optimize) + { + if (GET_CODE (operands[1]) == REG && REG_USERVAR_P (operands[1])) + operands[1] = copy_to_mode_reg (SImode, operands[1]); + if (GET_CODE (operands[2]) == REG && REG_USERVAR_P (operands[2])) + operands[2] = copy_to_mode_reg (SImode, operands[2]); + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (mod:SI (match_dup 1) (match_dup 2)))] + "" + "cltd\;idiv%L0 %2") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "xor%L0 %3,%3\;div%L0 %2") + +/* +;;this should be a valid double division which we may want to add + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (udiv:DI (match_operand:DI 1 "general_operand" "a") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "div%L0 %2,%0") +*/ + +;;- and instructions + +;; The `r' in `rm' for operand 3 looks redundant, but it causes +;; optional reloads to be generated if op 3 is a pseudo in a stack slot. + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "and%L0 %2,%0") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=rm,r") + (and:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "and%W0 %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "and%B0 %2,%0") + +/* I am nervous about these two.. add them later.. +;I presume this means that we have something in say op0= eax which is small +;and we want to and it with memory so we can do this by just an +;andb m,%al and have success. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "rm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%W0 %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=q") + (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "qm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%L0 %1,%0") + +*/ + + + +;;- Bit set (inclusive or) instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "or%L0 %2,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=rm,r") + (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "or%W0 %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "or%B0 %2,%0") + +;;- xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "xor%L0 %2,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=rm,r") + (xor:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "xor%W0 %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "qn")))] + "" + "xor%B0 %2,%0") + +;;- negation instructions +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "neg%L0 %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "neg%W0 %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=qm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg%B0 %0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=f,!m") + (neg:SF (match_operand:SF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fchs\")") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=f,!m") + (neg:DF (match_operand:DF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fchs\")") + +;; Absolute value instructions + +(define_insn "abssf2" + [(set (match_operand:SF 0 "general_operand" "=f,!m") + (abs:SF (match_operand:SF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fabs\")") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "general_operand" "=f,!m") + (abs:DF (match_operand:DF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fabs\")") + +;;- one complement instructions +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "not%L0 %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "not%W0 %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=qm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not%B0 %0") + +;;- arithmetic shift instructions + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sal%L0,%R0cl,%0); + else if (REG_P (operands[1]) && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1) + return AS2 (add%L0,%1,%1); + return AS2 (sal%L0,%2,%1); +}") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sal%W0,%R0cl,%0); + else + return AS2 (sal%W0,%2,%1); +}") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sal%B0,%R0cl,%0); + else + return AS2 (sal%B0,%2,%1); +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%L0,%R0cl,%0); + else + return AS2 (sar%L0,%2,%0); +}") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%W0,%R0cl,%0); + else + return AS2 (sar%W0,%2,%0); +}") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%B0,%R0cl,%0); + return + AS2 (sar%B0,%2,%1); +}") + +;;- logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shl%L0,%R0cl,%0); + else + return AS2 (shl%L0,%2,%1); +}") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shl%W0,%R0cl,%0); + else + return AS2 (shl%W0,%2,%1); +}") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shl%B0,%R0cl,%0); + else + return AS2 (shl%B0,%2,%1); +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%L0,%R0cl,%0); + else + return AS2 (shr%L0,%2,%1); +}") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%W0,%%cl,%0); + else + return AS2 (shr%W0,%2,%1); +}") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%B0,%%cl,%0); + else + return AS2 (shr%B0,%2,%1); +}") + +;;- rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%L0,%%cl,%0); + else + return AS2 (rol%L0,%2,%1); +}") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%W0,%%cl,%0); + else + return AS2 (rol%W0,%2,%1); +}") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%B0,%%cl,%0); + else + return AS2 (rol%B0,%2,%1); +}") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%L0,%%cl,%0); + else + return AS2 (ror%L0,%2,%1); +}") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%W0,%%cl,%0); + else + return AS2 (ror%W0,%2,%1); +}") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%B0,%%cl,%0); + else + return AS2 (ror%B0,%2,%1); +}") + +;; Store-flag instructions. + +(define_insn "seq" + [(set (match_operand:QI 0 "general_operand" "=q") + (eq (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + return \"sete %0\"; +") + +(define_insn "sne" + [(set (match_operand:QI 0 "general_operand" "=q") + (ne (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + return \"setne %0\"; +") + +(define_insn "sgt" + [(set (match_operand:QI 0 "general_operand" "=q") + (gt (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); +") + +(define_insn "sgtu" + [(set (match_operand:QI 0 "general_operand" "=q") + (gtu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"seta %0\"; ") + +(define_insn "slt" + [(set (match_operand:QI 0 "general_operand" "=q") + (lt (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); ") + +(define_insn "sltu" + [(set (match_operand:QI 0 "general_operand" "=q") + (ltu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"setb %0\"; ") + +(define_insn "sge" + [(set (match_operand:QI 0 "general_operand" "=q") + (ge (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); ") + +(define_insn "sgeu" + [(set (match_operand:QI 0 "general_operand" "=q") + (geu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"setae %0\"; ") + +(define_insn "sle" + [(set (match_operand:QI 0 "general_operand" "=q") + (le (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); +") + +(define_insn "sleu" + [(set (match_operand:QI 0 "general_operand" "=q") + (leu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"setbe %0\"; ") + +;; Basic conditional jump instructions. +;; We ignore the overflow flag for signed branch instructions. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "je %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jne %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ja %l0") + +;; There is no jump insn to check for `<' on IEEE floats. +;; Page 17-80 in the 80387 manual says jb, but that's wrong; +;; jb checks for `not >='. So swap the operands and do `>'. +(define_expand "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + extern rtx sequence_stack; + rtx prev = XEXP (XEXP (sequence_stack, 1), 0); + rtx body = PATTERN (prev); + rtx comp; + if (GET_CODE (body) == SET) + comp = SET_SRC (body); + else + comp = SET_SRC (XVECEXP (body, 0, 0)); + + if (GET_CODE (comp) == COMPARE + ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT + : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT) + { + if (GET_CODE (comp) == COMPARE) + { + rtx op0 = XEXP (comp, 0); + rtx op1 = XEXP (comp, 1); + XEXP (comp, 0) = op1; + XEXP (comp, 1) = op0; + } + else + { + rtx new = gen_rtx (COMPARE, VOIDmode, + CONST0_RTX (GET_MODE (comp)), comp); + if (GET_CODE (body) == SET) + SET_SRC (body) = new; + else + SET_SRC (XVECEXP (body, 0, 0)) = new; + } + emit_insn (gen_bgt (operands[0])); + DONE; + } +}") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jb %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jae %l0") + +;; See comment on `blt', above. +(define_expand "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + extern rtx sequence_stack; + rtx prev = XEXP (XEXP (sequence_stack, 1), 0); + rtx body = PATTERN (prev); + rtx comp; + if (GET_CODE (body) == SET) + comp = SET_SRC (body); + else + comp = SET_SRC (XVECEXP (body, 0, 0)); + + if (GET_CODE (comp) == COMPARE + ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT + : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT) + { + if (GET_CODE (comp) == COMPARE) + { + rtx op0 = XEXP (comp, 0); + rtx op1 = XEXP (comp, 1); + XEXP (comp, 0) = op1; + XEXP (comp, 1) = op0; + } + else + { + rtx new = gen_rtx (COMPARE, VOIDmode, + CONST0_RTX (GET_MODE (comp)), comp); + if (GET_CODE (body) == SET) + SET_SRC (body) = new; + else + SET_SRC (XVECEXP (body, 0, 0)) = new; + } + emit_insn (gen_bge (operands[0])); + DONE; + } +}") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jbe %l0") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jne %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "je %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jbe %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\") +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jae %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jb %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "ja %l0") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jmp %l0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "general_operand" "rm")) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ + CC_STATUS_INIT; + + return \"jmp %*%0\"; +}") + +/* +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (minus:HI (match_operand:HI 0 "general_operand" "c") + (const_int 1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "g")) + (pc))) + (set (match_dup 0) + (minus:HI (match_dup 0) + (const_int 1)))] + "" + "loop %l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (const_int -1) + (minus:SI (match_operand:SI 0 "general_operand" "c") + (const_int 1))) + (const_int 0)) + (label_ref (match_operand 1 "" "g")) + (pc))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (const_int 1)))] + "" + "loop %l1") +*/ + +;; Call subroutine returning no value. +(define_insn "call" + [(call (match_operand:QI 0 "indirect_operand" "m") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not really used on the m68000. + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + operands[0] = XEXP (operands[0], 0); + return \"call %*%0\"; + } + else + return \"call %0\"; +}") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "indirect_operand" "m") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not really used on the m68000. + "" + "* +{ + if (GET_CODE (operands[1]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 0); + output_asm_insn (\"call %*%1\", operands); + } + else + output_asm_insn (\"call %1\", operands); + + if (GET_MODE (operands[0]) == DFmode + || GET_MODE (operands[0]) == SFmode) + { +/* fp_pop_level++; */ + /* pop if reg dead */ + if (!FP_REG_P (operands[0])) + abort (); + if (top_dead_p (insn)) + { + POP_ONE_FP; + } + } + RET; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/i860.md b/gcc-1.40/config/i860.md new file mode 100644 index 0000000..5752a58 --- /dev/null +++ b/gcc-1.40/config/i860.md @@ -0,0 +1,2046 @@ +;;- Machine description for Intel 860 chip for GNU C compiler +;; Copyright (C) 1989 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +/* Bit-test instructions. */ + +(define_insn "" + [(set (cc0) (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_operand" "rL")) + (const_int 0)))] + "" + "* +{ + cc_status.flags |= CC_ONLY_EQ; + return \"and %1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_operand" "rL")) + (const_int 0)))] + "" + "* +{ + cc_status.flags |= CC_NEGATED; + cc_status.flags |= CC_ONLY_EQ; + return \"and %1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")) + (const_int 0)))] + "GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 0xffff) == 0" + "* +{ + cc_status.flags |= CC_ONLY_EQ; + return \"andh h%%%1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")) + (const_int 0)))] + "GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 0xffff) == 0" + "* +{ + cc_status.flags |= CC_NEGATED; + cc_status.flags |= CC_ONLY_EQ; + return \"andh h%%%1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (eq (ashiftrt:SI + (sign_extend:SI + (ashift:QI (match_operand:QI 0 "register_operand" "r") + (match_operand:QI 1 "logic_int" "n"))) + (match_operand:SI 2 "logic_int" "n")) + (const_int 0)))] + "" + "* +{ + int width = 8 - INTVAL (operands[2]); + int pos = 8 - width - INTVAL (operands[1]); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ~((-1) << width) << pos); + return \"and %2,%0,r0\"; +}") + +;; Compare instructions. +;; This controls RTL generation and register allocation. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpeqsi" + [(set (cc0) (eq (match_operand:SI 0 "logic_operand" "r,rL") + (match_operand:SI 1 "logic_operand" "L,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_EQ; + if (REG_P (operands[0])) + return \"xor %1,%0,r0\"; + return \"xor %0,%1,r0\"; +}") + +(define_insn "cmpltsi" + [(set (cc0) (lt (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + if (REG_P (operands[1])) + return \"subs %0,%1,r0\"; + cc_status.flags |= CC_REVERSED; + operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1])); + return \"adds %1,%0,r0\"; +}") + +(define_insn "cmpgtsi" + [(set (cc0) (gt (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + if (REG_P (operands[0])) + return \"subs %1,%0,r0\"; + cc_status.flags |= CC_REVERSED; + operands[0] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[0])); + return \"adds %0,%1,r0\"; +}") + +(define_insn "cmpgeusi" + [(set (cc0) (geu (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LEU; + if (REG_P (operands[1])) + return \"subu %0,%1,r0\"; + cc_status.flags |= CC_REVERSED; + operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1])); + return \"addu %1,%0,r0\"; +}") + +(define_insn "cmpleusi" + [(set (cc0) (leu (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LEU; + if (REG_P (operands[0])) + return \"subu %1,%0,r0\"; + cc_status.flags |= CC_REVERSED; + operands[0] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[0])); + return \"addu %0,%1,r0\"; +}") + +(define_insn "cmpeqsf" + [(set (cc0) (eq (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_EQ; + return \"pfeq.ss %r1,%r0,f0\"; +}") + +(define_insn "cmpltsf" + [(set (cc0) (lt (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.ss %r1,%r0,f0\"; +}") + +(define_insn "cmpgtsf" + [(set (cc0) (gt (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.ss %r0,%r1,f0\"; +}") + +(define_insn "cmplesf" + [(set (cc0) (le (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.ss %r1,%r0,f0\"; +}") + +(define_insn "cmpgesf" + [(set (cc0) (ge (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.ss %r0,%r1,f0\"; +}") + +(define_insn "cmpeqdf" + [(set (cc0) (eq (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_EQ; + return \"pfeq.dd %r1,%r0,f0\"; +}") + +(define_insn "cmpltdf" + [(set (cc0) (lt (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.dd %r1,%r0,f0\"; +}") + +(define_insn "cmpgtdf" + [(set (cc0) (gt (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.dd %r0,%r1,f0\"; +}") + +(define_insn "cmpledf" + [(set (cc0) (le (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.dd %r1,%r0,f0\"; +}") + +(define_insn "cmpgedf" + [(set (cc0) (ge (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.dd %r0,%r1,f0\"; +}") + +(define_insn "" + [(set (cc0) (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m")) + (match_operand:SI 1 "small_int" "I")))] + "INTVAL (operands[1]) >= 0" + "ld.s %0,r31\;xor %1,r31,r0") + +(define_insn "" + [(set (cc0) (eq (match_operand:SI 0 "small_int" "I") + (zero_extend:SI (match_operand:HI 1 "load_operand" "m"))))] + "INTVAL (operands[0]) >= 0" + "ld.s %1,r31\;xor %0,r31,r0") + +;; Define the real conditional branch instructions. + +(define_insn "cbranch" + [(set (pc) (if_then_else (cc0) (label_ref (match_operand 0 "" "")) (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_NEGATED) + return \"bnc %l0\"; + else + return \"bc %l0\"; +}") + +(define_insn "inverse_cbranch" + [(set (pc) (if_then_else (cc0) (pc) (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + if (cc_prev_status.flags & CC_NEGATED) + return \"bc %l0\"; + else + return \"bnc %l0\"; +}") + +;; Other conditional branches, made by combining. + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "bte_operand" "%rK") + (match_operand:SI 1 "bte_operand" "rJ")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG" + "bte %0,%r1,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "bte_operand" "%rK") + (match_operand:SI 1 "bte_operand" "rJ")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG" + "btne %0,%r1,%2") + +;; Optimize fetching an unsigned half word and comparing against constant. +;; No need to zero-extend. + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.s %0,r31\;bte %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:HI 1 "load_operand" "m"))) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.s %1,r31\;bte %0,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.s %0,r31\;btne %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:HI 1 "load_operand" "m"))) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.s %1,r31\;btne %0,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:QI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.b %0,r31\;bte %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:QI 1 "load_operand" "m"))) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.b %1,r31\;bte %0,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:QI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.b %0,r31\;btne %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:QI 1 "load_operand" "m"))) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.b %1,r31\;btne %0,r31,%2") + +;; Generation of conditionals. + +;; The first step is the emission of a standard-looking compare insn. +;; Then a standard-named conditional branch pattern is run. +;; That branch pattern looks back at the compare insn and deletes it. +;; It then emits a machine-specific compare insn and a branch-if-true +;; or a branch-if-false. + +;; These patterns have `abort' because they are supposed to be deleted +;; in that fashion. + +(define_insn "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "compare_operand" "") + (match_operand:SI 1 "compare_operand" "")))] + "" + "* abort ();") + +(define_insn "cmpsf" + [(set (cc0) (compare (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" "")))] + "" + "* abort ();") + +(define_insn "cmpdf" + [(set (cc0) (compare (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" "")))] + "" + "* abort ();") + +;; These are the standard-named conditional branch patterns. +;; Detailed comments are found in the first one only. + +(define_expand "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + /* Get out of the sequence just started for us. */ + + end_sequence (); + prev = get_last_insn (); + + /* Examine the preceding compare insn, and get rid of it. */ + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + + /* Now once again start a sequence for our new instructions. */ + + start_sequence (); + + /* Emit a single-condition compare insn according to + the type of operands and the condition to be tested. */ + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpeqsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpeqsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpeqdf (recog_operand[0], recog_operand[1])); + else + abort (); + + /* Emit branch-if-true. */ + + emit_jump_insn (gen_cbranch (label)); + + DONE; +}") + +(define_expand "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpeqsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpeqsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpeqdf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_inverse_cbranch (label)); + + DONE; +}") + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpgtsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpgtsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpgtdf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +(define_expand "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpltsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpltsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpltdf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +(define_expand "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + { + emit_insn (gen_cmpgtsi (recog_operand[0], recog_operand[1])); + emit_jump_insn (gen_inverse_cbranch (label)); + } + else + { + if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmplesf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpledf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + } + DONE; +}") + +(define_expand "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + { + emit_insn (gen_cmpltsi (recog_operand[0], recog_operand[1])); + emit_jump_insn (gen_inverse_cbranch (label)); + } + else + { + if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpgesf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpgedf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + } + DONE; +}") + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpleusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_inverse_cbranch (label)); + DONE; +}") + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpgeusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_inverse_cbranch (label)); + DONE; +}") + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpgeusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpleusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +;; Move instructions + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,m,f") + (match_operand:SI 1 "general_operand" "rmif,rfJ,rmfJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (FP_REG_P (operands[1])) + return \"fst.l %1,%0\"; + return \"st.l %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + if (FP_REG_P (operands[0])) + return \"fld.l %1,%0\"; + return \"ld.l %1,%0\"; + } + if (FP_REG_P (operands[1]) && FP_REG_P (operands[0])) + return \"fmov.ss %1,%0\"; + if (FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (FP_REG_P (operands[0]) && operands[1] == const0_rtx) + return \"fmov.ss f0,%0\"; + if (FP_REG_P (operands[0])) + return \"ixfr %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r,m,!*f,!r") + (match_operand:HI 1 "general_operand" "rmi,rJ,rJ*f,*f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"st.s %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + return \"ld.s %1,%0\"; + } + if (FP_REG_P (operands[1]) && FP_REG_P (operands[0])) + return \"fmov.ss %1,%0\"; + if (FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (FP_REG_P (operands[0]) && operands[1] == const0_rtx) + return \"fmov.ss f0,%0\"; + if (FP_REG_P (operands[0])) + return \"ixfr %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r,m,!*f,!r") + (match_operand:QI 1 "general_operand" "rmi,rJ,rJ*f,*f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"st.b %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + return \"ld.b %1,%0\"; + } + if (FP_REG_P (operands[1]) && FP_REG_P (operands[0])) + return \"fmov.ss %1,%0\"; + if (FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (FP_REG_P (operands[0]) && operands[1] == const0_rtx) + return \"fmov.ss f0,%0\"; + if (FP_REG_P (operands[0])) + return \"ixfr %1,%0\"; + return \"mov %1,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_expand "movstrsi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) + (mem:BLK (match_operand:BLK 1 "general_operand" ""))) + (use (match_operand:SI 2 "nonmemory_operand" "")) + (use (match_operand:SI 3 "immediate_operand" "")) + (clobber (match_dup 4)) + (clobber (match_dup 5)) + (clobber (match_dup 6)) + (clobber (match_dup 0)) + (clobber (match_dup 1))])] + "" + " +{ + operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); +}") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) + (mem:BLK (match_operand:SI 1 "register_operand" "r"))) + (use (match_operand:SI 2 "nonmemory_operand" "rn")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "register_operand" "=r")) + (clobber (match_operand:SI 5 "register_operand" "=r")) + (clobber (match_operand:SI 6 "register_operand" "=r")) + (clobber (match_dup 0)) + (clobber (match_dup 1))] + "" + "* return output_block_move (operands);") + +;; Floating point move insns + +;; This pattern forces (set (reg:DF ...) (const_double ...)) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general movdf pattern. +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=r,f,o") + (match_operand:DF 1 "" "mG,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov r0,%0\;mov r0,%1\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.l r0,l%%%m0(r31)\;st.l r0,l%%%m0+4(r31)\"; + } + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st.l r0,%0\;st.l r0,%1\"; + } + return output_move_double (operands); +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=*rm,&*r,?f,?*rm") + (match_operand:DF 1 "general_operand" "*r,m,*rfmG,f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + + /* Note that the only CONST_DOUBLE that should be possible is 0. */ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=rm,&r,?f,?rm") + (match_operand:DI 1 "general_operand" "r,miF,rfmG,fG"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + + if (FP_REG_P (operands[0]) && operands[1] == dconst0_rtx) + return \"fmov.dd f0,%0\"; + + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +;; The alternative m/r is separate from m/f +;; so that an f-reg won't be used as a reload reg between m and F. +;; The first alternative is separate from the second for the same reason. +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=*rf,*rf,*r,m,m") + (match_operand:SF 1 "general_operand" "*r,fmG,F,*r,fG"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmov.ss %1,%0\"; + if (GET_CODE (operands[1]) == REG) + return \"ixfr %1,%0\"; + if (operands[1] == fconst0_rtx) + return \"fmov.ss f0,%0\"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;fld.l l%%%m1(r31),%0\"; + } + return \"fld.l %1,%0\"; + } + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_CODE (operands[0]) == REG && FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (GET_CODE (operands[0]) == REG) + return \"mov %1,%0\"; + /* Now operand 0 must be memory. + If operand 1 is CONST_DOUBLE, its value must be 0. */ + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"fst.l %r1,l%%%m0(r31)\"; + } + return \"fst.l %r1,%0\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st.l %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld.l %1,%0\"; + if (operands[1] == fconst0_rtx) + return \"mov r0,%0\"; + return \"mov %1,%0\"; +}") + +;; Special load insns for REG+REG addresses. +;; Such addresses are not "legitimate" because st rejects them. + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=rf") + (match_operand:DF 1 "indexed_operand" "m"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=rf") + (match_operand:SF 1 "indexed_operand" "m"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + return \"fld.l %1,%0\"; + return \"ld.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "indexed_operand" "m"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + return \"fld.l %1,%0\"; + return \"ld.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r") + (match_operand:HI 1 "indexed_operand" "m"))] + "" + "ld.s %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "indexed_operand" "m"))] + "" + "ld.b %1,%0") + +;; Likewise for floating-point store insns. + +(define_insn "" + [(set (match_operand:DF 0 "indexed_operand" "=m") + (match_operand:DF 1 "register_operand" "f"))] + "" + "fst.d %1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "indexed_operand" "=m") + (match_operand:SF 1 "register_operand" "f"))] + "" + "fst.l %1,%0") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.b %1,l%%%m0(r31)\"; + } + else + return \"st.b %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.b %1,l%%%m0(r31)\"; + } + else + return \"st.b %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.s %1,l%%%m0(r31)\"; + } + else + return \"st.s %1,%0\"; + return \"mov %1,%0\"; +}") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "register_operand" "r")))] + "" + "and 0xffff,%1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "register_operand" "r")))] + "" + "and 0xff,%1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "register_operand" "r")))] + "" + "and 0xff,%1,%0") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "mr")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"shl 16,%1,%0\;shra 16,%0,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + abort (); + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.s l%%%m1(r31),%0\"; + } + else + return \"ld.s %1,%0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "mr")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"shl 24,%1,%0\;shra 24,%0,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + abort (); + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.b l%%%m1(r31),%0\"; + } + else + return \"ld.b %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "mr")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"shl 24,%1,%0\;shra 24,%0,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + abort (); + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.b l%%%m1(r31),%0\"; + } + else + return \"ld.b %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "indexed_operand" "m")))] + "" + "ld.s %1,%0") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "indexed_operand" "m")))] + "" + "ld.b %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "indexed_operand" "m")))] + "" + "ld.b %1,%0") + +;; Signed bitfield extractions come out looking like +;; (shiftrt (sign_extend (shift <Y> <C1>)) <C2>) +;; which we expand poorly as four shift insns. +;; These patters yeild two shifts: +;; (shiftrt (shift <Y> <C3>) <C4>) +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (match_operand:QI 1 "register_operand" "r")) + (match_operand:SI 2 "logic_int" "n")))] + "INTVAL (operands[2]) < 8" + "* +{ + return \"shl 24,%1,%0\;shra 24+%2,%0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (subreg:QI (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "logic_int" "n")) 0)) + (match_operand:SI 3 "logic_int" "n")))] + "INTVAL (operands[3]) < 8" + "* +{ + return \"shl 0x18+%2,%1,%0\;shra 0x18+%3,%0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (ashift:QI (match_operand:QI 1 "register_operand" "r") + (match_operand:QI 2 "logic_int" "n"))) + (match_operand:SI 3 "logic_int" "n")))] + "INTVAL (operands[3]) < 8" + "* +{ + return \"shl 0x18+%2,%1,%0\;shra 0x18+%3,%0,%0\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +;; First two patterns are for bitfields that came from memory +;; testing only the high bit. They work with old combiner. + +(define_insn "" + [(set (cc0) + (eq (zero_extend:SI (subreg:QI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)) + (const_int 0)))] + "" + "and 128,%0,r0") + +(define_insn "" + [(set (cc0) + (eq (sign_extend:SI (subreg:QI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)) + (const_int 0)))] + "" + "and 128,%0,r0") + +;; next two patterns are good for bitfields coming from memory +;; (via pseudo-register) or from a register, though this optimization +;; is only good for values contained wholly within the bottom 13 bits +(define_insn "" + [(set (cc0) + (eq + (and:SI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_int" "n")) + (match_operand:SI 2 "logic_int" "n")) + (const_int 0)))] + "LOGIC_INTVAL (INTVAL (operands[2]) << INTVAL (operands[1]))" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) << INTVAL (operands[1]))); + return \"and %2,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) + (eq + (and:SI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_int" "n")) + (match_operand:SI 2 "logic_int" "n")) + (const_int 0)))] + "LOGIC_INTVAL (INTVAL (operands[2]) << INTVAL (operands[1]))" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) << INTVAL (operands[1]))); + return \"and %2,%0,r0\"; +}") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF + (match_operand:SF 1 "register_operand" "f")))] + "" + "fmov.sd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "f")))] + "" + "fmov.ds %1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_expand "floatsidf2" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (xor:SI (match_operand:SI 1 "register_operand" "") + (const_int -2147483648))) + (set (subreg:SI (match_dup 5) 0) (match_dup 4)) + (set (subreg:SI (match_dup 5) 1) (subreg:SI (match_dup 2) 1)) + (set (match_operand:DF 0 "register_operand" "") + (minus:DF (match_dup 5) (match_dup 2)))] + "" + " +{ + /* Generate desired value, in float format of host machine. */ + double d = (double) (1 << 30) * ((double) (1 << 22) + (double) (1 << 1)); + operands[2] = gen_reg_rtx (DFmode); + operands[3] = immed_double_const (d, DFmode); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (DFmode); +}") + +;; Floating to fixed conversion. + +(define_expand "fix_truncdfsi2" + ;; This first insn produces a double-word value + ;; in which only the low word is valid. + [(set (match_dup 2) + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f")))) + (set (match_operand:SI 0 "register_operand" "=f") + (subreg:SI (match_dup 2) 0))] + "" + " +{ + operands[2] = gen_reg_rtx (DImode); +}") + +;; Recognize the first insn generated above. +;; This RTL looks like a fix_truncdfdi2 insn, +;; but we dont call it that, because only 32 bits +;; of the result are valid. +;; This pattern will work for the intended purposes +;; as long as we do not have any fixdfdi2 or fix_truncdfdi2. +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=f") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "" + "ftrunc.dd %1,%0") + +(define_expand "fix_truncsfsi2" + ;; This first insn produces a double-word value + ;; in which only the low word is valid. + [(set (match_dup 2) + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f")))) + (set (match_operand:SI 0 "register_operand" "=f") + (subreg:SI (match_dup 2) 0))] + "" + " +{ + operands[2] = gen_reg_rtx (DImode); +}") + +;; Recognize the first insn generated above. +;; This RTL looks like a fix_truncsfdi2 insn, +;; but we dont call it that, because only 32 bits +;; of the result are valid. +;; This pattern will work for the intended purposes +;; as long as we do not have any fixsfdi2 or fix_truncsfdi2. +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=f") + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "" + "ftrunc.sd %1,%0") + +;;- arithmetic instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,*f") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%r,*f") + (match_operand:SI 2 "nonmemory_operand" "rn,*f")))] + "" + "* +{ + if (which_alternative == 1) + return \"fiadd.ss %2,%1,%0\"; + if (REG_P (operands[2])) + return \"addu %2,%1,%0\"; + if (SMALL_INT (operands[2])) + return \"addu %2,%1,%0\"; + cc_status.flags &= ~CC_KNOW_HI_R31; + return \"orh h%%%2,r0,r31\;or l%%%2,r31,r31\;addu %1,r31,%0\"; +}") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=f") + (plus:DI (match_operand:DI 1 "register_operand" "%f") + (match_operand:DI 2 "register_operand" "f")))] + "" + "fiadd.dd %1,%2,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,*f") + (minus:SI (match_operand:SI 1 "register_operand" "r,I,*f") + (match_operand:SI 2 "nonmemory_operand" "rn,r,*f")))] + "" + "* +{ + if (which_alternative == 2) + return \"fisub.ss %1,%2,%0\"; + if (REG_P (operands[2])) + return \"subu %1,%2,%0\"; + if (SMALL_INT (operands[2]) && INTVAL (operands[2]) != -0x10000) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); + return \"addu %2,%1,%0\"; + } + cc_status.flags &= ~CC_KNOW_HI_R31; + return \"orh h%%%2,r0,r31\;or l%%%2,r31,r31\;sub %1,r31,%0\"; +}") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=f") + (minus:DI (match_operand:DI 1 "register_operand" "%f") + (match_operand:DI 2 "register_operand" "f")))] + "" + "fisub.dd %1,%2,%0") + +(define_expand "mulsi3" + [(set (subreg:SI (match_dup 4) 0) (match_operand:SI 1 "general_operand" "")) + (set (subreg:SI (match_dup 5) 0) (match_operand:SI 2 "general_operand" "")) + (clobber (match_dup 3)) + (set (subreg:SI (match_dup 3) 0) + (mult:SI (subreg:SI (match_dup 4) 0) (subreg:SI (match_dup 5) 0))) + (set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 0))] + "" + " +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); +}") + +(define_insn "" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=f") 0) + (mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 0) + (subreg:SI (match_operand:DI 2 "register_operand" "f") 0)))] + "" + "fmlow.dd %2,%1,%0") + +;;- and instructions (with compliment also) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"and %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"andh %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2]) & 0xffff); + output_asm_insn (\"andnot %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ~(unsigned) INTVAL (operands[2]) >> 16); + return \"andnoth %2,%0,%0\"; +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "rn"))))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"andnot %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"andnoth %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); + output_asm_insn (\"andnot %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"andnoth %2,%0,%0\"; +}") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"or %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"orh %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); + output_asm_insn (\"or %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"orh %2,%0,%0\"; +}") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"xor %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"xorh %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); + output_asm_insn (\"xor %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"xorh %2,%0,%0\"; +}") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "subu r0,%1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (not:SI (match_operand:SI 1 "arith_operand" "r")))] + "" + "subu -1,%1,%0") + +;; Floating point arithmetic instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fadd.dd %1,%2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fadd.ss %1,%2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fsub.dd %1,%2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fsub.ss %1,%2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fmul.dd %1,%2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fmul.ss %1,%2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "fsub.dd f0,%1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "fsub.ss f0,%1,%0") + +;; Shift instructions + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.b l%%%m1(r31),%0\"; + } + return \"ld.b %1,%0\"; +}") + + +;;- arithmetic shift instructions +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + return \"mov r0,%0\"; + return \"shl %2,%1,%0\"; +}") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (ashift:HI (match_operand:HI 1 "register_operand" "r") + (match_operand:HI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 16) + return \"mov r0,%0\"; + return \"shl %2,%1,%0\"; +}") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (ashift:QI (match_operand:QI 1 "register_operand" "r") + (match_operand:QI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 8) + return \"mov r0,%0\"; + return \"shl %2,%1,%0\"; +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + return \"shra 31,%1,%0\"; + return \"shra %2,%1,%0\"; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + return \"mov r0,%0\"; + return \"shr %2,%1,%0\"; +}") + +;; Unconditional and other jump instructions + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* +{ + return \"br %l0\;nop\"; +}") + +;; Here are two simple peepholes which fill the delay slot of +;; an unconditional branch. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "" + "* return output_delayed_branch (\"br %l2\", operands, insn);") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rfJ")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "" + "* return output_delayed_branch (\"br %l2\", operands, insn);") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "bri %0\;nop") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rfJ")) + (set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))] + "" + "* return output_delayed_branch (\"bri %2\", operands, insn);") + +;;- jump to subroutine +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i"))] + ;; operand[2] is next_arg_register + "" + " +{ + if (INTVAL (operands[1]) > 0) + { + emit_move_insn (arg_pointer_rtx, stack_pointer_rtx); + emit_insn (gen_rtx (USE, VOIDmode, arg_pointer_rtx)); + } +}") + +;;- jump to subroutine +(define_insn "" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i"))] + ;; operand[2] is next_arg_register + "" + "* +{ + /* strip the MEM. */ + operands[0] = XEXP (operands[0], 0); + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + return \"calli %0\;nop\"; + return \"call %0\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i"))] + ;;- Don't use operand 1 for most machines. + "! reg_mentioned_p (operands[0], operands[2])" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"calli %2\", operands, insn); + return output_delayed_branch (\"call %2\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rfJ")) + (call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i"))] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"calli %2\", operands, insn); + return output_delayed_branch (\"call %2\", operands, insn); +}") + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i")))] + ;; operand 3 is next_arg_register + "" + " +{ + if (INTVAL (operands[2]) > 0) + { + emit_move_insn (arg_pointer_rtx, stack_pointer_rtx); + emit_insn (gen_rtx (USE, VOIDmode, arg_pointer_rtx)); + } +}") + +(define_insn "" + [(set (match_operand 0 "register_operand" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i")))] + ;; operand 3 is next_arg_register + "" + "* +{ + /* strip the MEM. */ + operands[1] = XEXP (operands[1], 0); + CC_STATUS_INIT; + if (GET_CODE (operands[1]) == REG) + return \"calli %1\;nop\"; + return \"call %1\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i")))] + ;;- Don't use operand 4 for most machines. + "! reg_mentioned_p (operands[0], operands[3])" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"calli %3\", operands, insn); + return output_delayed_branch (\"call %3\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJf")) + (set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i")))] + ;;- Don't use operand 4 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"calli %3\", operands, insn); + return output_delayed_branch (\"call %3\", operands, insn); +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (label_ref (match_operand 2 "" "")))))] + "" + "* +{ + cc_status.flags = 0; + return \"mov %l2,r31\;ld.l r31(%1),%0\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))] + "REGNO (operands[0]) != REGNO (operands[2])" + "* return output_delayed_branch (\"bri %2\", operands, insn);") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/m68k.md b/gcc-1.40/config/m68k.md new file mode 100644 index 0000000..c241ab4 --- /dev/null +++ b/gcc-1.40/config/m68k.md @@ -0,0 +1,4156 @@ +;;- Machine description for GNU compiler +;;- Motorola 68000 Version +;; Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- instruction definitions + +;;- @@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. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' one of the address registers can be used. +;;- 'd' one of the data registers can be used. +;;- 'f' one of the m68881 registers can be used +;;- 'r' either a data or an address register can be used. +;;- 'x' if one of the Sun FPA registers +;;- 'y' if one of the Low Sun FPA registers (fpa0-fpa15). + +;;- Immediate Floating point operator constraints +;;- 'G' a floating point constant that is *NOT* one of the standard +;; 68881 constant values (to force calling output_move_const_double +;; to get it from rom if it is a 68881 constant). +;;- 'H' one of the standard FPA constant values +;; +;; See the functions standard_XXX_constant_p in output-m68k.c for more +;; info. + +;;- Immediate integer operand constraints: +;;- 'I' 1 .. 8 +;;- 'J' -32768 .. 32767 +;;- 'K' -128 .. 127 +;;- 'L' -8 .. -1 + +;;- FPA port explanation: + +;;- Usage of the Sun FPA and the 68881 together + +;;- The current port of gcc to the sun fpa disallows use of the m68881 +;;- instructions completely if code is targetted for the fpa. This is +;;- for the following reasons: + +;;- 1) Expressing the preference hierarchy (ie. use the fpa if you +;;- can, the 68881 otherwise, and data registers only if you are +;;- forced to it) is a bitch with the current constraint scheme, +;;- especially since it would have to work for any combination of +;;- -mfpa, -m68881. + +;;- 2) There are no instructions to move between the two types of +;;- registers; the stack must be used as an intermediary. + +;;- It could indeed be done; I think the best way would be to have +;;- seperate patterns for TARGET_FPA (which implies a 68881), +;;- TARGET_68881, and no floating point co-processor. Use +;;- define_expands for all of the named instruction patterns, and +;;- include code in the FPA instruction to deal with the 68881 with +;;- preferences specifically set to favor the fpa. Some of this has +;;- already been done: +;;- +;;- 1) Separation of most of the patterns out into a TARGET_FPA +;;- case and a TARGET_68881 case (the exceptions are the patterns +;;- which would need one define_expand and three define_insn's under +;;- it (with alot of duplicate code between them) to replace the +;;- current single define_insn. These are mov{[ds]f,[ds]i} and the +;;- first two patterns in the md. +;;- +;;- Some would still have to be done: +;;- +;;- 1) Add code to the fpa patterns which correspond to 68881 +;;- patterns to deal with the 68881 case (including preferences!). +;;- What you might actually do here is combine the fpa and 68881 code +;;- back together into one pattern for those instructions where it's +;;- absolutely necessary and save yourself some duplicate code. I'm +;;- not completely sure as to whether you could get away with doing +;;- this only for the mov* insns, or if you'd have to do it for all +;;- named insns. +;;- 2) Add code to the mov{[ds]f,[ds]i} instructions to handle +;;- moving between fpa regs and 68881 regs. + +;;- Since the fpa is more powerful than the 68881 and also has more +;;- registers, and since I think the reultant md would be medium ugly +;;- (lot's of duplicate code, ugly constraint strings), I elected not +;;- to do this change. + +;;- Another reason why someone *might* want to do the change is to +;;- control which register classes are accessed in a slightly cleaner +;;- way than I have. See the blurb on CONDITIONAL_REGISTER_USAGE in +;;- the internals manual. + +;;- Yet another reason why someone might want to do this change is to +;;- allow use of some of the 68881 insns which have no equivalent on +;;- the fpa. The sqrt instruction comes fairly quickly to mind. + +;;- If this is ever done, don't forget to change tm-sun3.h so that +;;- it *will* define __HAVE_68881__ when the FPA is in use. + +;;- Condition code hack + +;;- When a floating point compare is done in the fpa, the resulting +;;- condition codes are left in the fpastatus register. The values in +;;- this register must be moved into the 68000 cc register before any +;;- jump is executed. Once this has been done, regular jump +;;- instructions are fine (ie. floating point jumps are not necessary. +;;- They are only done if the cc is in the 68881). + +;;- The instructions that move the fpastatus register to the 68000 +;;- register clobber a data register (the move cannot be done direct). +;;- These instructions might be bundled either with the compare +;;- instruction, or the branch instruction. If we were using both the +;;- fpa and the 68881 together, we would wish to only mark the +;;- register clobbered if we were doing the compare in the fpa, but I +;;- think that that decision (whether to clobber the register or not) +;;- must be done before register allocation (makes sense) and hence we +;;- can't know if the floating point compare will be done in the fpa +;;- or the fp. So whenever we are asked for code that uses the fpa, +;;- we will mark a data register as clobbered. This is reasonable, as +;;- almost all floating point compare operations done with fpa code +;;- enabled will be done in the fpa. It's even more reasonable since +;;- we decided to make the 68881 and the fpa mutually exclusive. + +;;- We place to code to move the fpastatus register inside of a +;;- define_expand so that we can do it conditionally based on whether +;;- we are tagetting an fpa or not. + +;;- This still leaves us with the question of where we wish to put the +;;- code to move the fpastatus reg. If we put it in the compare +;;- instruction, we can restrict the clobbering of the register to +;;- floating point compares, but we can't take advantage of floating +;;- point subtracts & etc. that alter the fpastatus register. If we +;;- put it in the branch instruction, all branches compiled with fpa +;;- code enabled will clobber a data register, but we will be able to +;;- take advantage of fpa subtracts. This balance favors putting the +;;- code in with the compare instruction. + +;;- Note that if some enterprising hacker should decide to switch +;;- this, he'll need to modify the code in NOTICE_UPDATE_CC. + +;;- Usage of the top 16 fpa registers + +;;- The only locations which we may transfer fpa registers 16-31 from +;;- or to are the fpa registers 0-15. (68000 registers and memory +;;- locations are impossible). This causes problems in gcc, which +;;- assumes that mov?? instructions require no additional registers +;;- (see section 11.7) and since floating point moves *must* be +;;- supported into general registers (see section 12.3 under +;;- HARD_REGNO_OK_FOR_MODE_P) from anywhere. + +;;- My solution was to reserve fpa0 for moves into or out of these top +;;- 16 registers and to disparage the choice to reload into or out of +;;- these registers as much as I could. That alternative is always +;;- last in the list, so it will not be used unless all else fails. I +;;- will note that according to my current information, sun's compiler +;;- doesn't use these top 16 registers at all. + +;;- There is another possible way to do it. I *believe* that if you +;;- make absolutely sure that the code will not be exectued in the +;;- reload pass, you can support the mov?? names with define_expands +;;- which require new registers. This may be possible by the +;;- appropriate juggling of constraints. I may come back to this later. + +;;- Usage of constant RAM + +;;- This has been handled correctly (I believe) but the way I've done +;;- it could use a little explanation. The constant RAM can only be +;;- accessed when the instruction is in "command register" mode. +;;- "command register" mode means that no accessing of memory or the +;;- 68000 registers is being done. This can be expressed easily in +;;- constraints, so generally the mode of the instruction is +;;- determined by a branch off of which_alternative. In outputing +;;- instructions, a 'w' means to output an access to the constant ram +;;- (if the arg is CONST_DOUBLE and is one of the available +;;- constants), and 'x' means to output a register pair (if the arg is +;;- a 68000 register) and a 'y' is the combination of the above two +;;- processies. You use a 'y' in two operand DF instructions where you +;;- *know* the other operand is an fpa register, you use an 'x' in DF +;;- instructions where the arg might be a 68000 register and the +;;- instruction is *not* in "command register" mode, and you use a 'w' +;;- in two situations: 1) The instruction *is* in command register +;;- mode (and hence won't be accessing 68000 registers), or 2) The +;;- instruction is a two operand SF instruction where you know the +;;- other operand is an fpa register. + +;;- Optimization issues + +;;- I actually think that I've included all of the fpa instructions +;;- that should be included. Note that if someone is interested in +;;- doing serious floating point work on the sun fpa, I would advise +;;- the use of the "asm" instruction in gcc to allow you to use the +;;- sin, cos, and exponential functions on the fpa board. + +;;- END FPA Explanation Section. + + +;;- Some of these insn's are composites of several m68000 op codes. +;;- The assembler (or final @@??) insures that the appropriate one is +;;- selected. + +(define_insn "" + [(set (match_operand:DF 0 "push_operand" "=m") + (match_operand:DF 1 "general_operand" "ro<>fyF"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + return \"fmove%.d %f1,%0\"; + if (FPA_REG_P (operands[1])) + return \"fpmove%.d %1, %x0\"; + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=m") + (match_operand:DI 1 "general_operand" "ro<>Fy"))] + "" + "* +{ + return output_move_double (operands); +}") + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +{ +#ifdef ISI_OV + /* ISI's assembler fails to handle tstl a0. */ + if (! ADDRESS_REG_P (operands[0])) +#else + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) +#endif + return \"tst%.l %0\"; + /* If you think that the 68020 does not support tstl a0, + reread page B-167 of the 68020 manual more carefully. */ + /* On an address reg, cmpw may replace cmpl. */ +#ifdef HPUX_ASM + return \"cmp%.w %0,%#0\"; +#else + return \"cmp%.w %#0,%0\"; +#endif +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "rm"))] + "" + "* +{ +#ifdef ISI_OV + if (! ADDRESS_REG_P (operands[0])) +#else + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) +#endif + return \"tst%.w %0\"; +#ifdef HPUX_ASM + return \"cmp%.w %0,%#0\"; +#else + return \"cmp%.w %#0,%0\"; +#endif +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "dm"))] + "" + "tst%.b %0") + +(define_expand "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" ""))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, + gen_rtx (SET, VOIDmode, + cc0_rtx, operands[0]), + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx (SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "general_operand" "xmdF")) + (clobber (match_operand:SI 1 "general_operand" "d"))] + "TARGET_FPA" + "fptst%.s %x0\;fpmove fpastatus,%1\;movw %1,cc") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fdm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + if (FP_REG_P (operands[0])) + return \"ftst%.x %0\"; + return \"ftst%.s %0\"; +}") + +(define_expand "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" ""))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, gen_rtx (SET, VOIDmode, + cc0_rtx, operands[0]), + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx (SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "general_operand" "xrmF")) + (clobber (match_operand:SI 1 "general_operand" "d"))] + "TARGET_FPA" + "fptst%.d %x0\;fpmove fpastatus,%1\;movw %1,cc") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + if (FP_REG_P (operands[0])) + return \"ftst%.x %0\"; + return \"ftst%.d %0\"; +}") + +;; compare instructions. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +;; A composite of the cmp, cmpa, & cmpi m68000 op codes. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "rKs,mr,>") + (match_operand:SI 1 "general_operand" "mr,Ksr,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.l %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.l %d1,%d0\"; +#else + return \"cmp%.l %d0,%d1\"; +#endif + } +#ifdef HPUX_ASM + return \"cmp%.l %d0,%d1\"; +#else + return \"cmp%.l %d1,%d0\"; +#endif +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "rnm,d,n,m") + (match_operand:HI 1 "general_operand" "d,rnm,m,n")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.w %1,%0\"; + if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1])) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.w %d1,%d0\"; +#else + return \"cmp%.w %d0,%d1\"; +#endif + } +#ifdef HPUX_ASM + return \"cmp%.w %d0,%d1\"; +#else + return \"cmp%.w %d1,%d0\"; +#endif +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "dn,md,>") + (match_operand:QI 1 "general_operand" "dm,nd,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.b %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.b %d1,%d0\"; +#else + return \"cmp%.b %d0,%d1\"; +#endif + } +#ifdef HPUX_ASM + return \"cmp%.b %d0,%d1\"; +#else + return \"cmp%.b %d1,%d0\"; +#endif +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + rtx set = gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, VOIDmode, operands[0], operands[1])); + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, set, + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx (SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "x,y") + (match_operand:DF 1 "general_operand" "xH,rmF"))) + (clobber (match_operand:SI 2 "general_operand" "d,d"))] + "TARGET_FPA" + "fpcmp%.d %y1,%0\;fpmove fpastatus,%2\;movw %2,cc") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "f,mG") + (match_operand:DF 1 "general_operand" "fmG,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef HPUX_ASM + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.d %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %1,%f0\"; +#else + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.d %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %f0,%1\"; +#endif +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + rtx set = gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, VOIDmode, operands[0], operands[1])); + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, set, + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx(SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "x,y") + (match_operand:SF 1 "general_operand" "xH,rmF"))) + (clobber (match_operand:SI 2 "general_operand" "d,d"))] + "TARGET_FPA" + "fpcmp%.s %w1,%x0\;fpmove fpastatus,%2\;movw %2,cc") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "f,mdG") + (match_operand:SF 1 "general_operand" "fmdG,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef HPUX_ASM + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.s %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %1,%f0\"; +#else + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.s %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %f0,%1\"; +#endif +}") + +;; Recognizers for btst instructions. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; The following two patterns are like the previous two +;; except that they use the fact that bit-number operands +;; are automatically masked to 3 or 5 bits. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 7)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 31)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; Nonoffsettable mem refs are ok in this one pattern +;; since we don't try to adjust them. +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "md") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 8" + "* +{ + operands[1] = gen_rtx (CONST_INT, VOIDmode, 7 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +(define_insn "" + ;; The constraint "o,d" here means that a nonoffsettable memref + ;; will match the first alternative, and its address will be reloaded. + ;; Copying the memory contents into a reg would be incorrect if the + ;; bit position is over 7. + [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "o,d") + (const_int 1) + (match_operand:SI 1 "general_operand" "i,i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 15 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 15); +}") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "do") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 31 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 31); +}") + +(define_insn "" + [(set (cc0) (subreg:SI (lshiftrt:QI (match_operand:QI 0 "nonimmediate_operand" "dm") + (const_int 7)) + 0))] + "" + "* +{ + cc_status.flags = CC_Z_IN_NOT_N | CC_NOT_NEGATIVE; + return \"tst%.b %0\"; +}") + +(define_insn "" + [(set (cc0) (and:SI (sign_extend:SI (sign_extend:HI (match_operand:QI 0 "nonimmediate_operand" "dm"))) + (match_operand:SI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 0x100 + && exact_log2 (INTVAL (operands[1])) >= 0)" + "* +{ register int log = exact_log2 (INTVAL (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, log); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +;; move instructions + +;; A special case in which it is not desirable +;; to reload the constant into a data register. +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "general_operand" "J"))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -0x8000 + && INTVAL (operands[1]) < 0x8000" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.l %0\"; + return \"pea %a1\"; +}") + +;This is never used. +;(define_insn "swapsi" +; [(set (match_operand:SI 0 "general_operand" "r") +; (match_operand:SI 1 "general_operand" "r")) +; (set (match_dup 1) (match_dup 0))] +; "" +; "exg %1,%0") + +;; Special case of fullword move when source is zero. +;; The reason this is special is to avoid loading a zero +;; into a data reg with moveq in order to store it elsewhere. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (const_int 0))] + ;; clr insns on 68000 read before writing. + ;; This isn't so on the 68010, but we have no alternative for it. + "(TARGET_68020 + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"sub%.l %0,%0\"; + /* moveq is faster on the 68000. */ + if (DATA_REG_P (operands[0]) && !TARGET_68020) +#ifdef MOTOROLA + return \"moveq%.l %#0,%0\"; +#else + return \"moveq %#0,%0\"; +#endif + return \"clr%.l %0\"; +}") + +;; General case of fullword move. The register constraints +;; force integer constants in range for a moveq to be reloaded +;; if they are headed for memory. +(define_insn "movsi" + ;; Notes: make sure no alternative allows g vs g. + ;; We don't allow f-regs since fixed point cannot go in them. + ;; We do allow y and x regs since fixed point is allowed in them. + [(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m") + (match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))] + "" + "* +{ + if (which_alternative == 3) + return \"fpmove%.l %x1,fpa0\;fpmove%.l fpa0,%x0\"; + if (FPA_REG_P (operands[1]) || FPA_REG_P (operands[0])) + return \"fpmove%.l %x1,%x0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.l %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { +#ifdef MOTOROLA + return \"moveq%.l %1,%0\"; +#else + return \"moveq %1,%0\"; +#endif + } + else if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"move%.w %1,%0\"; + else if (push_operand (operands[0], SImode) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"pea %a1\"; + } + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && push_operand (operands[0], SImode)) + return \"pea %a1\"; + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && ADDRESS_REG_P (operands[0])) + return \"lea %a1,%0\"; + return \"move%.l %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.w %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { +#ifdef MOTOROLA + return \"moveq%.l %1,%0\"; +#else + return \"moveq %1,%0\"; +#endif + } + else if (INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"move%.w %1,%0\"; + } + else if (CONSTANT_P (operands[1])) + return \"move%.l %1,%0\"; +#ifndef SONY_ASM + /* Recognize the insn before a tablejump, one that refers + to a table of offsets. Such an insn will need to refer + to a label on the insn. So output one. Use the label-number + of the table of offsets to generate this label. */ + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + || GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF) + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) != PLUS) + { + rtx labelref; + if (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF) + labelref = XEXP (XEXP (operands[1], 0), 0); + else + labelref = XEXP (XEXP (operands[1], 0), 1); +#if defined (MOTOROLA) && ! defined (SGS_3B1) +#ifdef SGS + fprintf (asm_out_file, \"\\tset %s%d,.+2\\n\", \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#else /* not SGS */ + fprintf (asm_out_file, \"\\t.set %s%d,.+2\\n\", \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#endif /* not SGS */ +#else /* SGS_3B1 or not MOTOROLA */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); + /* For sake of 3b1, set flag saying we need to define the symbol + LD%n (with value L%n-LI%n) at the end of the switch table. */ + RTX_INTEGRATED_P (next_real_insn (XEXP (labelref, 0))) = 1; +#endif /* SGS_3B1 or not MOTOROLA */ + } +#endif /* SONY_ASM */ + return \"move%.w %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (match_operand:HI 1 "general_operand" "rmn"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.w %0\"; + } + return \"move%.w %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=d,*a,m,m,?*a") + (match_operand:QI 1 "general_operand" "dmi*a,d*a,dmi,?*a,m"))] + "" + "* +{ + rtx xoperands[4]; + if (ADDRESS_REG_P (operands[0]) && GET_CODE (operands[1]) == MEM) + { + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + /* Just pushing a byte puts it in the high byte of the halfword. */ + /* We must put it in the low half, the second byte. */ + output_asm_insn (\"subq%.w %#2,%3\;move%.b %1,%2\", xoperands); + return \"move%.w %+,%0\"; + } + if (ADDRESS_REG_P (operands[1]) && GET_CODE (operands[0]) == MEM) + { + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + output_asm_insn (\"move%.w %1,%-\;move%.b %2,%0\;addq%.w %#2,%3\", xoperands); + return \"\"; + } + /* clr and st insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + if (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + { + if (operands[1] == const0_rtx) + return \"clr%.b %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + { + CC_STATUS_INIT; + return \"st %0\"; + } + } + if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) + return \"move%.l %1,%0\"; + if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) + return \"move%.w %1,%0\"; + return \"move%.b %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (match_operand:QI 1 "general_operand" "dmn"))] + "" + "* +{ + if (operands[1] == const0_rtx + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) + return \"clr%.b %0\"; + return \"move%.b %1,%0\"; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=rmf,x,y,rm,!x,!rm") + (match_operand:SF 1 "general_operand" "rmfF,xH,rmF,y,rm,x"))] +; [(set (match_operand:SF 0 "general_operand" "=rmf") +; (match_operand:SF 1 "general_operand" "rmfF"))] + "" + "* +{ + if (which_alternative >= 4) + return \"fpmove%.s %1,fpa0\;fpmove%.s fpa0,%0\"; + if (FPA_REG_P (operands[0])) + { + if (FPA_REG_P (operands[1])) + return \"fpmove%.s %x1,%x0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + else if (FP_REG_P (operands[1])) + return \"fmove%.s %1,sp@-\;fpmove%.d sp@+, %0\"; + return \"fpmove%.s %x1,%x0\"; + } + if (FPA_REG_P (operands[1])) + { + if (FP_REG_P (operands[0])) + return \"fpmove%.s %x1,sp@-\;fmove%.s sp@+,%0\"; + else + return \"fpmove%.s %x1,%x0\"; + } + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + else if (ADDRESS_REG_P (operands[1])) + return \"move%.l %1,%-\;fmove%.s %+,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + return \"fmove%.s %f1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (ADDRESS_REG_P (operands[0])) + return \"fmove%.s %1,%-\;move%.l %+,%0\"; + return \"fmove%.s %f1,%0\"; + } + return \"move%.l %1,%0\"; +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=rm,&rf,&rof<>,y,rm,x,!x,!rm") + (match_operand:DF 1 "general_operand" "rf,m,rofF<>,rmF,y,xH,rm,x"))] +; [(set (match_operand:DF 0 "general_operand" "=rm,&rf,&rof<>") +; (match_operand:DF 1 "general_operand" "rf,m,rofF<>"))] + "" + "* +{ + if (which_alternative == 6) + return \"fpmove%.d %x1,fpa0\;fpmove%.d fpa0,%x0\"; + if (FPA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,sp@-\;fpmove%.d sp@+,%x0\"; + return \"fpmove%.d %x1,%x0\"; + } + else if (FPA_REG_P (operands[1])) + { + if (FP_REG_P(operands[0])) + return \"fpmove%.d %x1,sp@-\;fmoved sp@+,%0\"; + else + return \"fpmove%.d %x1,%x0\"; + } + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmove%.d %f1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.d %f1,%0\"; + } + return output_move_double (operands); +} +") + +;; movdi can apply to fp regs in some cases +(define_insn "movdi" + ;; Let's see if it really still needs to handle fp regs, and, if so, why. + [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>,y,rm,!*x,!rm") + (match_operand:DI 1 "general_operand" "rF,m,roi<>F,rmiF,y,rmF,*x"))] +; [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>,!&rm,!&f,y,rm,x,!x,!rm") +; (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfmF,rmi,y,rm,x"))] +; [(set (match_operand:DI 0 "general_operand" "=rm,&rf,&ro<>,!&rm,!&f") +; (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfF"))] + "" + "* +{ + if (which_alternative == 8) + return \"fpmove%.d %x1,fpa0\;fpmove%.d fpa0,%x0\"; + if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) + return \"fpmove%.d %x1,%x0\"; + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmove%.d %f1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.d %f1,%0\"; + } + return output_move_double (operands); +} +") + +;; Thus goes after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. It goes before the add/sub insns +;; so we will prefer it to them. + +(define_insn "pushasi" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "address_operand" "p"))] + "" + "pea %a1") + +;; truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:SI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the mov.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 3); + return \"move%.b %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:HI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG + && (GET_CODE (operands[1]) == MEM + || GET_CODE (operands[1]) == CONST_INT)) + { + /* Must clear condition codes, since the mov.w bases them on + the entire 16 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.w %1,%0\"; + } + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the mov.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 1); + return \"move%.b %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=dm,d") + (truncate:HI + (match_operand:SI 1 "general_operand" "roJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the mov.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 2); + return \"move%.w %1,%0\"; +}") + +;; zero extension instructions + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:HI (match_dup 0) 0)) + (match_operand:HI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + " operands[1] = make_safe_from (operands[1], operands[0]); ") + +;; Patterns to recognize zero-extend insns produced by the combiner. + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "rmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFFFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.w %1,%0\;and%.l %#0xFFFF,%0\"; + return \"clr%.l %0\;move%.w %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"move%.w %1,%0\;clr%.w %0\"; + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.w %0\;move%.w %1,%0\"; + else + { + output_asm_insn (\"clr%.w %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 2); + return \"move%.w %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=do<>") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.w %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.w %#0xFF,%0\"; + return \"clr%.w %0\;move%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + if (REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM) + { + output_asm_insn (\"clr%.w %-\", operands); + operands[0] = gen_rtx (MEM, GET_MODE (operands[0]), + plus_constant (stack_pointer_rtx, 1)); + return \"move%.b %1,%0\"; + } + else + return \"move%.b %1,%0\;clr%.b %0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.b %0\;move%.b %1,%0\"; + else + { + output_asm_insn (\"clr%.b %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 1); + return \"move%.b %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;move%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); +#ifdef MOTOROLA +#ifdef SGS + return \"clr.l -(%0)\;move%.b %1,3(%0)\"; +#else + return \"clr.l -(%0)\;move%.b %1,(3,%0)\"; +#endif +#else + return \"clrl %0@-\;moveb %1,%0@(3)\"; +#endif + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); +#ifdef MOTOROLA +#ifdef SGS + return \"clr.l (%0)+\;move%.b %1,-1(%0)\"; +#else + return \"clr.l (%0)+\;move%.b %1,(-1,%0)\"; +#endif +#else + return \"clrl %0@+\;moveb %1,%0@(-1)\"; +#endif + } + else + { + output_asm_insn (\"clr%.l %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 3); + return \"move%.b %1,%0\"; + } +}") + +;; sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "0,rmn")))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"move%.w %1,%0\"; + return \"ext%.l %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=d") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "0")))] + "" + "ext%.w %0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "0")))] + "TARGET_68020" + "extb%.l %0") + +;; Conversions between float and double. + +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "") + (float_extend:DF + (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (float_extend:DF + (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpstod %w1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=*fdm,f") + (float_extend:DF + (match_operand:SF 1 "general_operand" "f,dmF")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + /* Extending float to double in an fp-reg is a no-op. + NOTICE_UPDATE_CC has already assumed that the + cc will be set. So cancel what it did. */ + cc_status = cc_prev_status; + return \"\"; + } + return \"fmove%.x %1,%0\"; + } + if (FP_REG_P (operands[0])) + return \"fmove%.s %f1,%0\"; + if (DATA_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + return \"fmove%.d %f1,%0\"; +}") + +;; This cannot output into an f-reg because there is no way to be +;; sure of truncating in that case. +;; But on the Sun FPA, we can be sure. +(define_expand "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpdtos %y1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=dm") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.s %f1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "") + (float:SF (match_operand:SI 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=y,x") + (float:SF (match_operand:SI 1 "general_operand" "rmi,x")))] + "TARGET_FPA" + "fpltos %1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_expand "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "") + (float:DF (match_operand:SI 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=y,x") + (float:DF (match_operand:SI 1 "general_operand" "rmi,x")))] + "TARGET_FPA" + "fpltod %1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.b %1,%0") + +;; Convert a float to a float whose value is an integer. +;; This is the first stage of converting it to an integer type. + +(define_insn "ftruncdf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (fix:DF (match_operand:DF 1 "general_operand" "fFm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.d %f1,%0\"; +}") + +(define_insn "ftruncsf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (fix:SF (match_operand:SF 1 "general_operand" "dfFm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.s %f1,%0\"; +}") + +;; Convert a float whose value is an integer +;; to an actual integer. Second stage of converting float to integer type. +(define_insn "fixsfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixsfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "fixdfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixdfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +;; Convert a float to an integer. +;; On the Sun FPA, this is done in one step. + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=x,y") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "xH,rmF"))))] + "TARGET_FPA" + "fpstol %w1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=x,y") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "xH,rmF"))))] + "TARGET_FPA" + "fpdtol %y1,%0") + +;; add instructions + +;; Note that the last two alternatives are near-duplicates +;; in order to handle insns generated by reload. +;; This is needed since they are not themselves reloaded, +;; so commutativity won't apply to them. +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,!a") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0,a,rJK") + (match_operand:SI 2 "general_operand" "dIKLs,mrIKLs,rJK,a")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (!ADDRESS_REG_P (operands[1])) + { + rtx tmp = operands[1]; + + operands[1] = operands[2]; + operands[2] = tmp; + } + + /* These insns can result from reloads to access + stack slots over 64k from the frame pointer. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000) + return \"move%.l %2,%0\;add%.l %1,%0\"; +#ifdef SGS + if (GET_CODE (operands[2]) == REG) + return \"lea 0(%1,%2.l),%0\"; + else + return \"lea %c2(%1),%0\"; +#else /* not SGS */ +#ifdef MOTOROLA + if (GET_CODE (operands[2]) == REG) + return \"lea (%1,%2.l),%0\"; + else + return \"lea (%c2,%1),%0\"; +#else /* not MOTOROLA (MIT syntax) */ + if (GET_CODE (operands[2]) == REG) + return \"lea %1@(0,%2:l),%0\"; + else + return \"lea %1@(%c2),%0\"; +#endif /* not MOTOROLA */ +#endif /* not SGS */ + } + if (GET_CODE (operands[2]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return (ADDRESS_REG_P (operands[0]) + ? \"addq%.w %2,%0\" + : \"addq%.l %2,%0\"); + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return (ADDRESS_REG_P (operands[0]) + ? \"subq%.w %2,%0\" + : \"subq%.l %2,%0\"); + } +#endif + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"add%.w %2,%0\"; + } + return \"add%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "add%.w %2,%0") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return \"subq%.w %2,%0\"; + } + } +#endif + return \"add%.w %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "add%.w %1,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.b %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); + return \"subq%.b %2,%0\"; + } + } +#endif + return \"add%.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "add%.b %1,%0") + +(define_expand "adddf3" + [(set (match_operand:DF 0 "general_operand" "") + (plus:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (plus:DF (match_operand:DF 1 "general_operand" "%xH,y") + (match_operand:DF 2 "general_operand" "xH,dmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpadd%.d %y2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpadd%.d %y1,%0\"; + if (which_alternative == 0) + return \"fpadd3%.d %w2,%w1,%0\"; + return \"fpadd3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fadd%.x %2,%0\"; + return \"fadd%.d %f2,%0\"; +}") + +(define_expand "addsf3" + [(set (match_operand:SF 0 "general_operand" "") + (plus:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (plus:SF (match_operand:SF 1 "general_operand" "%xH,y") + (match_operand:SF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpadd%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpadd%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpadd3%.s %w2,%w1,%0\"; + return \"fpadd3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fadd%.x %2,%0\"; + return \"fadd%.s %f2,%0\"; +}") + +;; subtract instructions + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,?d") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,a,mrIKs") + (match_operand:SI 2 "general_operand" "dIKs,mrIKs,J,0")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (operands_match_p (operands[0], operands[2])) + { +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"subq%.l %1,%0\;neg%.l %0\"; + } +#endif + return \"sub%.l %1,%0\;neg%.l %0\"; + } + /* This case is matched by J, but negating -0x8000 + in an lea would give an invalid displacement. + So do this specially. */ + if (INTVAL (operands[2]) == -0x8000) + return \"move%.l %1,%0\;sub%.l %2,%0\"; +#ifdef SGS + return \"lea %n2(%1),%0\"; +#else +#ifdef MOTOROLA + return \"lea (%n2,%1),%0\"; +#else /* not MOTOROLA (MIT syntax) */ + return \"lea %1@(%n2),%0\"; +#endif /* not MOTOROLA */ +#endif /* not SGS */ + } + if (GET_CODE (operands[2]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"subq%.l %2,%0\"; +#endif + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"sub%.w %2,%0\"; + } + return \"sub%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "sub%.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "sub%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (minus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "sub%.w %1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "sub%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (minus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "sub%.b %1,%0") + +(define_expand "subdf3" + [(set (match_operand:DF 0 "general_operand" "") + (minus:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y,y") + (minus:DF (match_operand:DF 1 "general_operand" "xH,y,dmF") + (match_operand:DF 2 "general_operand" "xH,dmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprsub%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpsub%.d %y2,%0\"; + if (which_alternative == 0) + return \"fpsub3%.d %w2,%w1,%0\"; + return \"fpsub3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fsub%.x %2,%0\"; + return \"fsub%.d %f2,%0\"; +}") + +(define_expand "subsf3" + [(set (match_operand:SF 0 "general_operand" "") + (minus:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y,y") + (minus:SF (match_operand:SF 1 "general_operand" "xH,y,rmF") + (match_operand:SF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprsub%.s %w1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpsub%.s %w2,%0\"; + if (which_alternative == 0) + return \"fpsub3%.s %w2,%w1,%0\"; + return \"fpsub3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fsub%.x %2,%0\"; + return \"fsub%.s %f2,%0\"; +}") + +;; multiply instructions + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"muls.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"muls.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "muls%.l %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"mulu.w %2,%0\"; +#else + return \"mulu %2,%0\"; +#endif +}") + +(define_insn "umulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"mulu.w %2,%0\"; +#else + return \"mulu %2,%0\"; +#endif +}") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "mulu%.l %2,%0") + +(define_expand "muldf3" + [(set (match_operand:DF 0 "general_operand" "") + (mult:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (mult:DF (match_operand:DF 1 "general_operand" "%xH,y") + (match_operand:DF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"fpsqr%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpmul%.d %y2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpmul%.d %y1,%0\"; + if (which_alternative == 0) + return \"fpmul3%.d %w2,%w1,%0\"; + return \"fpmul3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fmul%.x %2,%0\"; + return \"fmul%.d %f2,%0\"; +}") + +(define_expand "mulsf3" + [(set (match_operand:SF 0 "general_operand" "") + (mult:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (mult:SF (match_operand:SF 1 "general_operand" "%xH,y") + (match_operand:SF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"fpsqr%.s %w1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpmul%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpmul%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpmul3%.s %w2,%w1,%0\"; + return \"fpmul3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fsglmul%.x %2,%0\"; + return \"fsglmul%.s %f2,%0\"; +}") + +;; divide instructions + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"ext.l %0\;divs.w %2,%0\"; +#else + return \"extl %0\;divs %2,%0\"; +#endif +}") + +(define_insn "divhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"divs.w %2,%0\"; +#else + return \"divs %2,%0\"; +#endif +}") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divs%.l %2,%0") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"and.l %#0xFFFF,%0\;divu.w %2,%0\"; +#else + return \"andl %#0xFFFF,%0\;divu %2,%0\"; +#endif +}") + +(define_insn "udivhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"divu.w %2,%0\"; +#else + return \"divu %2,%0\"; +#endif +}") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divu%.l %2,%0") + +(define_expand "divdf3" + [(set (match_operand:DF 0 "general_operand" "") + (div:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y,y") + (div:DF (match_operand:DF 1 "general_operand" "xH,y,rmF") + (match_operand:DF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprdiv%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpdiv%.d %y2,%0\"; + if (which_alternative == 0) + return \"fpdiv3%.d %w2,%w1,%0\"; + return \"fpdiv3%.d %x2,%x1,%x0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fdiv%.x %2,%0\"; + return \"fdiv%.d %f2,%0\"; +}") + +(define_expand "divsf3" + [(set (match_operand:SF 0 "general_operand" "") + (div:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y,y") + (div:SF (match_operand:SF 1 "general_operand" "xH,y,rmF") + (match_operand:SF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpdiv%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fprdiv%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpdiv3%.s %w2,%w1,%0\"; + return \"fpdiv3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fsgldiv%.x %2,%0\"; + return \"fsgldiv%.s %f2,%0\"; +}") + +;; Remainder instructions. + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"ext.l %0\;divs.w %2,%0\;swap.w %0\"; +#else + return \"ext.l %0\;divs.w %2,%0\;swap %0\"; +#endif +#else + return \"extl %0\;divs %2,%0\;swap %0\"; +#endif +}") + +(define_insn "modhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"divs.w %2,%0\;swap.w %0\"; +#else + return \"divs.w %2,%0\;swap %0\"; +#endif +#else + return \"divs %2,%0\;swap %0\"; +#endif +}") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"and.l %#0xFFFF,%0\;divu.w %2,%0\;swap.w %0\"; +#else + return \"and.l %#0xFFFF,%0\;divu.w %2,%0\;swap %0\"; +#endif +#else + return \"andl %#0xFFFF,%0\;divu %2,%0\;swap %0\"; +#endif +}") + +(define_insn "umodhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"divu.w %2,%0\;swap.w %0\"; +#else + return \"divu.w %2,%0\;swap %0\"; +#endif +#else + return \"divu %2,%0\;swap %0\"; +#endif +}") + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divsl%.l %2,%3:%0") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divul%.l %2,%3:%0") + +;; logical-and instructions + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xffff) == 0xffffffff + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (operands[2] == const0_rtx) + return \"clr%.w %0\"; + return \"and%.w %2,%0\"; + } + return \"and%.l %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (and:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "and%.w %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "and%.b %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%.w %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%.b %1,%0") + +;; inclusive-or instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"or%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval); + } + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval % 8); + } + return \"bset %1,%0\"; + } + return \"or%.l %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "or%.w %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "or%.b %2,%0") + +;; xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=do,m") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "di,dKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))) + { + if (! DATA_REG_P (operands[0])) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"eor%.w %2,%0\"; + } + return \"eor%.l %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=dm") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dn")))] + "" + "eor%.w %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=dm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "dn")))] + "" + "eor%.b %2,%0") + +;; negation instructions + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "neg%.l %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "neg%.w %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg%.b %0") + +(define_expand "negsf2" + [(set (match_operand:SF 0 "general_operand" "") + (neg:SF (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (neg:SF (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpneg%.s %w1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (neg:SF (match_operand:SF 1 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fneg%.x %1,%0\"; + return \"fneg%.s %f1,%0\"; +}") + +(define_expand "negdf2" + [(set (match_operand:DF 0 "general_operand" "") + (neg:DF (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (neg:DF (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpneg%.d %y1, %0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fneg%.x %1,%0\"; + return \"fneg%.d %f1,%0\"; +}") + +;; Absolute value instructions + +(define_expand "abssf2" + [(set (match_operand:SF 0 "general_operand" "") + (abs:SF (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (abs:SF (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpabs%.s %y1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (abs:SF (match_operand:SF 1 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fabs%.x %1,%0\"; + return \"fabs%.s %f1,%0\"; +}") + +(define_expand "absdf2" + [(set (match_operand:DF 0 "general_operand" "") + (abs:DF (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (abs:DF (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpabs%.d %y1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fabs%.x %1,%0\"; + return \"fabs%.d %f1,%0\"; +}") + +;; one complement instructions + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "not%.l %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "not%.w %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not%.b %0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (TARGET_68020) + return \"move%.b %1,%0\;extb%.l %0\"; + return \"move%.b %1,%0\;ext%.w %0\;ext%.l %0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;move%.b %1,%0\"; +}") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && (INTVAL (operands[0]) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.b %1,%0\"; +#else + return \"cmp%.b %0,%1\"; +#endif +") + +(define_insn "" + [(set (cc0) (compare (lshiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & ~0xff) == 0)" + "* +#ifdef HPUX_ASM + return \"cmp%.b %0,%1\"; +#else + return \"cmp%.b %1,%0\"; +#endif +") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && ((INTVAL (operands[0]) + 0x80) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.b %1,%0\"; +#else + return \"cmp%.b %0,%1\"; +#endif +") + +(define_insn "" + [(set (cc0) (compare (ashiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && ((INTVAL (operands[1]) + 0x80) & ~0xff) == 0)" + "* +#ifdef HPUX_ASM + return \"cmp%.b %0,%1\"; +#else + return \"cmp%.b %1,%0\"; +#endif +") + +;; arithmetic shift instructions +;; We don't need the shift memory by 1 bit instruction + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asl%.l %2,%0") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asl%.w %2,%0") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asl%.b %2,%0") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asr%.l %2,%0") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asr%.w %2,%0") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asr%.b %2,%0") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsl%.l %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsl%.w %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsl%.b %2,%0") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsr%.l %2,%0") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsr%.w %2,%0") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsr%.b %2,%0") + +;; rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "rol%.l %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "rol%.w %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "rol%.b %2,%0") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "ror%.l %2,%0") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "ror%.w %2,%0") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "ror%.b %2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+do") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"bfins %3,%0{%b2:%b1}\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"move%.b %3,%0\"; + return \"move%.w %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfextu %1{%b3:%b2},%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + output_asm_insn (\"clr%.l %0\", operands); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"move%.b %1,%0\"; + return \"move%.w %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfexts %1{%b3:%b2},%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"move%.b %1,%0\;extb%.l %0\"; + return \"move%.w %1,%0\;ext%.l %0\"; +}") + +;; Bit field instructions, general cases. +;; "o,d" constraint causes a nonoffsettable memref to match the "o" +;; so that its address is reloaded. + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts %1{%b3:%b2},%0") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + return \"bfextu %1{%b3:%b2},%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) + (match_operand 3 "immediate_operand" "i,i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[3]) == -1 + || (GET_CODE (operands[1]) == CONST_INT + && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" + "* +{ + CC_STATUS_INIT; + return \"bfchg %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset %0{%b2:%b1}\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (match_operand:SI 3 "general_operand" "d,d"))] + "TARGET_68020 && TARGET_BITFIELD" + "bfins %3,%0{%b2:%b1}") + +;; Now recognize bit field insns that operate on registers +;; (or at least were intended to do so). + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts %1{%b3:%b2},%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + return \"bfextu %1{%b3:%b2},%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ +#if 0 + /* These special cases are now recognized by a specific pattern. */ + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 16 && INTVAL (operands[2]) == 16) + return \"move%.w %3,%0\"; + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8) + return \"move%.b %3,%0\"; +#endif + return \"bfins %3,%0{%b2:%b1}\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +;;; now handle the register cases +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "seq" + [(set (match_operand:QI 0 "general_operand" "=d") + (eq (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\"); +") + +(define_insn "sne" + [(set (match_operand:QI 0 "general_operand" "=d") + (ne (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sne %0\", \"fsne %0\", \"sne %0\"); +") + +(define_insn "sgt" + [(set (match_operand:QI 0 "general_operand" "=d") + (gt (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", 0); +") + +(define_insn "sgtu" + [(set (match_operand:QI 0 "general_operand" "=d") + (gtu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"shi %0\"; ") + +(define_insn "slt" + [(set (match_operand:QI 0 "general_operand" "=d") + (lt (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ") + +(define_insn "sltu" + [(set (match_operand:QI 0 "general_operand" "=d") + (ltu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scs %0\"; ") + +(define_insn "sge" + [(set (match_operand:QI 0 "general_operand" "=d") + (ge (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ") + +(define_insn "sgeu" + [(set (match_operand:QI 0 "general_operand" "=d") + (geu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scc %0\"; ") + +(define_insn "sle" + [(set (match_operand:QI 0 "general_operand" "=d") + (le (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sle %0\", \"fsle %0\", 0); +") + +(define_insn "sleu" + [(set (match_operand:QI 0 "general_operand" "=d") + (leu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"sls %0\"; ") + +;; Basic conditional jump instructions. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbeq %l0\", \"fbeq %l0\", \"jbeq %l0\"); +#else + OUTPUT_JUMP (\"jeq %l0\", \"fjeq %l0\", \"jeq %l0\"); +#endif +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbne %l0\", \"fbne %l0\", \"jbne %l0\"); +#else + OUTPUT_JUMP (\"jne %l0\", \"fjne %l0\", \"jne %l0\"); +#endif +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbgt %l0\", \"fbgt %l0\", 0); +#else + OUTPUT_JUMP (\"jgt %l0\", \"fjgt %l0\", 0); +#endif +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbhi %l0\"; +#else + return \"jhi %l0\"; +#endif +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jblt %l0\", \"fblt %l0\", \"jbmi %l0\"); +#else + OUTPUT_JUMP (\"jlt %l0\", \"fjlt %l0\", \"jmi %l0\"); +#endif +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbcs %l0\"; +#else + return \"jcs %l0\"; +#endif +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbge %l0\", \"fbge %l0\", \"jbpl %l0\"); +#else + OUTPUT_JUMP (\"jge %l0\", \"fjge %l0\", \"jpl %l0\"); +#endif +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbcc %l0\"; +#else + return \"jcc %l0\"; +#endif +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jble %l0\", \"fble %l0\", 0); +#else + OUTPUT_JUMP (\"jle %l0\", \"fjle %l0\", 0); +#endif +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbls %l0\"; +#else + return \"jls %l0\"; +#endif +") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbne %l0\", \"fbne %l0\", \"jbne %l0\"); +#else + OUTPUT_JUMP (\"jne %l0\", \"fjne %l0\", \"jne %l0\"); +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbeq %l0\", \"fbeq %l0\", \"jbeq %l0\"); +#else + OUTPUT_JUMP (\"jeq %l0\", \"fjeq %l0\", \"jeq %l0\"); +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jble %l0\", \"fbngt %l0\", 0); +#else + OUTPUT_JUMP (\"jle %l0\", \"fjngt %l0\", 0); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbls %l0\"; +#else + return \"jls %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbge %l0\", \"fbnlt %l0\", \"jbpl %l0\"); +#else + OUTPUT_JUMP (\"jge %l0\", \"fjnlt %l0\", \"jpl %l0\"); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbcc %l0\"; +#else + return \"jcc %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jblt %l0\", \"fbnge %l0\", \"jbmi %l0\"); +#else + OUTPUT_JUMP (\"jlt %l0\", \"fjnge %l0\", \"jmi %l0\"); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbcs %l0\"; +#else + return \"jcs %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbgt %l0\", \"fbnle %l0\", 0); +#else + OUTPUT_JUMP (\"jgt %l0\", \"fjnle %l0\", 0); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbhi %l0\"; +#else + return \"jhi %l0\"; +#endif +") + +;; Subroutines of "casesi". + +(define_expand "casesi_1" + [(set (match_operand:SI 3 "general_operand" "") + (plus:SI (match_operand:SI 0 "general_operand" "") + ;; Note operand 1 has been negated! + (match_operand:SI 1 "immediate_operand" ""))) + (set (cc0) (compare (match_operand:SI 2 "general_operand" "") + (match_dup 3))) + (set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 4 "" "")) (pc)))] + "" + "") + +(define_expand "casesi_2" + [(set (match_operand:SI 0 "" "") (mem:HI (match_operand:SI 1 "" ""))) + ;; The USE here is so that at least one jump-insn will refer to the label, + ;; to keep it alive in jump_optimize. + (parallel [(set (pc) + (plus:SI (pc) (match_dup 0))) + (use (label_ref (match_operand 2 "" "")))])] + "" + "") + +;; Operand 0 is index (in bytes); operand 1 is minimum, operand 2 themaximum; +;; operand 3 is CODE_LABEL for the table; +;; operand 4 is the CODE_LABEL to go to if index out of range. +(define_expand "casesi" + ;; We don't use these for generating the RTL, but we must describe + ;; the operands here. + [(match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "general_operand" "") + (match_operand 3 "" "") + (match_operand 4 "" "")] + "" + " +{ + rtx table_elt_addr; + rtx index_diff; + + operands[1] = negate_rtx (SImode, operands[1]); + index_diff = gen_reg_rtx (SImode); + /* Emit the first few insns. */ + emit_insn (gen_casesi_1 (operands[0], operands[1], operands[2], + index_diff, operands[4])); + /* Construct a memory address. This may emit some insns. */ + table_elt_addr + = memory_address_noforce + (HImode, + gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, index_diff, + gen_rtx (CONST_INT, VOIDmode, 2)), + gen_rtx (LABEL_REF, VOIDmode, operands[3]))); + /* Emit the last few insns. */ + emit_insn (gen_casesi_2 (gen_reg_rtx (HImode), table_elt_addr, operands[3])); + DONE; +}") + +;; Recognize one of the insns resulting from casesi_2. +(define_insn "" + [(set (pc) + (plus:SI (pc) (match_operand:HI 0 "general_operand" "r"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ +#ifdef ASM_RETURN_CASE_JUMP + ASM_RETURN_CASE_JUMP; +#else +#ifdef SGS +#ifdef ASM_OUTPUT_CASE_LABEL + return \"jmp 6(%%pc,%0.w)\"; +#else + return \"jmp 2(%%pc,%0.w)\"; +#endif +#else /* not SGS */ +#ifdef MOTOROLA + return \"jmp (2,pc,%0.w)\"; +#else + return \"jmp pc@(2,%0:w)\"; +#endif +#endif +#endif /* no ASM_RETURN_CASE_JUMP */ +}") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +#ifdef MOTOROLA + return \"jbra %l0\"; +#else + return \"jra %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:HI (match_operand:HI 0 "general_operand" "=g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + { +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + return \"sub%.w %#1,%0\;jbcc %l1\"; +#else + return \"subq%.w %#1,%0\;jbcc %l1\"; +#endif +#else /* not MOTOROLA */ + return \"subqw %#1,%0\;jcc %l1\"; +#endif + } +#ifdef MOTOROLA +#ifdef HPUX_ASM +#ifndef NO_ADDSUB_Q + return \"sub%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; +#else + return \"subq%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; +#endif +#else /* not HPUX_ASM */ + return \"subq%.w %#1,%0\;cmp%.w %#-1,%0\;jbne %l1\"; +#endif +#else /* not MOTOROLA */ + return \"subqw %#1,%0\;cmpw %#-1,%0\;jne %l1\"; +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:SI (match_operand:SI 0 "general_operand" "=g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifndef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;sub.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub.l %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;subq.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq.l %#1,%0\;jbcc %l1\"; +#endif /* not NO_ADDSUB_Q */ +#ifdef HPUX_ASM +#ifndef NO_ADDSUB_Q + return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#else + return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#endif +#else + return \"subq.l %#1,%0\;cmp.l %#-1,%0\;jbne %l1\"; +#endif +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subql %#1,%0\;jcc %l1\"; + return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; +#endif +}") + +;; dbra patterns that use REG_NOTES info generated by strength_reduce. + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "=g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifndef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;sub.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub.l %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;subq.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq.l %#1,%0\;jbcc %l1\"; +#endif +#ifdef HPUX_ASM +#ifndef NO_ADDSUB_Q + return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#else + return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#endif +#else + return \"subq.l %#1,%0\;cmp.l %#-1,%0\;jbne %l1\"; +#endif +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subql %#1,%0\;jcc %l1\"; + return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; +#endif +}") + +;; Call subroutine with no return value. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "o") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not really used on the m68000. + + "" + "* +#ifdef MOTOROLA + return \"jsr %0\"; +#else + return \"jbsr %0\"; +#endif +") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "general_operand" "o") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not really used on the m68000. + "" + "* +#ifdef MOTOROLA + return \"jsr %1\"; +#else + return \"jbsr %1\"; +#endif +") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This should not be used unless the add/sub insns can't be. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (match_operand:QI 1 "address_operand" "p"))] + "" + "lea %a1,%0") + +;; This is the first machine-dependent peephole optimization. +;; It is useful when a floating value is returned from a function call +;; and then is moved into an FP register. +;; But it is mainly intended to test the support for these optimizations. + +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) + (set (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "ad"))] + "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" + "* +{ + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%@\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; +} +") + +;; FPA multiply and add. +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (plus:DF (mult:DF (match_operand:DF 1 "general_operand" "%x,dmF,y") + (match_operand:DF 2 "general_operand" "xH,y,y")) + (match_operand:DF 3 "general_operand" "xH,y,dmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.d %1,%w2,%w3,%0\"; + return \"fpma%.d %x1,%x2,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (plus:DF (match_operand:DF 1 "general_operand" "xH,y,dmF") + (mult:DF (match_operand:DF 2 "general_operand" "%x,dmF,y") + (match_operand:DF 3 "general_operand" "xH,y,y"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.d %2,%w3,%w1,%0\"; + return \"fpma%.d %x2,%x3,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (plus:SF (mult:SF (match_operand:SF 1 "general_operand" "%x,ydmF,y") + (match_operand:SF 2 "general_operand" "xH,y,ydmF")) + (match_operand:SF 3 "general_operand" "xH,ydmF,ydmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.s %1,%w2,%w3,%0\"; + return \"fpma%.s %1,%2,%3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (plus:SF (match_operand:SF 1 "general_operand" "xH,ydmF,ydmF") + (mult:SF (match_operand:SF 2 "general_operand" "%x,ydmF,y") + (match_operand:SF 3 "general_operand" "xH,y,ydmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.s %2,%w3,%w1,%0\"; + return \"fpma%.s %2,%3,%1,%0\"; +}") + +;; FPA Multiply and subtract +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (minus:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (mult:DF (match_operand:DF 2 "register_operand" "%xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpms%.d %3,%w2,%w1,%0\"; + return \"fpms%.d %x3,%2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (minus:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (mult:SF (match_operand:SF 2 "register_operand" "%xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpms%.s %3,%w2,%w1,%0\"; + return \"fpms%.s %3,%2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "%xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpmr%.d %2,%w1,%w3,%0\"; + return \"fpmr%.d %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "%xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpmr%.s %2,%w1,%w3,%0\"; + return \"fpmr%.s %x2,%1,%x3,%0\"; +}") + +;; FPA Add and multiply +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (plus:DF (match_operand:DF 1 "register_operand" "%xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.d %2,%w1,%w3,%0\"; + return \"fpam%.d %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (plus:DF (match_operand:DF 2 "register_operand" "%xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.d %3,%w2,%w1,%0\"; + return \"fpam%.d %x3,%2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (plus:SF (match_operand:SF 1 "register_operand" "%xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.s %2,%w1,%w3,%0\"; + return \"fpam%.s %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (plus:SF (match_operand:SF 2 "register_operand" "%xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.s %3,%w2,%w1,%0\"; + return \"fpam%.s %x3,%2,%x1,%0\"; +}") + +;;FPA Subtract and multiply +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (minus:DF (match_operand:DF 1 "register_operand" "xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.d %2,%w1,%w3,%0\"; + return \"fpsm%.d %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (minus:DF (match_operand:DF 2 "register_operand" "xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.d %3,%w2,%w1,%0\"; + return \"fpsm%.d %x3,%2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (minus:SF (match_operand:SF 1 "register_operand" "xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.s %2,%w1,%w3,%0\"; + return \"fpsm%.s %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (minus:SF (match_operand:SF 2 "register_operand" "xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.s %3,%w2,%w1,%0\"; + return \"fpsm%.s %x3,%2,%x1,%0\"; +}") + + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- comment-start-skip: ";+- *" +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/m88k.md b/gcc-1.40/config/m88k.md new file mode 100644 index 0000000..366ac90 --- /dev/null +++ b/gcc-1.40/config/m88k.md @@ -0,0 +1,2273 @@ +;;- Machine description for the Motorola 88000 for GNU C compiler +;; Copyright (C) 1988 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@mcc.com) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +;; Compare instructions. +;; This pattern is used for generating an "insn" +;; which does just a compare and sets a (fictitious) condition code. + +;; The actual the m88000 insns are compare-and-conditional-jump. +;; The define_peephole's below recognize the combinations of +;; compares and jumps, and output each pair as a single assembler insn. + +;; This controls RTL generation and register allocation. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "arith_operand" "rI") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[0]) == CONST_INT) + { + cc_status.flags |= CC_REVERSED; + return \"cmp r25,%1,%0\"; + } + return \"cmp r25,%0,%1\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "nonmemory_operand" "rG") + (match_operand:DF 1 "nonmemory_operand" "rG")))] + "" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE) + { + cc_status.flags |= CC_REVERSED | CC_IN_FCCR; + return \"fcmp.sdd r25,%1,%0\"; + } + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sdd r25,%0,%1\"; +}") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "rG") + (match_operand:SF 1 "nonmemory_operand" "rG")))] + "" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE) + { + cc_status.flags |= CC_REVERSED | CC_IN_FCCR; + return \"fcmp.sss r25,%1,%0\"; + } + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sss r25,%0,%1\"; +}") +;; We have to have this because cse can optimize the previous pattern +;; into this one. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "cmp r25,%0,0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "r"))] + "" + "* +{ + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sds r25,%0,r0\"; +}") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "r"))] + "" + "* +{ + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sss r25,%0,r0\"; +}") + +;; These control RTL generation for conditional jump insns +;; and match them for register allocation. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 eq,r25,%l0") + +(define_peephole + [(set (cc0) + (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd eq0,%0,%l1\"; +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 ne,r25,%l0") + +(define_peephole + [(set (cc0) + (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd ne0,%0,%l1\"; +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 gt,r25,%l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 hi,r25,%l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 lt,r25,%l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 lo,r25,%l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 ge,r25,%l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 hs,r25,%l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 le,r25,%l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 ls,r25,%l0") + +;; These match inverted jump insns for register allocation. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 eq,r25,%l0") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd ne0,%0,%l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 ne,r25,%l0") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd eq0,%0,%l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 gt,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 hi,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 lt,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 lo,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 ge,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 hs,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 le,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 ls,r25,%l0") + +;; Move instructions + +(define_insn "swapsi" + [(set (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (set (match_dup 1) (match_dup 0))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + { + CC_STATUS_INIT; + return \"ld r25,%0\;xmem r25,%1\;st r25,%0\"; + } + if (! REG_P (operands[1])) + return \"xmem %0,%1\"; + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + return \"xor %0,%0,%1\;xor %1,%1,%0\;xor %0,%0,%1\"; + } + return \"xmem %1,%0\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "memory_operand" "m")) + (set (match_operand:SI 2 "register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m")) + (set (match_dup 1) (match_dup 2)) + (set (match_dup 3) (match_dup 0))] + "" + "* +{ + CC_STATUS_INIT; + return \"ld r25,%1\;xmem r25,%3\;st r25,%1\"; +}") + +(define_insn "swapqi" + [(set (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")) + (set (match_dup 1) (match_dup 0))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + { + CC_STATUS_INIT; + return \"ld.bu r25,%0\;xmem.bu r25,%1\;st.bu r25,%0\"; + } + if (! REG_P (operands[1])) + return \"xmem.bu %0,%1\"; + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + return \"xor %0,%0,%1\;xor %1,%1,%0\;xor %0,%0,%1\"; + } + return \"xmem.bu %1,%0\"; +}") + +(define_peephole + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "memory_operand" "m")) + (set (match_operand:QI 2 "register_operand" "=r") + (match_operand:QI 3 "memory_operand" "m")) + (set (match_dup 1) (match_dup 2)) + (set (match_dup 3) (match_dup 0))] + "" + "* +{ + CC_STATUS_INIT; + return \"ld.bu r25,%1\;xmem.bu r25,%3\;st.bu r25,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "g") + (const_int 0))] + "" + "* +{ + if (REG_P (operands[0])) + return \"or %0,r0,0\"; + return \"st r0,%0\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g,r") + (match_operand:SI 1 "general_operand" "r,mi"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld %0,%1\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + if (GET_CODE (operands[1]) == LABEL_REF + || GET_CODE (operands[1]) == SYMBOL_REF) + return \"lda %0,r0,%1\"; + return \"or %0,r0,%1\"; + } + return \"st %1,%0\"; +}") + +;; Simulate pre inc. Post inc/dec is automatically optimized +;; by sheer luck. ?? In which phase should this really be done?? +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (match_operand:SI 2 "register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + "st %2,%0,%1\\t;; pipelined!\;addu %0,%0,%1\\t;; /") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "g") + (const_int 0))] + "" + "* +{ + if (REG_P (operands[0])) + return \"or %0,r0,0\"; + return \"st.h r0,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "r,mn"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld.h %0,%1\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (HImode, operands); + return \"or %0,r0,%1\"; + } + return \"st.h %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.h %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (zero_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.hu %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (mem:HI (plus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (match_operand:SI 2 "register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + "st.h %2,%0,%1\\t;; pipelined!\;addu %0,%0,%1\\t;; /") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "g") + (const_int 0))] + "" + "* +{ + if (REG_P (operands[0])) + return \"or %0,r0,0\"; + return \"st.b r0,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g,r") + (match_operand:QI 1 "general_operand" "r,mn"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld.b %0,%1\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (QImode, operands); + return \"or %0,r0,%1\"; + } + return \"st.b %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (sign_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.b %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (zero_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.bu %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (mem:QI (plus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (match_operand:SI 2 "register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + "st.b %2,%0,%1\\t;; pipelined!\;addu %0,%0,%1\\t;; /") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_insn "movstrsi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:SI 2 "arith32_operand" "rn")) + (clobber (reg:SI 10)) + (clobber (reg:SI 11)) + (clobber (reg:SI 12))] + "" + "* output_block_move (operands);") + +;; This pattern forces (set (reg:DF ...) (const_double ...)) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general movdf pattern. +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=r,o") + (match_operand:DF 1 "" "mG,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"add %0,r0,0\;add %1,r0,0\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st r0,%0\;st r0,%1\"; + } + return output_move_double (operands); +} +") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r,m") + (match_operand:DF 1 "general_operand" "rm,r"))] + "" + "* return output_move_double (operands);") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r,m") + (match_operand:DI 1 "general_operand" "rm,r"))] + "" + "* return output_move_double (operands);") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g,r") + (match_operand:SF 1 "general_operand" "r,mF"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld %0,%1\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_store_const_float (SFmode, operands); + return \"or %0,r0,%1\"; + } + return \"st %1,%0\"; +}") + +;;- load effective address +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "lda.b %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:HI 1 "address_operand" "p"))] + "" + "lda.w %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "address_operand" "p"))] + "" + "lda %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:DI 1 "address_operand" "p"))] + "" + "lda.d %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SF 1 "address_operand" "p"))] + "" + "lda %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:DF 1 "address_operand" "p"))] + "" + "lda.d %0,%a1") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st.b %1,%0\"; + return \"or %0,r0,%1\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st.b %1,%0\"; + return \"or %0,r0,%1\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st.h %1,%0\"; + return \"or %0,r0,%1\"; +}") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"mask %0,%1,0xffff\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.hu %0,%1\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"mask %0,%1,0xff\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.bu %0,%1\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"mask %0,%1,0xff\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.bu %0,%1\"; +}") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"ext %0,%1,16<0>\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.h %0,%1\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"ext %0,%1,8<0>\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.b %0,%1\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"ext %0,%1,8<0>\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.b %0,%1\"; +}") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=r") + (float_extend:DF + (match_operand:SF 1 "general_operand" "r")))] + "" + "fadd.dss %0,r0,%1") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=r") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "r")))] + "" + "fadd.ssd %0,r0,%1") +;; Conversions between floating point and integer + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=r") + (float:DF (match_operand:SI 1 "general_operand" "r")))] + "" + "flt.ds %0,%1") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=r") + (float:SF (match_operand:SI 1 "general_operand" "r")))] + "" + "flt.ss %0,%1") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "r"))))] + "" + "int.sd %0,%1") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "r"))))] + "" + "int.ss %0,%1") + +;;- arithmetic instructions +;;- add instructions +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"addu %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"addu %0,%1,%2\"; + if (INT_FITS_16_BITS (-i)) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, -i); + return \"subu %0,%1,%2\"; + } + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;addu %0,%1,%0\"; +}") + +(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.ddd %0,%1,%2") + +;; a bunch more can go in here! + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fadd.sss %0,%1,%2") + +;;- subtract instructions +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"subu %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"subu %0,%1,%2\"; + if (INT_FITS_16_BITS (-i)) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, -i); + return \"addu %0,%1,%2\"; + } + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;subu %0,%1,%0\"; +}") + +(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.ddd %0,%1,%2") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fsub.sss %0,%1,%2") + +;;- multiply instructions +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"mul %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"mul %0,%1,%2\"; + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;mul %0,%1,%0\"; +}") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "mul %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.ddd %0,%1,%2") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fmul.sss %0,%1,%2") + +;;- divide instructions +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"div %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"div %0,%1,%2\"; + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;div %0,%1,%0\"; +}") + + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "div %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.ddd %0,%1,%2") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fdiv.sss %0,%1,%2") + +;; Remainder instructions. + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + if (INT_FITS_16_BITS (-i)) + fatal (\"implement negative case for mod\"); + fatal (\"implement 32 bit case for mod\"); +}") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + if (INT_FITS_16_BITS (-i)) + fatal (\"implement negative case for umod\"); + fatal (\"implement 32 bit case for umod\"); +}") + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (match_operand:SI 3 "register_operand" "=r") + (mod:SI (match_dup 1) (match_dup 2)))] + "" + "div %0,%1,%2\;mul %3,%0,%2\;sub %3,%1,%3") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (match_operand:SI 3 "register_operand" "=r") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "div %0,%1,%2\;mul %3,%0,%2\;sub %3,%1,%3") + +;;- and instructions (with complement also) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"and %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"mask %0,%1,%2\"; + if (INT_FITS_16_BITS (-i)) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, i & 0xffff); + return \"and %0,%1,%2\"; + } + return \"and.u %0,%1,hi16(%2)\;and %0,%1,lo16(%2)\"; +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "%r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "and.c %0,%1,%2") + +;;- Bit set (inclusive or) instructions (with complement also) +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"or %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"or %0,%1,%2\"; + return \"or.u %0,%1,hi16(%2)\;or %0,%1,lo16(%2)\"; +}") + +(define_insn "iorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "%r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "or.c %0,%1,%2") + +;;- xor instructions (with complement also) +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"xor %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"xor %0,%1,%2\"; + if ((i & 0xffff) == 0) + return \"xor.u %0,%1,hi16(%2)\"; + return \"xor.u %0,%1,hi16(%2)\;xor %0,%1,lo16(%2)\"; +}") + +(define_insn "xorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "register_operand" "%r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "xor.c %0,%1,%2") + +;;- one complement instructions +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "xor.c %0,%1,r0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "ld.b %0,%1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "ld.bu %0,%1") + +;;- arithmetic shift instructions +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"mak %0,%1,0<%2>\"; + return \"mask %0,%2,0x1f\;mak %0,%1,%0\"; +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"ext %0,%1,0<%2>\"; + return \"mask %0,%2,0x1f\;ext %0,%1,%0\"; +}") + +;;- logical shift instructions +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"extu %0,%1,0<%2>\"; + return \"mask %0,%2,0x1f\;extu %0,%1,%0\"; +}") + +;;- rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, SImode, 32 - INTVAL (operands[2])); + return \"rot %0,%1,%2\"; + } + return \"or %0,r0,32\;sub %0,%2,%0\;rot %0,%1,%0\"; +}") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "rot %0,%1,%2") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+ro") + (match_operand:SI 1 "int5_operand" "K") + (match_operand:SI 2 "int5_operand" "K")) + (match_operand:SI 3 "register_operand" "r"))] + "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"mak %0,%3,%1<%2>\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"st.b %3,%0\"; + return \"st.w %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=&r") + (zero_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "int5_operand" "K") + (match_operand:SI 3 "int5_operand" "K")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"extu %0,%1,%2<%3>\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"ld.bu %0,%1\"; + return \"ld.hu %0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "int5_operand" "K") + (match_operand:SI 3 "int5_operand" "K")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"extu %0,%1,%2<%3>\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"ld.b %0,%1\"; + return \"ld.h %0,%1\"; +}") + +;; Bit field instructions. + +(define_insn "extv" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extract:SI (match_operand:QI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,rK") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"ext %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;ext %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extract:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,rK") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"ext %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;ext %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "extzv" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extract:SI (match_operand:QI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,Kr") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"extu %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;extu %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,Kr") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"extu %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;extu %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "arith_operand" "K,K,&r") + (match_operand:SI 2 "arith_operand" "K,&r,&")) + (const_int 0))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"clr %0,%0,%1<%2>\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) & 0x1f) << 5); + return \"mask %2,%2,0x1f\;or %2,%2,%1\;clr %0,%0,%2\"; + } + return \"mak %1,%1,5<5>\;mask %2,%2,0x1f\;or %2,%2,%1\;clr %0,%0,%2\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "arith_operand" "K,K,&r") + (match_operand:SI 2 "arith_operand" "K,&r,&r")) + (const_int -1))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"set %0,%0,%1<%2>\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) & 0x1f) << 5); + return \"mask %2,%2,0x1f\;or %2,%2,%1\;set %0,%0,%2\"; + } + return \"mak %1,%1,5<5>\;mask %2,%2,0x1f\;or %2,%2,%1\;set %0,%0,%2\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "arith_operand" "K,K,&r") + (match_operand:SI 2 "arith_operand" "K,&r,&r")) + (match_operand:SI 3 "register_operand" "&r,&r,r"))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"mak %3,%3,%1<%2>\;clr %0,%0,%1<%2>\;or %0,%0,%3\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) & 0x1f) << 5); + return \"mask %2,%2,0x1f\;or %2,%2,%1\;mak %3,%3,%2\;clr %0,%0,%2\;or %0,%0,%3\"; + } + return \"mak %1,%1,5<5>\;mask %2,%2,0x1f\;or %2,%2,%1\;mak %1,%3,%2\;clr %0,%0,%2\;or %0,%0,%1\"; +}") + +;; negate insns +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "sub %0,r0,%1") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "fsub.dsd %0,r0,%1") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (neg:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "fsub.sss %0,r0,%1") + +;; Store condition code values into registers +(define_insn "seq" + [(set (match_operand:SI 0 "general_operand" "=g") + (eq (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<eq>\"; + return \"extu r25,r25,1<eq>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (eq (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<eq>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<eq>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (eq (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<eq>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<eq>\;st r25,%2\"; +}") + +(define_insn "sne" + [(set (match_operand:SI 0 "general_operand" "=g") + (ne (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<ne>\"; + return \"extu r25,r25,1<ne>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (ne (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<ne>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<ne>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (ne (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<ne>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<ne>\;st r25,%2\"; +}") + +(define_insn "sgt" + [(set (match_operand:SI 0 "general_operand" "=g") + (gt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<gt>\"; + return \"extu r25,r25,1<gt>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (gt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<gt>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<gt>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (gt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<gt>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<gt>\;st r25,%2\"; +}") + +(define_insn "sgtu" + [(set (match_operand:SI 0 "general_operand" "=g") + (gtu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<hi>\"; + return \"extu r25,r25,1<hi>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (gtu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<hi>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<hi>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (gtu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<hi>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<hi>\;st r25,%2\"; +}") + +(define_insn "slt" + [(set (match_operand:SI 0 "general_operand" "=g") + (lt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<lt>\"; + return \"extu r25,r25,1<lt>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (lt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<lt>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<lt>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (lt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<lt>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<lt>\;st r25,%2\"; +}") + +(define_insn "sltu" + [(set (match_operand:SI 0 "general_operand" "=g") + (ltu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<lo>\"; + return \"extu r25,r25,1<lo>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (ltu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<lo>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<lo>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (ltu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<lo>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<lo>\;st r25,%2\"; +}") + +(define_insn "sge" + [(set (match_operand:SI 0 "general_operand" "=g") + (ge (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<ge>\"; + return \"extu r25,r25,1<ge>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (ge (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<ge>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<ge>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (ge (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<ge>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<ge>\;st r25,%2\"; +}") + +(define_insn "sgeu" + [(set (match_operand:SI 0 "general_operand" "=g") + (geu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<hs>\"; + return \"extu r25,r25,1<hs>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (geu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<hs>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<hs>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (geu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<hs>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<hs>\;st r25,%2\"; +}") + +(define_insn "sle" + [(set (match_operand:SI 0 "general_operand" "=g") + (le (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<le>\"; + return \"extu r25,r25,1<le>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (le (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<le>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<le>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (le (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<le>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<le>\;st r25,%2\"; +}") + +(define_insn "sleu" + [(set (match_operand:SI 0 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1<ls>\"; + return \"extu r25,r25,1<ls>\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1<ls>\"; + return \"cmp r25,%0,0\;extu r25,r25,1<ls>\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1<ls>\"; + return \"cmp r25,%0,%1\;extu r25,r25,1<ls>\;st r25,%2\"; +}") + + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "" + [(set (pc) + (label_ref (match_operand 0 "" ""))) + (clobber (const_int 1))] + "" + "br.n %l0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %0") + +;;- jump to subroutine +(define_insn "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "general_operand" "g")) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + operands[0] = XEXP (operands[0], 0); + if (REG_P (operands[0])) + return \"jsr %0\"; + return \"bsr %0\"; +}") + +(define_insn "" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "general_operand" "g")) + (clobber (const_int 1)) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + operands[0] = XEXP (operands[0], 0); + if (REG_P (operands[0])) + return \"jsr.n %0\"; + return \"bsr.n %0\"; +}") + +;;- jump to subroutine +(define_insn "call_value" + [(set (match_operand 0 "" "=r") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "general_operand" "g"))) + (use (reg:SI 1))] + ;;- Don't use operand 2 for most machines. + "" + "* +{ + operands[1] = XEXP (operands[1], 0); + if (REG_P (operands[1])) + return \"jsr %1\"; + return \"bsr %1\"; +}") + +(define_insn "" + [(set (match_operand 0 "" "=r") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "general_operand" "g"))) + (use (reg:SI 1)) + (clobber (const_int 2))] + ;;- Don't use operand 2 for most machines. + "" + "* +{ + operands[1] = XEXP (operands[1], 0); + if (REG_P (operands[1])) + return \"jsr.n %1\"; + return \"bsr.n %1\"; +}") + +;; A memory ref with constant address is not normally valid. +;; But it is valid in a call insns. This pattern allows the +;; loading of the address to combine with the call. +(define_insn "" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "general_operand" "g")) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[0]) == SYMBOL_REF" + "bsr %0") + +(define_insn "" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (const_int 1)) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[0]) == SYMBOL_REF" + "bsr.n %0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb1 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb0 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb0 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb1 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb1 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb1 0,%0,%l1") + +;; These four entries allow a jlbc or jlbs,to be made +;; by combination with a bic. +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb1 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb1 0,%0,%l1") +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/mips.md b/gcc-1.40/config/mips.md new file mode 100644 index 0000000..82b4a50 --- /dev/null +++ b/gcc-1.40/config/mips.md @@ -0,0 +1,1957 @@ +;; Mips.md Naive version of Machine Description for MIPS +;; Contributed by A. Lichnewsky, lich@inria.inria.fr +;; Changes by Michael Meissner, meissner@osf.org +;; Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;;------------------------------------------------------------------------ +;; + +;; +;; .................... +;; +;; Peephole Optimizations for +;; +;; ARITHMETIC +;; +;; .................... +;; + ;;- The following peepholes are + ;;- motivated by the fact that + ;;- stack movement result in some + ;;- cases in embarrassing sequences + ;;- of addiu SP,SP,int + ;;- addiu SP,SP,other_int + + ;;- -------------------- + ;;- REMARK: this would be done better + ;;- by analysis of dependencies in + ;;- basic blocks, prior to REG ALLOC, + ;;- and simplification of trees: + ;;- (+ (+ REG const) const) + ;;- -> (+ REG newconst) + ;;- -------------------- + ;;- Merged peephole code from + ;;- raeburn@ATHENA.MIT.EDU + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operator 1 "additive_op" + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "small_int" "I")])) + (set (match_operand:SI 4 "register_operand" "=r") + (match_operator 5 "additive_op" + [(match_dup 0) + (match_operand:SI 6 "small_int" "I")]))] + "(REGNO (operands[0]) == REGNO (operands[4]) + || dead_or_set_p (insn, operands[0]))" + "* +{ + int addend; + /* compute sum, with signs */ + addend = INTVAL (operands[3]) * (GET_CODE (operands[1]) == PLUS ? 1 : -1); + addend += INTVAL (operands[6]) * (GET_CODE (operands[5]) == PLUS ? 1 : -1); + if (addend != 0) + { + operands[0] = gen_rtx (CONST_INT, VOIDmode, addend); + return \"addi%:\\t%4,%2,%0\"; + } + /* value is zero; copy */ + if (REGNO (operands[4]) != REGNO (operands[2])) + return \"add%:\\t%4,%2,$0\"; + /* copying to self; punt */ + return \" # null operation: additive operands cancel (%0,%2)\"; +}") + +;; +;; .................... +;; +;; ARITHMETIC +;; +;; .................... +;; + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "add.d\\t%0,%1,%2") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "add.s\\t%0,%1,%2") + +;; The following is generated when omiting the frame pointer +;; and for referencing large auto arrays during optimization. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] == stack_pointer_rtx || operands[1] == frame_pointer_rtx" + "* +{ + int number; + if (GET_CODE (operands[2]) != CONST_INT) + return \"add%:\\t%0,%1,%2\"; + + number = INTVAL (operands[2]); + if (((unsigned) (number + 0x8000) > 0xffff)) + { + operands[3] = gen_rtx (REG, SImode, 1); /* assembler temp. */ + return \".set\\tnoat\\n\\tli\\t%3,%2\\n\\tadd%:\\t%0,%1,%3\\n\\t.set\\tat\"; + } + + return (number < 0) ? \"sub%:\\t%0,%1,%n2\" : \"add%:\\t%0,%1,%2\"; +}") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "arith_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"sub%:\\t%0,%1,%n2\" + : \"add%:\\t%0,%1,%2\"; +}") + + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "sub.d\\t%0,%1,%2") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "sub.s\\t%0,%1,%2") + +;; The following is generated when omiting the frame pointer +;; and for referencing large auto arrays during optimization. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] == stack_pointer_rtx || operands[1] == frame_pointer_rtx" + "* +{ + int number; + if (GET_CODE (operands[2]) != CONST_INT) + return \"sub%:\\t%0,%1,%2\"; + + number = INTVAL (operands[2]); + if (((unsigned) (number + 0x8000) > 0xffff)) + { + operands[3] = gen_rtx (REG, SImode, 1); /* assembler temp. */ + return \".set\\tnoat\\n\\tli\\t%3,%2\\n\\tsub%:\\t%0,%1,%3\\n\\t.set\\tat\"; + } + + return (number < 0) ? \"add%:\\t%0,%1,%n2\" : \"sub%:\\t%0,%1,%2\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"add%:\\t%0,%1,%n2\" + : \"sub%:\\t%0,%1,%2\"; +}") + + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "mul.d\\t%0,%1,%2") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "mul.s\\t%0,%1,%2") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "arith_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "mul\\t%0,%1,%2") + + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "div.d\\t%0,%1,%2") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (div:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "div.s\\t%0,%1,%2") + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (match_operand:SI 3 "register_operand" "=r") + (mod:SI (match_dup 1) + (match_dup 2)))] + "" + "div\\t$0,%1,%2\\n\\tmflo\\t%0\\t\\t#quotient\\n\\tmfhi\\t%3\\t\\t#remainder") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "div\\t%0,%1,%2") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (match_operand:SI 3 "register_operand" "=r") + (umod:SI (match_dup 1) + (match_dup 2)))] + "" + "divu\\t$0,%1,%2\\n\\tmflo\\t%0\\t\\t#quotient\\n\\tmfhi\\t%3\\t\\t#remainder") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "divu\\t%0,%1,%2") + + +;; Remainder instructions + + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "rem\\t%0,%1,%2") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "remu\\t%0,%1,%2") + + +;; Absoluate value instructions -- Don't use the integer abs, +;; since that signals an exception on -2147483648 (sigh). + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "abs.s\\t%0,%1") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "abs.d\\t%0,%1") + +;; +;; .................... +;; +;; LOGICAL +;; +;; .................... +;; + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=&r") + (and:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "" + "and\\t%0,%1,%2\;and\\t%D0,%D1,%D2") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "uns_arith_operand" "%r") + (match_operand:SI 2 "uns_arith_operand" "rK")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT) + ? \"andi\\t%0,%1,%x2\" + : \"and\\t%0,%1,%2\"; +}") + + +;; Simple hack to recognize the "nor" instruction on the MIPS +;; [rms: I don't think the following is actually required.] +;; This must appear before the normal or patterns, so that the +;; combiner will correctly fold things. + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=r") + (not:DI (ior:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r"))))] + "" + "nor\\t%0,%1,%2\;nor\\t%D0,%D1,%D2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (ior:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))))] + "" + "nor\\t%0,%1,%2") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=&r") + (ior:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "" + "or\\t%0,%1,%2\;or\\t%D0,%D1,%D2") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "uns_arith_operand" "%r") + (match_operand:SI 2 "uns_arith_operand" "rJ")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT) + ? \"ori\\t%0,%1,%x2\" + : \"or\\t%0,%1,%2\"; +}") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=&r") + (xor:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "" + "xor\\t%0,%1,%2\;xor\\t%D0,%D1,%D2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "uns_arith_operand" "%r") + (match_operand:SI 2 "uns_arith_operand" "rK")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT) + ? \"xori\\t%0,%1,%x2\" + : \"xor\\t%0,%1,%2\"; +}") + +;; +;; .................... +;; +;; TRUNCATION +;; +;; .................... + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "register_operand" "r")))] + "" + "andi\\t%0,%1,0xff\\t#truncsiqi2\\t %1 -> %0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "register_operand" "r")))] + "" + "* + output_asm_insn (\"sll\\t%0,%1,0x10\\t#truncsihi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x10\\t#truncsihi2\\t %1 -> %0\"; +") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:HI 1 "register_operand" "r")))] + "" + "andi\\t%0,%1,0xff\\t#trunchiqi2\\t %1 -> %0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] + "" + "cvt.s.d\\t%0,%1\\t#truncdfsf2\\t %1 -> %0") + +;; +;; .................... +;; +;; ZERO EXTENSION +;; +;; .................... + +;; Extension insns. +;; Those for integer source operand +;; are ordered widest source type first. + + + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + output_asm_insn (\"sll\\t%0,%1,0x10\\t#zero_extendhisi2\\t %1 -> %0\", + operands); + return \"srl\\t%0,%0,0x10\\t#zero_extendhisi2\\t %1 -> %0\"; + } + else + return \"lhu\\t%0,%1\\t#zero extendhisi2 %1 -> %0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "" + "* + output_asm_insn (\"sll\\t%0,%1,0x18\\t#zero_extendqihi2\\t %1 -> %0\", + operands); + return \"srl\\t%0,%0,0x18\\t#zero_extendqihi2\\t %1 -> %0\"; + ") + + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + return \"andi\\t%0,%1,0xff\\t#zero_extendqisi2\\t %1 -> %0\"; + } + else + return \"lbu\\t%0,%1\\t#zero extendqisi2 %1 -> %0\"; +}") + + +;; +;; .................... +;; +;; SIGN EXTENSION +;; +;; .................... + +;; Extension insns. +;; Those for integer source operand +;; are ordered widest source type first. + + + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + output_asm_insn (\"sll\\t%0,%1,0x10\\t#sign extendhisi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x10\\t#sign extendhisi2\\t %1 -> %0\"; + } + else + return \"lh\\t%0,%1\\t#sign extendhisi2 %1 -> %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "" + "* + output_asm_insn (\"sll\\t%0,%1,0x18\\t#sign extendqihi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x18\\t#sign extendqihi2\\t %1 -> %0\"; + ") + + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:QI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + output_asm_insn (\"sll\\t%0,%1,0x18\\t#sign extendqisi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x18\\t#sign extendqisi2\\t %1 -> %0\"; + } + else + return \"lb\\t%0,%1\\t#sign extendqisi2 %1 -> %0\"; +}") + + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] + "" + "cvt.d.s\\t%0,%1\\t#extendsfdf2\\t %1 -> %0") + + +;; +;; .................... +;; +;; CONVERSIONS +;; +;; .................... + + +(define_insn "fix_truncdfsi2_internal" + [(set (match_operand:DF 0 "register_operand" "=f") + (fix:DF (match_operand:DF 1 "register_operand" "f"))) + (clobber (match_operand:SI 2 "register_operand" "r"))] + "" + "trunc.w.d %0,%1,%2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "" + "mfc1\\t%0,%1") + +(define_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "" + " +{ + rtx reg1 = gen_reg_rtx (DFmode); /* fp reg that gets trunc result */ + rtx reg2 = gen_reg_rtx (SImode); /* gp reg that saves FP status bits */ + emit_insn (gen_fix_truncdfsi2_internal (reg1, operands[1], reg2)); + operands[1] = reg1; + /* Fall through and generate default code */ +}") + +(define_insn "fix_truncsfsi2_internal" + [(set (match_operand:SF 0 "register_operand" "=f") + (fix:SF (match_operand:SF 1 "register_operand" "f"))) + (clobber (match_operand:SI 2 "register_operand" "r"))] + "" + "trunc.w.s %0,%1,%2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "" + "mfc1\\t%0,%1") + +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "" + " +{ + rtx reg1 = gen_reg_rtx (SFmode); /* fp reg that gets trunc result */ + rtx reg2 = gen_reg_rtx (SImode); /* gp reg that saves FP status bits */ + emit_insn (gen_fix_truncsfsi2_internal (reg1, operands[1], reg2)); + operands[1] = reg1; + /* Fall through and generate default code */ +}") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "register_operand" "r")))] + "" + "mtc1\\t%1,%0\\t\\t#floatsidf2\\t%1 -> %0\;cvt.d.w\\t%0,%0") + + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "register_operand" "r")))] + "" + "mtc1\\t%1,%0\\t\\t#floatsisf2\\t%1 -> %0\;cvt.s.w\\t%0,%0") + +(define_expand "fixuns_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "") + (unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))] + "" + " +{ + rtx reg1 = gen_reg_rtx (DFmode); + rtx reg2 = gen_reg_rtx (DFmode); + rtx reg3 = gen_reg_rtx (SImode); + rtx label1 = gen_label_rtx (); + rtx label2 = gen_label_rtx (); + REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31); + + if (reg1) /* turn off complaints about unreached code */ + { + emit_move_insn (reg1, immed_real_const_1 (offset, DFmode)); + do_pending_stack_adjust (); + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, DFmode, operands[1], reg1))); + + emit_jump_insn (gen_bge (label1)); + + emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1])); + emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (LABEL_REF, VOIDmode, label2))); + emit_barrier (); + + emit_label (label1); + emit_move_insn (reg2, gen_rtx (MINUS, DFmode, operands[1], reg1)); + emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000)); + + emit_insn (gen_fix_truncdfsi2 (operands[0], reg2)); + emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); + + emit_label (label2); + + /* allow REG_NOTES to be set on last insn (labels don't have enough + fields, and can't be used for REG_NOTES anyway). */ + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + DONE; + } +}") + +(define_expand "fixuns_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "") + (unsigned_fix:SI (match_operand:SF 1 "register_operand" "")))] + "" + " +{ + rtx reg1 = gen_reg_rtx (SFmode); + rtx reg2 = gen_reg_rtx (SFmode); + rtx reg3 = gen_reg_rtx (SImode); + rtx label1 = gen_label_rtx (); + rtx label2 = gen_label_rtx (); + REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31); + + if (reg1) /* turn off complaints about unreached code */ + { + emit_move_insn (reg1, immed_real_const_1 (offset, SFmode)); + do_pending_stack_adjust (); + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, SFmode, operands[1], reg1))); + + emit_jump_insn (gen_bge (label1)); + + emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1])); + emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (LABEL_REF, VOIDmode, label2))); + emit_barrier (); + + emit_label (label1); + emit_move_insn (reg2, gen_rtx (MINUS, SFmode, operands[1], reg1)); + emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000)); + + emit_insn (gen_fix_truncsfsi2 (operands[0], reg2)); + emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); + + emit_label (label2); + + /* allow REG_NOTES to be set on last insn (labels don't have enough + fields, and can't be used for REG_NOTES anyway). */ + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + DONE; + } +}") + + ;;- Wild things used when + ;;- unions make double and int + ;;- overlap. + ;;- + ;;- This must be supported + ;;- since corresponding code + ;;- gets generated + +(define_insn "" + [(set (subreg:DF (match_operand:DI 0 "register_operand" "=ry") 0) + (match_operand:DF 1 "register_operand" "rf")) + (clobber (match_operand 2 "register_operand" "rf"))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +(define_insn "" + [(set (subreg:DF (match_operand:DI 0 "register_operand" "=ry") 0) + (match_operand:DF 1 "register_operand" "rf"))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=rf") + (subreg:DF (match_operand:DI 1 "register_operand" "ry") 0)) + (clobber (match_operand 2 "register_operand" "rf"))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=rf") + (subreg:DF (match_operand:DI 1 "register_operand" "ry") 0))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +;; +;; .................... +;; +;; MOVES +;; +;; and +;; +;; LOADS AND STORES +;; +;; .................... + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r,*r,*m") + (match_operand:DI 1 "general_operand" "r,*miF,*r"))] + "" + "* +{ + extern rtx adj_offsettable_operand (); + extern int offsettable_address_p (); + + if (which_alternative == 0) + { + /* Move REGISTER <- REGISTER */ + if (REGNO (operands[0]) != (REGNO (operands[1])+1)) + return \"move\\t%0,%1\\n\\tmove\\t%D0,%D1\"; + else + return \"move\\t%D0,%D1\\n\\tmove\\t%0,%1\"; + } + + else if (which_alternative == 1) + { + if (GET_CODE (operands[1]) == MEM) + { + /* REGISTER <- MEMORY */ + if (offsettable_address_p (1, DImode, XEXP (operands[1], 0))) + { + operands[2] = adj_offsettable_operand (operands[1], 4); + return \"lw\\t%0,%1\;lw\\t%D0,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%1\;lw\\t%0,0(%2)\;lw\\t%D0,4(%2)\;set\\tat\"; + } + } + + /* REGISTER <- small integer constant */ + else if (CONSTANT_P (operands[1])) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >= 0 ? 0 : -1); + return \"li\\t%M0,%2\;li\\t%L0,%1\"; + } + + /* Register <- large integer constant */ + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (operands[1])); + operands[3] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (operands[1])); + return \"li\\t%M0,%3\;li\\t%L0,%2\"; + } + } + + else if (which_alternative == 2 && GET_CODE (operands[0]) == MEM) + { + /* Memory <- Register */ + if (offsettable_address_p (1, DImode, XEXP (operands[0], 0))) + { + operands[2] = adj_offsettable_operand (operands[0], 4); + return \"sw\\t%1,%0\;sw\\t%D1,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%0\;sw\\t%1,0(%2)\;sw\\t%D1,4(%2)\;set\\tat\"; + } + } + + abort_with_insn (insn, \"impossible case in movdi\"); + return \"\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,r,m,r,r,m,*r") + (match_operand:SI 1 "general_operand" "r,m,r,i,J,J,*p"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG && code1 == REG) + return \"move\\t%0,%1\"; + + else if (code0 == REG && code1 == MEM) + return \"lw\\t%0,%1\"; + + else if (code0 == MEM && code1 == REG) + return \"sw\\t%1,%0\"; + + else if (code0 == REG && code1 == CONST_INT) + return \"li\\t%0,%1\"; + + else if (code0 == MEM && code1 == CONST_INT && INTVAL (operands[1]) == 0) + return \"sw\\t$0,%0\"; + + else if (code0 == REG && CONSTANT_P (operands[1])) + return \"la\\t%0,%a1\"; + + else if (code0 == REG && code1 == PLUS + && GET_CODE (XEXP (operands[1], 0)) == REG + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT) + { + operands[2] = XEXP (operands[1], 0); + operands[3] = XEXP (operands[1], 1); + return \"add%:\\t%0,%2,%3\"; + } + + abort_with_insn (insn, \"Bad movsi\"); + return 0; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r,r,m,r,r,m") + (match_operand:HI 1 "general_operand" "r,m,r,i,J,J"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG && code1 == REG) + return \"move\\t%0,%1\"; + + else if (code0 == REG && code1 == MEM) + return \"lh\\t%0,%1\"; + + else if (code0 == MEM && code1 == REG) + return \"sh\\t%1,%0\"; + + else if (code0 == REG && code1 == CONST_INT) + return \"li\\t%0,%1\"; + + else if (code0 == MEM && code1 == CONST_INT && INTVAL (operands[1]) == 0) + return \"sh\\t$0,%0\"; + + else if (code0 == REG && CONSTANT_P (operands[1])) + return \"la\\t%0,%a1\"; + + else if (code0 == REG && code1 == PLUS + && GET_CODE (XEXP (operands[1], 0)) == REG + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT) + { + operands[2] = XEXP (operands[1], 0); + operands[3] = XEXP (operands[1], 1); + return \"add%:\\t%0,%2,%3\"; + } + + abort_with_insn (insn, \"Bad movhi\"); + return 0; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r,r,m,r,r,m") + (match_operand:QI 1 "general_operand" "r,m,r,i,J,J"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG && code1 == REG) + return \"move\\t%0,%1\"; + + else if (code0 == REG && code1 == MEM) + return \"lb\\t%0,%1\"; + + else if (code0 == MEM && code1 == REG) + return \"sb\\t%1,%0\"; + + else if (code0 == REG && code1 == CONST_INT) + return \"li\\t%0,%1\"; + + else if (code0 == MEM && code1 == CONST_INT && INTVAL (operands[1]) == 0) + return \"sb\\t$0,%0\"; + + else if (code0 == REG && CONSTANT_P (operands[1])) + return \"la\\t%0,%a1\"; + + else if (code0 == REG && code1 == PLUS + && GET_CODE (XEXP (operands[1], 0)) == REG + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT) + { + operands[2] = XEXP (operands[1], 0); + operands[3] = XEXP (operands[1], 1); + return \"add%:\\t%0,%2,%3\"; + } + + abort_with_insn (insn, \"Bad movqi\"); + return 0; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=f,f,m,fy,*f,*y,*y,*m") + (match_operand:SF 1 "general_operand" "f,m,f,F,*y,*f,*m,*y"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG) + { + if (code1 == REG) + { + if (FP_REG_P (REGNO (operands[0]))) + { + if (FP_REG_P (REGNO (operands[1]))) + return \"mov.s\\t%0,%1\"; + else + return \"mtc1\\t%1,%0\\t\\t# Calling sequence trick\"; + } + + else if (FP_REG_P (REGNO (operands[1]))) + return \"mfc1\\t%0,%1\\t\\t# Calling sequence trick\"; + + else + return \"move\\t%0,%1\"; + } + + else if (code1 == CONST_DOUBLE) + return \"li.s\\t%0,%1\"; + + else if (code1 == MEM) + return (GP_REG_P (REGNO (operands[0]))) ? \"lw\\t%0,%1\" : \"l.s\\t%0,%1\"; + } + + else if (code0 == MEM && code1 == REG) + return (GP_REG_P (REGNO (operands[1]))) ? \"sw\\t%1,%0\" : \"s.s\\t%1,%0\"; + + abort_with_insn (insn, \"Bad movsf\"); + return \"\"; +}") + + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=f,f,m,fy,*f,*y,&*y,*m") + (match_operand:DF 1 "general_operand" "f,m,f,F,*y,*f,*m,*y"))] + "" + "* +{ + extern rtx adj_offsettable_operand (); + extern int offsettable_address_p (); + + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG) + { + if (code1 == REG) + { + if (FP_REG_P (REGNO (operands[0]))) + { + if (FP_REG_P (REGNO (operands[1]))) + return \"mov.d\\t%0,%1\"; + else + return \"mtc1\\t%L1,%0\\t\\t# Calling sequence trick\;mtc1\\t%M1,%D0\"; + } + + else if (FP_REG_P (REGNO (operands[1]))) + return \"mfc1\\t%L0,%1\\t\\t# Calling sequence trick\;mfc1\\t%M0,%D1\"; + + else if (REGNO (operands[0]) != (REGNO (operands[1])+1)) + return \"move\\t%0,%1\\n\\tmove\\t%D0,%D1\"; + + else + return \"move\\t%D0,%D1\\n\\tmove\\t%0,%1\"; + } + + else if (code1 == CONST_DOUBLE) + return \"li.d\\t%0,%1\"; + + else if (code1 == MEM) + { + if (FP_REG_P (REGNO (operands[0]))) + return \"l.d\\t%0,%1\"; + + else if (offsettable_address_p (1, DFmode, XEXP (operands[1], 0))) + { + operands[2] = adj_offsettable_operand (operands[1], 4); + if (reg_mentioned_p (operands[0], operands[1])) + return \"lw\\t%D0,%2\;lw\\t%0,%1\"; + else + return \"lw\\t%0,%1\;lw\\t%D0,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%1\;lw\\t%0,0(%2)\;lw\\t%D0,4(%2)\;set\\tat\"; + } + } + } + + else if (code0 == MEM && code1 == REG) + { + if (FP_REG_P (REGNO (operands[1]))) + return \"s.d\\t%1,%0\"; + + else if (offsettable_address_p (1, DFmode, XEXP (operands[0], 0))) + { + operands[2] = adj_offsettable_operand (operands[0], 4); + return \"sw\\t%1,%0\;sw\\t%D1,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%0\;sw\\t%1,0(%2)\;sw\\t%D1,4(%2)\;set\\tat\"; + } + } + + abort_with_insn (insn, \"Bad movdf\"); + return \"\"; +}") + + +;; +;; .................... +;; +;; OTHER ARITHMETIC AND SHIFT +;; +;; .................... + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + + return \"sll\\t%0,%1,%2\"; +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + + return \"sra\\t%0,%1,%2\"; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + + return \"srl\\t%0,%1,%2\"; +}") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "sub%:\\t%0,$0,%1") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "neg.d\\t%0,%1") + +(define_insn "negsf2" + + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "neg.s\\t%0,%1") + + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "nor\\t%0,$0,%1") + +;; +;; .................... +;; +;; COMPARISONS +;; +;; .................... + + ;;- Order is significant here + ;;- because there are untyped + ;;- comparisons generated by + ;;- the optimizer + ;;- (set (cc0) + ;;- (compare (const_int 2) + ;;- (const_int 1))) + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "* + compare_collect (SImode, operands[0], operands[1]); + return \"\\t\\t\\t\\t# cmpsi\\t%0,%1\"; +") + + +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "* + compare_collect (SImode, operands[0], gen_rtx (REG, SImode, 0)); + return \"\\t\\t\\t\\t# (set (cc0)\\t%0)\"; +") + +;; These patterns are hopelessly invalid, because +;; comparing subword values properly requires extending them. + +;; (define_insn "cmphi" +;; [(set (cc0) +;; (compare (match_operand:HI 0 "register_operand" "r") +;; (match_operand:HI 1 "register_operand" "r")))] +;; "" +;; "* +;; compare_collect (HImode, operands[0], operands[1]); +;; return \" #\\tcmphi\\t%0,%1\"; +;; ") +;; +;; (define_insn "cmpqi" +;; [(set (cc0) +;; (compare (match_operand:QI 0 "register_operand" "r") +;; (match_operand:QI 1 "register_operand" "r")))] +;; "" +;; "* +;; compare_collect (QImode, operands[0], operands[1]); +;; return \" #\\tcmpqi\\t%0,%1\"; +;; ") +;; +;; (define_insn "" +;; [(set (cc0) +;; (match_operand:QI 0 "register_operand" "r"))] +;; "" +;; "* +;; compare_collect (QImode, operands[0], gen_rtx (REG, QImode, 0)); +;; return \" #\\t (set (cc0)\\t%0)\"; +;; ") +;; +;; (define_insn "" +;; [(set (cc0) +;; (match_operand:HI 0 "register_operand" "r"))] +;; "" +;; "* +;; compare_collect (HImode, operands[0], gen_rtx (REG, HImode, 0)); +;; return \" #\\t (set (cc0)\\t%0)\"; +;; ") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "f")))] + "" + "* + compare_collect (DFmode, operands[0], operands[1]); + return \" #\\t\\t\\t\\tcmpdf\\t%0,%1\" ; +") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f")))] + "" + "* + compare_collect (SFmode, operands[0], operands[1]); + return \"\\t\\t\\t\\t# cmpsf\\t%0,%1\" ; +") + +;; +;; .................... +;; +;; BRANCHES +;; +;; .................... + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"j\\t%0\"; + else + return \"j\\t%l0\"; +}") + + +(define_insn "tablejump" + [(set (pc) + (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "j\\t%0") + + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"beq\\t%0,%1,%2\\t\\t# beq\", br_ops); + } + return \"\"; +} + ") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bne\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bne\", br_ops); + } + else + { + output_asm_insn (\"bne\\t%0,%1,%2\\t\\t# bne\", br_ops); + } + return \"\"; +} + +") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgt branch %0 > %1\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgt\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgt branch %0 > %1\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgt\", br_ops); + } + else + { + output_asm_insn (\"bgt\\t%0,%1,%2\\t\\t# bgt\", br_ops); + } + return \"\"; +} + +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# blt\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# blt\", br_ops); + } + else + { + output_asm_insn (\"blt\\t%0,%1,%2\\t\\t# blt\", br_ops); + } + return \" #\\tblt\\t%l0\\t\\t# blt\"; +} +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgtu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgtu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgtu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgtu\", br_ops); + } + else + { + output_asm_insn (\"bgtu\\t%0,%1,%2\\t\\t# bgtu\", br_ops); + } + return \" #\\tbgtu\\t%l0\\t\\t# bgtu\"; +} +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else + { + output_asm_insn (\"bltu\\t%0,%1,%2\\t\\t# bltu\", br_ops); + } + return \"\"; +} +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge\", br_ops); + } + else + { + output_asm_insn (\"bge\\t%0,%1,%2\\t\\t# bge\", br_ops); + } + return \"\"; +} +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bgeu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bgeu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu\", br_ops); + } + else + { + output_asm_insn (\"bgeu\\t%0,%1,%2\\t\\t# bgeu\", br_ops); + } + return \"\"; +} +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else + { + output_asm_insn (\"ble\\t%0,%1,%2\\t\\t# ble\", br_ops); + } + return \"\"; +} +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else + { + output_asm_insn (\"bleu\\t%0,%1,%2\\t\\t# bleu\", br_ops); + } + return \" #\\tbleu\\t%l0\\t\\t# bleu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"beq\\t%0,%1,%2\\t\\t# beq Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bne\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"bne\\t%0,%1,%2\\t\\t# bne Inv.\", br_ops); + } + return \"\"; +} + +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"bgt\\t%0,%1,%2\\t\\t# bgt Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"bgtu\\t%0,%1,%2\\t\\t# bgtu Inv.\", br_ops); + } + return \" #\\tbgtu\\t%l0\\t\\t# bgtu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"blt\\t%0,%1,%2\\t\\t# blt Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else + { + output_asm_insn (\"bltu\\t%0,%1,%2\\t\\t# bltu Inv.\", br_ops); + } + return \" #\\tbltu\\t%l0\\t\\t# bltu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge (DF) Inv.\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge (SF) Inv.\", br_ops); + } + else + { + output_asm_insn (\"bge\\t%0,%1,%2\\t\\t# bge Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu (DF) Inv.\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu (SF )Inv.\", br_ops); + } + else + { + output_asm_insn (\"bgeu\\t%0,%1,%2\\t\\t# bgeu Inv.\", br_ops); + } + return \" #\\tbgeu\\t%l0\\t\\t# bgeu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else + { + output_asm_insn (\"ble\\t%0,%1,%2\\t\\t# ble Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bleu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bleu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bleu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bleu\", br_ops); + } + else + { + output_asm_insn (\"bleu\\t%0,%1,%2\\t\\t# bleu Inv.\", br_ops); + } + return \"\"; +} +") + +;; +;; .................... +;; +;; LINKAGE +;; +;; .................... + +(define_insn "call" + [(call (match_operand 0 "memory_operand" "m") + (match_operand 1 "" "i")) + (clobber (reg:SI 31))] + "" + "* +{ + register rtx target = XEXP (operands[0], 0); + + if (GET_CODE (target) == SYMBOL_REF) + return \"jal\\t%0\"; + + else + { + operands[0] = target; + return \"jal\\t$31,%0\"; + } +}") + + +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand 1 "memory_operand" "m") + (match_operand 2 "" "i"))) + (clobber (reg:SI 31))] + "" + "* +{ + register rtx target = XEXP (operands[1], 0); + + if (GET_CODE (target) == SYMBOL_REF) + return \"jal\\t%1\"; + + else + { + operands[1] = target; + return \"jal\\t$31,%1\"; + } +}") + +(define_insn "nop" + [(const_int 0)] + "" + ".set\\tnoreorder\;nop\;.set\\treorder") + +(define_insn "probe" + [(mem:SI (reg:SI 29))] + "" + "* +{ + operands[0] = gen_rtx (REG, SImode, 1); + operands[1] = stack_pointer_rtx; + return \".set\\tnoat\;lw\\t%0,0(%1)\\t\\t# stack probe\;.set\\tat\"; +}") + +;; +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/ns32k.md b/gcc-1.40/config/ns32k.md new file mode 100644 index 0000000..f5693de --- /dev/null +++ b/gcc-1.40/config/ns32k.md @@ -0,0 +1,2636 @@ +;; BUGS: +;; Insert no-op between an insn with memory read-write operands +;; following by a scale-indexing operation. +;; The Sequent assembler does not allow addresses to be used +;; except in insns which explicitly compute an effective address. +;; I.e., one cannot say "cmpd _p,@_x" +;; Implement unsigned multiplication?? + +;;- Machine descrption for GNU compiler +;;- ns32000 Version +;; Copyright (C) 1988 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@mcc.com) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +; tstsi is first test insn so that it is the one to match +; a constant argument. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rmn"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqd %1,%0\"; }") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "g"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqw %1,%0\"; }") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "g"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqb %1,%0\"; }") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fmF"))] + "TARGET_32081" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = dconst0_rtx; + return \"cmpl %1,%0\"; }") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fmF"))] + "TARGET_32081" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = fconst0_rtx; + return \"cmpf %1,%0\"; }") + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "rmn") + (match_operand:SI 1 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + return \"cmpqd %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + int i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + return \"cmpqd %0,%1\"; + } + return \"cmpd %0,%1\"; +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + short i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + if (INTVAL (operands[1]) > 7) + operands[1] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqw %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + short i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[0]) > 7) + operands[0] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqw %0,%1\"; + } + } + return \"cmpw %0,%1\"; +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + char i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + if (INTVAL (operands[1]) > 7) + operands[1] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqb %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + char i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[0]) > 7) + operands[0] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqb %0,%1\"; + } + } + return \"cmpb %0,%1\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "fmF") + (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "cmpl %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "fmF") + (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "cmpf %0,%1") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=&fg<") + (match_operand:DF 1 "general_operand" "fFg"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movl %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"movd %1,tos\", xoperands); + output_asm_insn (\"movd %1,tos\", operands); + return \"movl tos,%0\"; + } + return \"movl %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"movl %1,tos\;movd tos,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"movd tos,%0\"; + } + else + return \"movl %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=fg<") + (match_operand:SF 1 "general_operand" "fFg"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movd %1,tos\;movf tos,%0\"; + else + return \"movf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } +#ifndef GAS_SYNTAX + /* GAS understands floating constants in ordinary movd instructions + * but other assembers might object. + */ + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + union {int i[2]; float f; double d;} convrt; + convrt.i[0] = CONST_DOUBLE_LOW (operands[1]); + convrt.i[1] = CONST_DOUBLE_HIGH (operands[1]); + convrt.f = convrt.d; + + /* Is there a better machine-independent way to to this? */ + operands[1] = gen_rtx (CONST_INT, VOIDmode, convrt.i[0]); + return \"movd %1,%0\"; + } +#endif + else return \"movd %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:TI 0 "memory_operand" "=m") + (match_operand:TI 1 "memory_operand" "m"))] + "" + "movmd %1,%0,4") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=&g<,*f,g") + (match_operand:DI 1 "general_operand" "gF,g,*f"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movl %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"movd %1,tos\", xoperands); + output_asm_insn (\"movd %1,tos\", operands); + return \"movl tos,%0\"; + } + return \"movl %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"movl %1,tos\;movd tos,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"movd tos,%0\"; + } + else + return \"movl %1,%0\"; + } + return output_move_double (operands); +}") + +;; This special case must precede movsi. +(define_insn "" + [(set (reg:SI 17) + (match_operand:SI 0 "general_operand" "rmn"))] + "" + "lprd sp,%0") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g<,*f,g") + (match_operand:SI 1 "general_operand" "gx,g,*f"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movd %1,tos\;movf tos,%0\"; + else + return \"movf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + return \"movqd %1,%0\"; + if (i < 0x4000 && i >= -0x4000) +#ifdef GNX_V3 + return \"addr %c1,%0\"; +#else + return \"addr @%c1,%0\"; +#endif + return \"movd %1,%0\"; + } + else if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[1]) < 16) + return \"movd %1,%0\"; + else if (REGNO (operands[1]) == FRAME_POINTER_REGNUM) + { + if (GET_CODE(operands[0]) == REG) + return \"sprd fp,%0\"; + else + return \"addr 0(fp),%0\" ; + } + else if (REGNO (operands[1]) == STACK_POINTER_REGNUM) + { + if (GET_CODE(operands[0]) == REG) + return \"sprd sp,%0\"; + else + return \"addr 0(sp),%0\" ; + } + else abort (0); + } + else if (GET_CODE (operands[1]) == MEM) + return \"movd %1,%0\"; + /* Check if this effective address can be + calculated faster by pulling it apart. */ + if (REG_P (operands[0]) + && GET_CODE (operands[1]) == MULT + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && (INTVAL (XEXP (operands[1], 1)) == 2 + || INTVAL (XEXP (operands[1], 1)) == 4)) + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (XEXP (operands[1], 1)) >> 1); + return output_shift_insn (xoperands); + } + return \"addr %a1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g<") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + short i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[1]) > 7) + operands[1] = + gen_rtx (CONST_INT, VOIDmode, i); + return \"movqw %1,%0\"; + } + } + return \"movw %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+r")) + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL(operands[1]) <= 7 && INTVAL(operands[1]) >= -8) + return \"movqw %1,%0\"; + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g<") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ if (GET_CODE (operands[1]) == CONST_INT) + { + char char_val = (char)INTVAL (operands[1]); + if (char_val <= 7 && char_val >= -8) + { + if (INTVAL (operands[1]) > 7) + operands[1] = + gen_rtx (CONST_INT, VOIDmode, char_val); + return \"movqb %1,%0\"; + } + } + return \"movb %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+r")) + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL(operands[1]) < 8 && INTVAL(operands[1]) > -9) + return \"movqb %1,%0\"; + return \"movb %1,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_insn "movstrsi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:SI 2 "general_operand" "rmn")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2))] + "" + "* +{ + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + abort (); + operands[0] = XEXP (operands[0], 0); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[0]) == MEM) + if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"movd %0,r2\;movd %1,r1\", operands); + else + output_asm_insn (\"movd %0,r2\;addr %a1,r1\", operands); + else if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"addr %a0,r2\;movd %1,r1\", operands); + else + output_asm_insn (\"addr %a0,r2\;addr %a1,r1\", operands); + + if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) >> 2); + if ((unsigned) INTVAL (operands[2]) <= 7) + return \"movqd %2,r0\;movsd\"; + else + return \"movd %2,r0\;movsd\"; + } + else + { + return \"movd %2,r0\;movsb\"; + } +}") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (truncate:QI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "movb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (truncate:HI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "movw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (truncate:QI (match_operand:HI 1 "general_operand" "g")))] + "" + "movb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "movxwd %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "movxbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (sign_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "movxbd %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float_extend:DF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "movfl %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float_truncate:SF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "movlf %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "movzwd %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (zero_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbd %1,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +;; Rumor has it that the National part does not correctly convert +;; constant ints to floats. This conversion is therefore disabled. +;; A register must be used to perform the conversion. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_32081" + "movdf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float:DF (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_32081" + "movdl %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_32081" + "movwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float:DF (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_32081" + "movwl %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:QI 1 "general_operand" "rm")))] + "TARGET_32081" + "movbf %1,%0") + +; Some assemblers warn that this insn doesn't work. +; Maybe they know something we don't. +;(define_insn "floatqidf2" +; [(set (match_operand:DF 0 "general_operand" "=fm<") +; (float:DF (match_operand:QI 1 "general_operand" "rm")))] +; "TARGET_32081" +; "movbl %1,%0") + +;; Float-to-fix conversion insns. +;; The sequent compiler always generates "trunc" insns. + +(define_insn "fixsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fixsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fixdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclb %1,%0") + +(define_insn "fixdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclw %1,%0") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncld %1,%0") + +;; Unsigned + +(define_insn "fixunssfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (unsigned_fix:QI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fixunssfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (unsigned_fix:HI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fixunssfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (unsigned_fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fixunsdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclb %1,%0") + +(define_insn "fixunsdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclw %1,%0") + +(define_insn "fixunsdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncld %1,%0") + +;;; These are not yet used by GCC +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_32081" + "trunclb %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_32081" + "trunclw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncld %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "addl %2,%0") + + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "addf %2,%0") + +(define_insn "" + [(set (reg:SI 17) + (plus:SI (reg:SI 17) + (match_operand:SI 0 "immediate_operand" "i")))] + "GET_CODE (operands[0]) == CONST_INT" + "* +{ +#ifndef SEQUENT_ADJUST_STACK + if (INTVAL (operands[0]) == 8) + return \"cmpd tos,tos\"; + if (INTVAL (operands[0]) == 4) + return \"cmpqd %$0,tos\"; +#endif + if (INTVAL (operands[0]) < 64 && INTVAL (operands[0]) > -64) + return \"adjspb %$%n0\"; + else if (INTVAL (operands[0]) < 8192 && INTVAL (operands[0]) >= -8192) + return \"adjspw %$%n0\"; + return \"adjspd %$%n0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (plus:SI (reg:SI 16) + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "addr %c1(fp),%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (plus:SI (reg:SI 17) + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "addr %c1(sp),%0") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=g,=g<") + (plus:SI (match_operand:SI 1 "general_operand" "%0,%r") + (match_operand:SI 2 "general_operand" "rmn,n")))] + "" + "* +{ + if (which_alternative == 1) + { + int i = INTVAL (operands[2]); + if ( i < 0x40000000 && i >= -0x40000000 ) + return \"addr %c2(%1),%0\"; + else + return \"movd %1,%0\;addd %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 7 && i >= -8) + return \"addqd %2,%0\"; + else if (GET_CODE (operands[0]) == REG + && i < 0x4000 && i >= -0x4000) + return \"addr %c2(%0),%0\"; + } + return \"addd %2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i <= 7 && i >= -8) + return \"addqw %2,%0\"; + } + return \"addw %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "=r")) + (plus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-9 && INTVAL(operands[1]) < 8) + return \"addqw %1,%0\"; + return \"addw %1,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i <= 7 && i >= -8) + return \"addqb %2,%0\"; + } + return \"addb %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "=r")) + (plus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-9 && INTVAL(operands[1]) < 8) + return \"addqb %1,%0\"; + return \"addb %1,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "subl %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "subf %2,%0") + +(define_insn "" + [(set (reg:SI 17) + (minus:SI (reg:SI 17) + (match_operand:SI 0 "immediate_operand" "i")))] + "GET_CODE (operands[0]) == CONST_INT" + "* +{ + if (GET_CODE(operands[0]) == CONST_INT && INTVAL(operands[0]) < 64 + && INTVAL(operands[0]) > -64) + return \"adjspb %0\"; + return \"adjspd %0\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqd %$%n2,%0\"; + } + return \"subd %2,%0\"; +}") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqw %$%n2,%0\"; + } + return \"subw %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "=r")) + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) + return \"addqw %$%n1,%0\"; + return \"subw %1,%0\"; +}") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqb %$%n2,%0\"; + } + return \"subb %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "=r")) + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) + return \"addqb %$%n1,%0\"; + return \"subb %1,%0\"; +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "mull %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "mulf %2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "muld %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mult:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "mulb %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "muld %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (umult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "umulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (umult:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "mulb %2,%0") + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (umult:DI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "meid %2,%0") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "divl %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "divf %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "quod %2,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "quow %2,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (div:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "quob %2,%0") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"deid %2,%0\;movd %1,%0\"; +}") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (udiv:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + operands[1] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1); + return \"deiw %2,%0\;movw %1,%0\"; +}") + +(define_insn "udivqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (udiv:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + operands[1] = gen_rtx (REG, QImode, REGNO (operands[0]) + 1); + return \"deib %2,%0\;movb %1,%0\"; +}") + +;; Remainder instructions. + +(define_insn "modsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mod:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "remd %2,%0") + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "remw %2,%0") + +(define_insn "modqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mod:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "remb %2,%0") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "deid %2,%0") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (umod:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:HI 2 "general_operand" "g")))] + "" + "deiw %2,%0") + +(define_insn "umodqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (umod:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:QI 2 "general_operand" "g")))] + "" + "deib %2,%0") + +; This isn't be usable in its current form. +;(define_insn "udivmoddisi4" +; [(set (subreg:SI (match_operand:DI 0 "general_operand" "=r") 1) +; (udiv:SI (match_operand:DI 1 "general_operand" "0") +; (match_operand:SI 2 "general_operand" "rmn"))) +; (set (subreg:SI (match_dup 0) 0) +; (umod:SI (match_dup 1) (match_dup 2)))] +; "" +; "deid %2,%0") + +;;- Logical Instructions: AND + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((INTVAL (operands[2]) | 0xff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffffff00) + return \"movqb %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xff); + return \"andb %2,%0\"; + } + } + if ((INTVAL (operands[2]) | 0xffff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffff0000) + return \"movqw %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + return \"andw %2,%0\"; + } + } + } + return \"andd %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffffff00) + return \"movqb %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xff); + return \"andb %2,%0\"; + } + } + return \"andw %2,%0\"; +}") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "andb %2,%0") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "0") + (not:SI (match_operand:SI 2 "general_operand" "rmn"))))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"bicb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"bicw %2,%0\"; + } + return \"bicd %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "rmn")) + (match_operand:SI 2 "general_operand" "0")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if ((INTVAL (operands[1]) & 0xffffff00) == 0) + return \"bicb %1,%0\"; + if ((INTVAL (operands[1]) & 0xffff0000) == 0) + return \"bicw %1,%0\"; + } + return \"bicd %1,%0\"; +}") + +(define_insn "andcbhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "0") + (not:HI (match_operand:HI 2 "general_operand" "g"))))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 0xffffff00) == 0) + return \"bicb %2,%0\"; + return \"bicw %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "g")) + (match_operand:HI 2 "general_operand" "0")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 0xffffff00) == 0) + return \"bicb %1,%0\"; + return \"bicw %1,%0\"; +}") + +(define_insn "andcbqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "0") + (not:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "bicb %2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "g")) + (match_operand:QI 2 "general_operand" "0")))] + "" + "bicb %1,%0") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"orb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"orw %2,%0\"; + } + return \"ord %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE(operands[2]) == CONST_INT && + (INTVAL(operands[2]) & 0xffffff00) == 0) + return \"orb %2,%0\"; + return \"orw %2,%0\"; +}") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "orb %2,%0") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"xorb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"xorw %2,%0\"; + } + return \"xord %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE(operands[2]) == CONST_INT && + (INTVAL(operands[2]) & 0xffffff00) == 0) + return \"xorb %2,%0\"; + return \"xorw %2,%0\"; +}") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "xorb %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "negl %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (neg:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "negf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (neg:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "negd %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "negw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "negb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (not:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "comd %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "comw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "comb %1,%0") + +;; arithmetic left and right shift operations + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=g,g") + (ashift:SI (match_operand:SI 1 "general_operand" "r,0") + (match_operand:SI 2 "general_operand" "I,rmn")))] + "" + "* return output_shift_insn (operands);") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[2]) == 1) + return \"addw %0,%0\"; + else if (INTVAL (operands[2]) == 2) + return \"addw %0,%0\;addw %0,%0\"; + return \"ashw %2,%0\"; +}") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[2]) == 1) + return \"addb %1,%0\"; + else if (INTVAL (operands[2]) == 2) + return \"addb %1,%0\;addb %0,%0\"; + return \"ashb %2,%0\"; +}") + +;; Arithmetic right shift on the 32k works by negating the shift count. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashift:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashift:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "lshd %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "lshw %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "lshb %2,%0") + +;; Logical right shift on the 32k works by negating the shift count. +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshift:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshift:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +;; Rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "rotd %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "rotw %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "rotb %2,%0") + +;; Right rotate on the 32k works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotate:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotate:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +;;- load or push effective address +;; These come after the move, add, and multiply patterns +;; because we don't want pushl $1 turned into pushad 1. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (REG_P (operands[0]) + && GET_CODE (operands[1]) == MULT + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && (INTVAL (XEXP (operands[1], 1)) == 2 + || INTVAL (XEXP (operands[1], 1)) == 4)) + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (XEXP (operands[1], 1)) >> 1); + return output_shift_insn (xoperands); + } + return \"addr %a1,%0\"; +}") + +;;; Index insns. These are about the same speed as multiply-add counterparts. +;;; but slower then using power-of-2 shifts if we can use them +; +;(define_insn "" +; [(set (match_operand:SI 0 "register_operand" "=r") +; (plus:SI (match_operand:SI 1 "general_operand" "rmn") +; (mult:SI (match_operand:SI 2 "register_operand" "0") +; (plus:SI (match_operand:SI 3 "general_operand" "rmn") (const_int 1)))))] +; "GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) > 8" +; "indexd %0,%3,%1") +; +;(define_insn "" +; [(set (match_operand:SI 0 "register_operand" "=r") +; (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0") +; (plus:SI (match_operand:SI 2 "general_operand" "rmn") (const_int 1))) +; (match_operand:SI 3 "general_operand" "rmn")))] +; "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 8" +; "indexd %0,%2,%3") + +;; Set, Clear, and Invert bit + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (match_dup 0)))] + "" + "sbitd %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI + (match_dup 0) + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn"))))] + "" + "sbitd %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0) + (match_dup 0)))] + "" + "sbitb %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI + (match_dup 0) + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0)))] + "" + "sbitb %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI + (not:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn"))) + (match_dup 0)))] + "" + "cbitd %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI + (match_dup 0) + (not:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")))))] + "" + "cbitd %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI + (subreg:QI + (not:SI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn"))) 0) + (match_dup 0)))] + "" + "cbitb %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI + (match_dup 0) + (subreg:QI + (not:SI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn"))) 0)))] + "" + "cbitb %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (match_dup 0)))] + "" + "ibitd %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI + (match_dup 0) + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn"))))] + "" + "ibitd %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0) + (match_dup 0)))] + "" + "ibitb %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI + (match_dup 0) + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0)))] + "" + "ibitb %1,%0") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:SI 0 "general_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitd %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (zero_extract (match_operand:SI 0 "general_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (const_int 1)))] + "" + "* +{ cc_status.flags = CC_Z_IN_NOT_F; + return \"tbitd %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:HI 0 "general_operand" "rm") + (const_int 1) + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (zero_extract (match_operand:HI 0 "general_operand" "rm") + (const_int 1) + (match_operand:HI 1 "general_operand" "g")) + (const_int 1)))] + "" + "* +{ cc_status.flags = CC_Z_IN_NOT_F; + return \"tbitw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:QI 0 "general_operand" "rm") + (const_int 1) + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (zero_extract:SI (match_operand:QI 0 "general_operand" "rm") + (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) + (const_int 1)))] + "" + "* +{ cc_status.flags = CC_Z_IN_NOT_F; + return \"tbitb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "rm") + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + cc_status.flags = CC_Z_IN_F; + return \"tbitd %1,%0\"; +}") + +;; extract(base, width, offset) +;; Signed bitfield extraction is not supported in hardware on the +;; NS 32032. It is therefore better to let GCC figure out a +;; good strategy for generating the proper instruction sequence +;; and represent it as rtl. + +;; Optimize the case of extracting a byte or word from a register. +;; Otherwise we must load a register with the offset of the +;; chunk we want, and perform an extract insn (each of which +;; is very expensive). Since we use the stack to do our bit-twiddling +;; we cannot use it for a destination. Perhaps things are fast +;; enough on the 32532 that such hacks are not needed. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=ro") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int" "i") + (match_operand:SI 3 "const_int" "i")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) == 8 || INTVAL (operands[3]) == 16 || INTVAL (operands[3]) == 24)" + "* +{ + output_asm_insn (\"movd %1,tos\", operands); + if (INTVAL (operands[2]) == 16) + { + if (INTVAL (operands[3]) == 8) + output_asm_insn (\"movzwd 1(sp),%0\", operands); + else + output_asm_insn (\"movzwd 2(sp),%0\", operands); + } + else + { + if (INTVAL (operands[3]) == 8) + output_asm_insn (\"movzbd 1(sp),%0\", operands); + else if (INTVAL (operands[3]) == 16) + output_asm_insn (\"movzbd 2(sp),%0\", operands); + else + output_asm_insn (\"movzbd 3(sp),%0\", operands); + } + return \"cmpqd %$0,tos\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=ro") + (zero_extract:SI (match_operand:HI 1 "register_operand" "r") + (match_operand:SI 2 "const_int" "i") + (match_operand:SI 3 "const_int" "i")))] + "INTVAL (operands[2]) == 8 && INTVAL (operands[3]) == 8" + "movw %1,tos\;movzbd 1(sp),%0\;adjspb %$-2") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=g<,g<") + (zero_extract:SI (match_operand:SI 1 "general_operand" "rm,o") + (match_operand:SI 2 "const_int" "i,i") + (match_operand:SI 3 "general_operand" "rK,n")))] + "" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + { + if (INTVAL (operands[3]) >= 8) + operands[1] = adj_offsettable_operand (operands[1], + INTVAL (operands[3]) >> 3); + return \"extsd %1,%0,%3,%2\"; + } + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<,g<") + (zero_extract:SI (match_operand:HI 1 "general_operand" "rm,o") + (match_operand:SI 2 "const_int" "i,i") + (match_operand:SI 3 "general_operand" "rK,n")))] + "" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + { + if (INTVAL (operands[3]) >= 8) + operands[1] = adj_offsettable_operand (operands[1], + INTVAL (operands[3]) >> 3); + return \"extsd %1,%0,%3,%2\"; + } + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extract:SI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "const_int" "i") + (match_operand:SI 3 "general_operand" "rn")))] + "" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + return \"extsd %1,%0,%3,%2\"; + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g,o") + (match_operand:SI 1 "const_int" "i,i") + (match_operand:SI 2 "general_operand" "rK,n")) + (match_operand:SI 3 "general_operand" "rm,rm"))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) >= 8) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[2]) / 8); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 8); + } + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + } + return \"insd %2,%3,%0,%1\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:HI 0 "general_operand" "+g,o") + (match_operand:SI 1 "const_int" "i,i") + (match_operand:SI 2 "general_operand" "rK,n")) + (match_operand:SI 3 "general_operand" "rm,rm"))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) >= 8) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[2]) / 8); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 8); + } + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + } + return \"insd %2,%3,%0,%1\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "general_operand" "=g") + (match_operand:SI 1 "const_int" "i") + (match_operand:SI 2 "general_operand" "rn")) + (match_operand:SI 3 "general_operand" "rm"))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + return \"insd %2,%3,%0,%1\"; +}") + + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfc %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfs %l0\"; + else return \"beq %l0\"; +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfs %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfc %l0\"; + else return \"bne %l0\"; +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bgt %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bhi %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blt %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blo %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bge %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bhs %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ble %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bls %l0") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfs %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfc %l0\"; + else return \"bne %l0\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfc %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfs %l0\"; + else return \"beq %l0\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "ble %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bls %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bge %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bhs %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blt %l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blo %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bgt %l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bhi %l0") + +;; Subtract-and-jump and Add-and-jump insns. +;; These can actually be used for adding numbers in the range -8 to 7 + +(define_insn "" + [(set (pc) + (if_then_else + (ne (minus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8" + "acbd %$%n1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (plus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 8" + "acbd %1,%0,%l2") + +;; Reversed + +(define_insn "" + [(set (pc) + (if_then_else + (eq (minus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8" + "acbd %$%n1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (plus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 8" + "acbd %1,%0,%l2") + +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ +#ifndef JSR_ALWAYS + if (GET_CODE (operands[0]) == MEM) + { + rtx temp = XEXP (operands[0], 0); + if (CONSTANT_ADDRESS_P (temp)) + { +#ifdef GAS_SYNTAX + operands[0] = temp; + return \"bsr %0\"; +#else +#ifdef GNX_V3 + return \"bsr %0\"; +#else + return \"bsr %?%a0\"; +#endif +#endif + } + if (GET_CODE (XEXP (operands[0], 0)) == REG) +#if defined(GNX_V3) || defined(GAS_SYNTAX) + return \"jsr %0\"; +#else + return \"jsr %a0\"; +#endif + } +#endif /* not JSR_ALWAYS */ + return \"jsr %0\"; +}") + +(define_insn "call_value" + [(set (match_operand 0 "" "=fg") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ +#ifndef JSR_ALWAYS + if (GET_CODE (operands[0]) == MEM) + { + rtx temp = XEXP (operands[0], 0); + if (CONSTANT_ADDRESS_P (temp)) + { +#ifdef GAS_SYNTAX + operands[0] = temp; + return \"bsr %1\"; +#else +#ifdef GNX_V3 + return \"bsr %1\"; +#else + return \"bsr %?%a1\"; +#endif +#endif + } + if (GET_CODE (XEXP (operands[0], 0)) == REG) +#if defined(GNX_V3) || defined(GAS_SYNTAX) + return \"jsr %1\"; +#else + return \"jsr %a1\"; +#endif + } +#endif /* not JSR_ALWAYS */ + return \"jsr %1\"; +}") + +(define_insn "return" + [(return)] + "0" + "ret 0") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (abs:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "absf %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "absl %1,%0") + +(define_insn "abssi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (abs:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "absd %1,%0") + +(define_insn "abshi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (abs:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "absw %1,%0") + +(define_insn "absqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (abs:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "absb %1,%0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;(define_insn "tablejump" +;; [(set (pc) +;; (plus:SI (match_operand:SI 0 "general_operand" "g") +;; (pc)))] +;; "" +;; "cased %0") + +(define_insn "tablejump" + [(set (pc) + (plus:SI (pc) (match_operand:HI 0 "general_operand" "g"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (operands[1])); + return \"casew %0\"; +}") + +;;(define_insn "" +;; [(set (pc) +;; (plus:SI (match_operand:QI 0 "general_operand" "g") +;; (pc)))] +;; "" +;; "caseb %0") + +;; Scondi instructions +(define_insn "seq" + [(set (match_operand:SI 0 "general_operand" "=g<") + (eq (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcd %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsd %0\"; + else return \"seqd %0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (eq (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcw %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsw %0\"; + else return \"seqw %0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (eq (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcb %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsb %0\"; + else return \"seqb %0\"; +}") + +(define_insn "sne" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ne (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsd %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcd %0\"; + else return \"sned %0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ne (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsw %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcw %0\"; + else return \"snew %0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ne (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsb %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcb %0\"; + else return \"sneb %0\"; +}") + +(define_insn "sgt" + [(set (match_operand:SI 0 "general_operand" "=g<") + (gt (cc0) (const_int 0)))] + "" + "sgtd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (gt (cc0) (const_int 0)))] + "" + "sgtw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (gt (cc0) (const_int 0)))] + "" + "sgtb %0") + +(define_insn "sgtu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (gtu (cc0) (const_int 0)))] + "" + "shid %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (gtu (cc0) (const_int 0)))] + "" + "shiw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (gtu (cc0) (const_int 0)))] + "" + "shib %0") + +(define_insn "slt" + [(set (match_operand:SI 0 "general_operand" "=g<") + (lt (cc0) (const_int 0)))] + "" + "sltd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (lt (cc0) (const_int 0)))] + "" + "sltw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (lt (cc0) (const_int 0)))] + "" + "sltb %0") + +(define_insn "sltu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ltu (cc0) (const_int 0)))] + "" + "slod %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ltu (cc0) (const_int 0)))] + "" + "slow %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ltu (cc0) (const_int 0)))] + "" + "slob %0") + +(define_insn "sge" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ge (cc0) (const_int 0)))] + "" + "sged %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ge (cc0) (const_int 0)))] + "" + "sgew %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ge (cc0) (const_int 0)))] + "" + "sgeb %0") + +(define_insn "sgeu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (geu (cc0) (const_int 0)))] + "" + "shsd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (geu (cc0) (const_int 0)))] + "" + "shsw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (geu (cc0) (const_int 0)))] + "" + "shsb %0") + +(define_insn "sle" + [(set (match_operand:SI 0 "general_operand" "=g<") + (le (cc0) (const_int 0)))] + "" + "sled %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (le (cc0) (const_int 0)))] + "" + "slew %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (le (cc0) (const_int 0)))] + "" + "sleb %0") + +(define_insn "sleu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (leu (cc0) (const_int 0)))] + "" + "slsd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (leu (cc0) (const_int 0)))] + "" + "slsw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (leu (cc0) (const_int 0)))] + "" + "slsb %0") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/out-alliant.c b/gcc-1.40/config/out-alliant.c new file mode 100644 index 0000000..63727ad --- /dev/null +++ b/gcc-1.40/config/out-alliant.c @@ -0,0 +1,291 @@ +/* Subroutines for insn-output.c for Alliant FX computers. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Some output-actions in alliant.md need these. */ +#include <stdio.h> +extern FILE *asm_out_file; + +/* Index into this array by (register number >> 3) to find the + smallest class which contains that register. */ +enum reg_class regno_reg_class[] + = { DATA_REGS, ADDR_REGS, FP_REGS }; + +static rtx find_addr_reg (); + +char * +output_btst (operands, countop, dataop, insn, signpos) + rtx *operands; + rtx countop, dataop; + rtx insn; + int signpos; +{ + operands[0] = countop; + operands[1] = dataop; + + if (GET_CODE (countop) == CONST_INT) + { + register int count = INTVAL (countop); + /* If COUNT is bigger than size of storage unit in use, + advance to the containing unit of same size. */ + if (count > signpos) + { + int offset = (count & ~signpos) / 8; + count = count & signpos; + operands[1] = dataop = adj_offsettable_operand (dataop, offset); + } + if (count == signpos) + cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; + else + cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; + + if (count == 31 + && next_insns_test_no_inequality (insn)) + return "tst%.l %1"; + if (count == 15 + && next_insns_test_no_inequality (insn)) + return "tst%.w %1"; + if (count == 7 + && next_insns_test_no_inequality (insn)) + return "tst%.b %1"; + + cc_status.flags = CC_NOT_NEGATIVE; + } + return "btst %0,%1"; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (operands[1] != const0_rtx) + return "mov%.l %1,%0"; + if (! ADDRESS_REG_P (operands[0])) + return "clr%.l %0"; + return "sub%.l %0,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + output_asm_insn ("subq%.l %#8,%0", operands); + operands[0] = gen_rtx (MEM, DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + output_asm_insn ("subq%.l %#8,%1", operands); + operands[1] = gen_rtx (MEM, DImode, operands[1]); + optype1 = OFFSOP; + } + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N(sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1]))) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + return ""; +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +int +standard_SunFPA_constant_p (x) + rtx x; +{ + return( 0 ); +} + diff --git a/gcc-1.40/config/out-convex.c b/gcc-1.40/config/out-convex.c new file mode 100644 index 0000000..df6fb73 --- /dev/null +++ b/gcc-1.40/config/out-convex.c @@ -0,0 +1,219 @@ +/* Subroutines for insn-output.c for Convex. + Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Boolean to keep track of whether the current section is .text or not. + Used by .align handler in tm-convex.h. */ + +int current_section_is_text; + +/* + * set_cmp (left_rtx, right_rtx, [bhwlsd]) + * gen_cmp (label_rtx, cmpop, [tf]) + * + * set_cmp saves the operands of a "cmp" insn, + * along with the type character to be used in the compare instruction. + * + * gen_cmp finds out what comparison is to be performed and + * outputs the necessary instructions, eg, + * "eq.w a1,a2 ! jbra.t L5" + * for (cmpsi a1 a2) (beq L5) + */ + +static rtx xop0, xop1; +static char typech, regch; + +char * +set_cmp (op0, op1, typechr) + rtx op0, op1; + char typechr; +{ + xop0 = op0; + xop1 = op1; + typech = typechr; + if (GET_CODE (op0) == REG) + regch = REGNO_OK_FOR_BASE_P (REGNO (op0)) ? 'a' : 's'; + else if (GET_CODE (op1) == REG) + regch = REGNO_OK_FOR_BASE_P (REGNO (op1)) ? 'a' : 's'; + else abort (); + return ""; +} + +char * +gen_cmp (label, cmpop, tf) + rtx label; + char *cmpop; + char tf; +{ + char buf[80]; + char revop[4]; + rtx ops[3]; + + ops[2] = label; + + /* constant must be first; swap operands if necessary + if lt, le, ltu, leu are swapped, change to le, lt, leu, ltu + and reverse the sense of the jump */ + + if (CONSTANT_P (xop1) || GET_CODE (xop1) == CONST_DOUBLE) + { + ops[0] = xop1; + ops[1] = xop0; + if (cmpop[0] == 'l') + { + bcopy (cmpop, revop, 4); + revop[1] ^= 'e' ^ 't'; + tf ^= 't' ^ 'f'; + cmpop = revop; + } + } + else + { + ops[0] = xop0; + ops[1] = xop1; + } + + sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2", cmpop, typech, regch, tf); + output_asm_insn (buf, ops); + return ""; +} + +/* + * Routines to look at CONST_DOUBLEs without sinful knowledge of + * what the inside of u.d looks like + * + * const_double_high_int -- high word of machine double or long long + * const_double_low_int -- low word + * const_double_float_int -- the word of a machine float + */ + +static double frexp (); +static void float_extract (); + +int +const_double_high_int (x) + rtx x; +{ + if (GET_MODE (x) == DImode) + return CONST_DOUBLE_HIGH (x); + else + { + int sign, expd, expf; + unsigned fracdh, fracdl, fracf; + float_extract (x, &sign, &expd, &fracdh, &fracdl, &expf, &fracf); + + if (fracdh == 0) + return 0; + if (expd < -01777 || expd > 01777) + return 1 << 31; + return sign << 31 | (expd + 02000) << 20 | fracdh - (1 << 20); + } +} + +int +const_double_low_int (x) + rtx x; +{ + if (GET_MODE (x) == DImode) + return CONST_DOUBLE_LOW (x); + else + { + int sign, expd, expf; + unsigned fracdh, fracdl, fracf; + float_extract (x, &sign, &expd, &fracdh, &fracdl, &expf, &fracf); + return fracdl; + } +} + +int +const_double_float_int (x) + rtx x; +{ + int sign, expd, expf; + unsigned fracdh, fracdl, fracf; + float_extract (x, &sign, &expd, &fracdh, &fracdl, &expf, &fracf); + + if (fracf == 0) + return 0; + if (expf < -0177 || expf > 0177) + return 1 << 31; + return sign << 31 | (expf + 0200) << 20 | fracf - (1 << 23); +} + +#define T21 ((double) (1 << 21)) +#define T24 ((double) (1 << 24)) +#define T53 ((double) (1 << 27) * (double) (1 << 26)) + +static void +float_extract (x, sign, expd, fracdh, fracdl, expf, fracf) + rtx x; + int *sign, *expd, *expf; + unsigned *fracdh, *fracdl, *fracf; +{ + int exp, round; + double d, r; + union real_extract u; + + bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u); + + /* Get sign and exponent. */ + + if (*sign = u.d < 0) + u.d = -u.d; + d = frexp (u.d, &exp); + + /* Get 21 fraction bits for high word and 32 for low word. */ + + for (round = 0; ; round = 1) + { + r = frexp (round ? d + 1.0 / T53 : d, expd); + *expd += exp; + *fracdh = r * T21; + *fracdl = (r - *fracdh / T21) * T53; + if (round || ((r - *fracdh / T21) - *fracdl / T53) < 0.5 * T53) + break; + } + + /* Get 24 bits for float fraction. */ + + for (round = 0; ; round = 1) + { + r = frexp (round ? d + 1.0 / T24 : d, expf); + *expf += exp; + *fracf = r * T24; + if (round || (r - *fracf / T24) < 0.5 * T24) + break; + } +} + +static double +frexp (d, exp) + double d; + int *exp; +{ + int e = 0; + + if (d > 0) + { + while (d < 0.5) d *= 2.0, e--; + while (d >= 1.0) d /= 2.0, e++; + } + + *exp = e; + return d; +} diff --git a/gcc-1.40/config/out-i386.c b/gcc-1.40/config/out-i386.c new file mode 100644 index 0000000..958d09f --- /dev/null +++ b/gcc-1.40/config/out-i386.c @@ -0,0 +1,1418 @@ +/* Subroutines for insn-output.c for Intel 80386. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef FILE +#include <stdio.h> +#endif + +#define FP_TOP (gen_rtx(REG, DFmode, FIRST_FLOAT_REG)) + +#define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx)) +#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx)) + +#define RET return "" + +/* #define RETCOM(X) fprintf (asm_out_file, "%sX fp_pop_level=%d\n", \ + COMMENT_BEGIN, fp_pop_level); RET */ +#define RETCOM(X) return "" + +#define POP_ONE_FP \ + { /* fp_pop_level--; */ \ + fprintf (asm_out_file, "\tfstp %sst (0)\n", RP); } + +extern FILE *asm_out_file; +static char *singlemove_string (); +static void output_movf (); +static void replace_float_constant (); +static int mentions_fp_top (); +static int call_top_dead_p (); +static int fp_top_dead_p1 (); +static rtx via_memory (); +static void output_asm_insn_double_reg_op (); + +/* All output functions must increment or decrement this to indicate + the net number of pops or pushes which they perform. Note that it won't + necessarily balance with the optimize running, since we might have + two different calls with the same pop shared by cross jumping. + However on optimize the reg dead heuristic seems to work. */ + +int fp_pop_level = 0; + +static char *hi_reg_name[] = HI_REGISTER_NAMES; +static char *qi_reg_name[] = QI_REGISTER_NAMES; + +/* for fabs, fch, .. where the argument operand[1] must first be moved to + constraints "=fm" "0" */ + +#define FP_CALL1(op) \ + { if (FP_REG_P (operands[0])) \ + return op; \ + output_movf (FP_TOP, operands[1]); \ + output_asm_insn (op, operands); \ + /* fp_pop_level--; */ \ + return "fstp%z0 %0"; } + +/* handle case of call where op0/op1 is "=mf" and opn is "mrf" + eg. fadd */ +#define FP_CALL(op, rev, n) \ + return fp_call_internal (op, rev, n, operands, insn); + +static char * +fp_call_internal (op, rev, n, operands, insn) + char *op; + char *rev; + int n; + rtx *operands; + rtx insn; +{ + if (!FP_REG_P (operands[0])) + { + /* Here destination is in memory + and source is in the fp stack. */ + output_movf (FP_TOP, operands[0]); + output_asm_insn_double_reg_op (op, rev, insn); + return "fstp%z0 %0"; + } + + if (FP_REG_P (operands[n])) + { + rtx temp = operands[1]; + char *tem1 = op; + operands[1] = operands[n]; + op = rev; + operands[n] = temp; + rev = tem1; + } + + if (REG_P (operands[n])) + { + rtx xops[2]; + via_memory (operands[n]); + operands[n] = AT_SP (GET_MODE (operands[n])); + xops[0] = stack_pointer_rtx; + xops[1] = gen_rtx (CONST_INT, VOIDmode, + GET_MODE_SIZE (GET_MODE (operands[n]))); + output_asm_insn (op, operands + n); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } + else + output_asm_insn (op, operands + n); + + if (FP_REG_P (operands[0])) + { + /* It turns out not to work to use top_dead_p because + the death notes are not accurate enough. + But this ought to work, because the only thing that can + live across basic blocks is reg 8, and these insns + never involve reg 8 directly. */ + if (fp_top_dead_p1 (insn)) + POP_ONE_FP; + } + + RET; +} + +/* Output assembler code to perform insn OP + with two stack operands, and output on the stack. + + REV is the assembler insn that does the same thing but + effectively interchanges the meanings of the two arguments. + + Somewhat counterintuitively, the "first" operand was pushed last. + + The output replaces either the top-of-stack or both of the arguments, + depending on whether the other argument is wanted after this insn. */ + +static void +output_asm_insn_double_reg_op (op, rev, insn) + char *op; + char *rev; + rtx insn; +{ + fputc ('\t', asm_out_file); + if (top_dead_p (insn)) + { + /* Here we want the "reversed" insn, fsubr or fdivr. + But there is an assembler bug in all 80386 assemblers + which exchanges the meanings of fsubr and fsub, and of fdivr and fdiv! + So use the "unreversed" opcode (which will assemble into + the "reversed" insn). */ + rev = op; + + while (*rev && *rev != '%') + fputc (*rev++, asm_out_file); + /* fp_pop_level--; */ + + fprintf (asm_out_file, AS2 (p,%sst,%sst(1)), RP, RP); + } + else + { + while (*op && *op != '%') + fputc (*op++, asm_out_file); + fprintf (asm_out_file,AS2 ( ,%sst(1),%sst), RP, RP); + } + putc ('\n', asm_out_file); +} + +/* Moves X to memory location 8 below stack pointer + and returns an RTX for that memory location. + X should be a register, in DFmode or SFmode. */ + +static rtx +via_memory (x) + rtx x; +{ + if (!REG_P (x)) + abort (); + if (GET_MODE (x) == DFmode) + { + rtx xops[1]; + xops[0] = gen_rtx (REG, SImode, REGNO (x) + 1); + output_asm_insn ("push%L0 %0", xops); + } + output_asm_insn ("push%L0 %0", &x); +} + +/* Output an insn to copy the SFmode value in fp0 to OPERAND + without clobbering fp0. */ + +void +fp_store_sf (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[3]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = AT_SP (Pmode); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4); + output_asm_insn (AS2 (add%L0,%2,%0), xoperands); + output_asm_insn ("fst%S0 %1", xoperands); + output_asm_insn ("pop%L0 %0", &target); + } + else if (GET_CODE (target) == MEM) + output_asm_insn ("fst%S0 %0", &target); +} + +/* Output an insn to pop an SF value from fp0 into TARGET. + This destroys the value of fp0. */ + +void +fp_pop_sf (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[3]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = AT_SP (Pmode); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4); + output_asm_insn (AS2 (add%L0,%2,%0), xoperands); + output_asm_insn ("fstp%S0 %1", xoperands); + output_asm_insn ("pop%L0 %0", &target); + /* fp_pop_level--; */ + } + else if (GET_CODE (target) == MEM) + { + /* fp_pop_level--; */ + output_asm_insn ("fstp%S0 %0", &target); + } + else abort (); +} + +/* Copy the top of the fpu stack into TARGET, without popping. */ + +void +fp_store_df (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[4]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1); + xoperands[2] = AT_SP (Pmode); + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8); + output_asm_insn (AS2 (add%L0,%3,%0), xoperands); + output_asm_insn ("fst%Q0 %2", xoperands); + output_asm_insn ("pop%L0 %0", &target); + output_asm_insn ("pop%L0 %1", xoperands); + } + else if (GET_CODE (target) == MEM) + output_asm_insn ("fst%Q0 %0", &target); +} + +/* Copy the top of the fpu stack into TARGET, with popping. */ + +void +fp_pop_df (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[4]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1); + xoperands[2] = AT_SP (Pmode); + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8); + output_asm_insn (AS2 (add%L0,%3,%0), xoperands); + /* fp_pop_level--; */ + output_asm_insn ("fstp%Q0 %2", xoperands); + output_asm_insn ("pop%L0 %0", &target); + output_asm_insn ("pop%L0 %1", xoperands); + } + else if (GET_CODE (target) == MEM) + { + /* fp_pop_level--; */ + output_asm_insn ("fstp%z0 %0", &target); + } +} + +#if 0 +/* Pop the fp stack, convert value to integer and store in TARGET. + TARGET may be memory or register, and may have QI, HI or SImode. */ + +void +fp_pop_int (target) + rtx target; +{ + if (REG_P (target) || GET_MODE (target) != SImode) + { + rtx xxops[2]; + xxops[0] = stack_pointer_rtx; + xxops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + output_asm_insn (AS2 (sub%L0,%1,%0), xxops); + xxops[0] = AT_SP (Pmode); + /* fp_pop_level--; */ + output_asm_insn ("fistp%L0 %0", xxops); + output_asm_insn ("pop%L0 %0", &target); + } + else if (GET_CODE (target) == MEM) + { + /* fp_pop_level--; */ + output_asm_insn ("fistp%L0 %0", &target); + } + else abort (); +} +#endif + +/* Push the SFmode value X onto the fpu stack. */ + +void +fp_push_sf (x) + rtx x; +{ + /* fp_pop_level++; */ + if (REG_P (x)) + { + rtx xoperands[2]; + rtx xfops[3]; + output_asm_insn ("push%L0 %0", &x); + xfops[0] = AT_SP (Pmode); + xfops[2] = gen_rtx (CONST_INT, VOIDmode, 4); + xfops[1] = stack_pointer_rtx; + output_asm_insn ("fld%S0 %0 \n\tadd%L0 %2,%1", xfops); + } + else + output_asm_insn ("fld%S0 %0", &x); +} + +/* Push the DFmode value X onto the fpu stack. */ + +void +fp_push_df (x) + rtx x; +{ + /* fp_pop_level++; */ + + if (REG_P (x)) + { + rtx xoperands[2]; + rtx xfops[3]; + xoperands[0] = x; + xoperands[1] = gen_rtx (REG, SImode, REGNO (x) + 1); + output_asm_insn ("push%L0 %1", xoperands); + output_asm_insn ("push%L0 %0", xoperands); + xfops[0] = AT_SP (Pmode); + xfops[2] = gen_rtx (CONST_INT, VOIDmode, 8); + xfops[1] = stack_pointer_rtx; + output_asm_insn ("fld%Q0 %0 \n\tadd%L0 %2,%1", xfops); + } + else if (GET_CODE (x) == MEM) + output_asm_insn ("fld%Q0 %0", &x); +} + +static char *output_move_const_single (); + +static char * +singlemove_string (operands) + rtx *operands; +{ + rtx x; + if (GET_CODE (operands[0]) == MEM + && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC) + { + if (XEXP (x, 0) != stack_pointer_rtx) + abort (); + return "push%L0 %1"; + } + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + return output_move_const_single (operands); + } + else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG) + return AS2 (mov%L0,%1,%0); + else if (CONSTANT_P (operands[1])) + return AS2 (mov%L0,%1,%0); + else + { + output_asm_insn ("push%L0 %1", operands); + return "pop%L0 %0"; + } +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +/* Output an insn to add the constant N to the register X. */ + +static void +asm_add (n, x) + int n; + rtx x; +{ + rtx xops[2]; + xops[1] = x; + if (n < 0) + { + xops[0] = gen_rtx (CONST_INT, VOIDmode, -n); + output_asm_insn (AS2 (sub%L0,%0,%1), xops); + } + else if (n > 0) + { + xops[0] = gen_rtx (CONST_INT, VOIDmode, n); + output_asm_insn (AS2 (add%L0,%0,%1), xops); + } +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + asm_add (-8, operands[0]); + operands[0] = gen_rtx (MEM, DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + asm_add (-8, operands[1]); + operands[1] = gen_rtx (MEM, DImode, operands[1]); + optype1 = OFFSOP; + } + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N (sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4 (sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1]))) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + asm_add (4, addreg0); + if (addreg1) + asm_add (4, addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + asm_add (-4, addreg0); + if (addreg1) + asm_add (-4, addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + asm_add (4, addreg0); + if (addreg1) + asm_add (4, addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + asm_add (-4, addreg0); + if (addreg1) + asm_add (-4, addreg1); + + return ""; +} + +int +standard_80387_constant_p (x) + rtx x; +{ + union { double d; int i[2];} u; + register double d; + u.i[0] = XINT (x, 0); + u.i[1] = XINT (x, 1); + d = u.d; + + if (d == 0) + return 1; + if (d == 1) + return 2; + /* Note that on the 80387, other constants, such as pi, + are much slower to load as standard constants + than to load from doubles in memory! */ + + return 0; +} + +static char * +output_move_const_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + int conval = standard_80387_constant_p (operands[1]); + + /* fp_pop_level++; */ + if (conval == 1) + return "fldz"; + if (conval == 2) + return "fld1"; + /* fp_pop_level--; */ + } + + output_move_double (operands); +} + + +static char * +output_move_const_single (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + int conval = standard_80387_constant_p (operands[1]); + + /* fp_pop_level++; */ + if (conval == 1) + return "fldz"; + if (conval == 2) + return "fld1"; + /* fp_pop_level--; */ + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + union { int i[2]; double d;} u1; + union { int i; float f;} u2; + u1.i[0] = CONST_DOUBLE_LOW (operands[1]); + u1.i[1] = CONST_DOUBLE_HIGH (operands[1]); + u2.f = u1.d; + operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i); + } + return singlemove_string (operands); +} + +/* Output an insn to move an SF value from FROM to TO. + The kinds of operands are not restricted + except that they may not both be in memory. */ + +void +output_movsf (to, from) + rtx from, to; +{ + rtx xops[2]; + xops[0] = to; + xops[1] = from; + if (FP_REG_P (from) || FP_REG_P (to)) + { + from = xops[1]; + } + + if (FP_REG_P (from)) + { +#if 0 + { + if (REGNO (from) != REGNO (to)) + { + output_asm_insn ("fld%S0 %1 \n\tfstp%S0 %0", xops); + } + } + else +#endif + + if (! FP_REG_P (to)) + fp_pop_sf (to); + } + else if (FP_REG_P (to)) + fp_push_sf (from); + else + output_asm_insn (singlemove_string (xops), xops); +} + +/* Output an insn to move a DF value from FROM to TO. + The kinds of operands are not restricted + except that they may not both be in memory. */ + +void +output_movdf (to, from) + rtx from, to; +{ + rtx xops[2]; + xops[0] = to; + xops[1] = from; + if (FP_REG_P (from) || FP_REG_P (to)) + { + from = xops[1]; + to = xops[0]; + } + if (FP_REG_P (from)) + { +#if 0 + { + if (REGNO (from) != REGNO (to)) + abort (); +/* output_asm_insn ("fld%Q0 %1 \n\t fstp%Q0 %0", xops);*/ + } + else + { +#endif + if (! FP_REG_P (to)) + fp_pop_df (to); + } + else if (FP_REG_P (to)) + fp_push_df (from); + else + output_asm_insn (output_move_double (xops), xops); +} + +/* does move of FROM to TO where the mode is the minimum of the +two */ + +static void +output_movf (to, from) + rtx to, from; +{ + if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode) + output_movsf (to, from); + else + output_movdf (to, from); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +void +function_prologue (file, size) + FILE *file; + int size; +{ + register int regno; + int nregs, limit; + rtx xops[4]; + extern int frame_pointer_needed; + + /* fp_pop_level = 0; */ + xops[0] = stack_pointer_rtx; + xops[1] = frame_pointer_rtx; + xops[2] = gen_rtx (CONST_INT, VOIDmode, size); + if (frame_pointer_needed) + { + output_asm_insn ("push%L0 %1", xops); + output_asm_insn (AS2 (mov%L0,%0,%1), xops); + if (size) + output_asm_insn (AS2 (sub%L0,%2,%0), xops); + } + + /* Note If use enter it is NOT reversed args. + This one is not reversed from intel!! + I think enter is slower. Also sdb doesn't like it. + But if you want it the code is: + { + xops[3] = const0_rtx; + output_asm_insn ("enter %2,%3", xops); + } + */ + nregs = 0; + limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + for (regno = limit - 1; regno >= 0; regno--) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]); + } +} + +void +function_epilogue (file, size) + FILE *file; + int size; +{ + register int regno; + register int nregs, limit; + int assure_sp_pos; + int return_struct_adjust; + extern int frame_pointer_needed; + extern int current_function_pops_args; + extern int current_function_args_size; + extern int flag_pcc_struct_return; + + limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + nregs = 0; + + return_struct_adjust = + (current_function_returns_struct +#ifdef STRUCT_RETURN_CALLER_POP + && !flag_pcc_struct_return +#endif + ? 4 : 0); + + for (regno = (limit -1); regno >= 0; regno--) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + nregs++; + + /* sp is often unreliable so we must go off the frame pointer, + */ + + if (nregs && frame_pointer_needed) + { + rtx xops[2]; + xops[0] = adj_offsettable_operand (AT_BP (Pmode), + -size -(nregs*(UNITS_PER_WORD))); + xops[1] = stack_pointer_rtx; + output_asm_insn (AS2 (lea%L0,%0,%1), xops); + } + for (regno = 0; regno < limit; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + fprintf (file, "\tpop%s ", L_SIZE); + fprintf (file, "%se%s\n", RP, hi_reg_name[regno]); + } + } + + if (frame_pointer_needed) + fprintf (file, "\tleave\n"); + if (current_function_pops_args && current_function_args_size) + fprintf (file, "\tret %s%d\n", IP, + (current_function_args_size + return_struct_adjust)); + else if (return_struct_adjust) + fprintf (file, "\tret %s%d\n", IP, return_struct_adjust); + else + fprintf (file, "\tret\n"); +} + +int +hard_regno_mode_ok (regno, mode) + int regno; + enum machine_mode mode; +{ + return + (regno < 2 ? 1 + /* Used to reject floating modes here */ + : regno < 4 ? 1 + : regno >= 8 ? mode == DFmode || mode == SFmode + : mode != QImode); +} + +/* Print the name of a register based on its machine mode and number. + If CODE is 'w', pretend the mode is HImode. + If CODE is 'b', pretend the mode is QImode. + If CODE is 'k', pretend the mode is SImode. */ + +#define PRINT_REG(X, CODE, FILE) \ + do { fprintf (FILE, "%s", RP); \ + switch ((CODE == 'w' ? 2 \ + : CODE == 'b' ? 1 \ + : CODE == 'k' ? 4 \ + : GET_MODE_SIZE (GET_MODE (X)))) \ + { \ + case 4: \ + case 8: \ + if (!FP_REG_P (X)) fputs ("e", FILE); \ + case 2: \ + fputs (hi_reg_name[REGNO (X)], FILE); \ + break; \ + case 1: \ + fputs (qi_reg_name[REGNO (X)], FILE); \ + break; \ + } \ + } while (0) + +/* Meaning of CODE: + f -- float insn (print a CONST_DOUBLE as a float rather than in hex). + L,W,B,Q,S -- print the opcode suffix for specified size of operand. + R -- print the prefix for register names. + z -- print the opcode suffix for the size of the current operand. + * -- print a star (in certain assembler syntax) + w -- print the operand as if it's a "word" (HImode) even if it isn't. + c -- don't print special prefixes before constant operands. +*/ + +void +print_operand (file, x, code) + FILE *file; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '*': + if (USE_STAR) + putc ('*', file); + return; + + case 'L': + PUT_OP_SIZE (code, 'l', file); + return; + + case 'W': + PUT_OP_SIZE (code, 'w', file); + return; + + case 'B': + PUT_OP_SIZE (code, 'b', file); + return; + + case 'Q': + PUT_OP_SIZE (code, 'l', file); + return; + + case 'S': + PUT_OP_SIZE (code, 's', file); + return; + + case 'R': + fprintf (file, "%s", RP); + return; + + case 'z': + /* this is the size of op from size of operand */ + switch (GET_MODE_SIZE (GET_MODE (x))) + { + case 2: + PUT_OP_SIZE ('W', 'w', file); + return; + case 4: + if (GET_MODE (x) == SFmode) + { + PUT_OP_SIZE ('S', 's', file); + return; + } + else + PUT_OP_SIZE ('L', 'l', file); + return; + case 8: + if (!FP_REG_P (x)) PUT_OP_SIZE ('Q', 'l', file); + return; + case 1: + PUT_OP_SIZE ('B', 'b', file); + return; + } + } + } + if (GET_CODE (x) == REG) + { + PRINT_REG (x, code, file); + } + else if (GET_CODE (x) == MEM) + { + PRINT_PTR (x, file); + if (CONSTANT_ADDRESS_P (XEXP (x, 0))) + output_addr_const (file, XEXP (x, 0)); + else + output_address (XEXP (x, 0)); + } + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) + { + union { double d; int i[2]; } u; + union { float f; int i; } u1; + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); + u1.f = u.d; + if (code == 'f') + fprintf (file, "%.22e", u1.f); + else + { + PRINT_IMMED_PREFIX (file); + fprintf (file, "0x%x", u1.i); + } + } + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + { + union { double d; int i[2]; } u; + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); + fprintf (file, "%.22e", u.d); + } + else + { + if (code != 'c') + { + if (GET_CODE (x) == CONST_INT) + PRINT_IMMED_PREFIX (file); + else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF + || GET_CODE (x) == LABEL_REF) + PRINT_OFFSET_PREFIX (file); + } + output_addr_const (file, x); + } +} + +/* Print a memory operand whose address is ADDR. */ + +void +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + switch (GET_CODE (addr)) + { + case REG: + ADDR_BEG (file); + fprintf (file, "%se", RP); + fputs (hi_reg_name[REGNO (addr)], file); + ADDR_END (file); + break; + + case PLUS: + reg1 = 0; + reg2 = 0; + ireg = 0; + breg = 0; + offset = 0; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { + if (reg1 == 0) reg1 = addr; + else reg2 = addr; + addr = 0; + } + if (offset != 0) + { + if (addr != 0) abort (); + addr = offset; + } + if ((reg1 && GET_CODE (reg1) == MULT) + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) + { + breg = reg2; + ireg = reg1; + } + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) + { + breg = reg1; + ireg = reg2; + } + + if (ireg != 0 || breg != 0) + { + int scale = 1; + + if (addr != 0) + { + if (GET_CODE (addr) == LABEL_REF) + output_asm_label (addr); + else + output_addr_const (file, addr); + } + + if (ireg != 0 && GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)); + ireg = XEXP (ireg, 0); + } + /* output breg+ireg*scale */ + PRINT_B_I_S (breg, ireg, scale, file); + break; + } + + case MULT: + { + int scale; + if (GET_CODE (XEXP (addr, 0)) == CONST_INT) + { + scale = INTVAL (XEXP (addr, 0)); + ireg = XEXP (addr, 1); + } + else + { + scale = INTVAL (XEXP (addr, 1)); + ireg = XEXP (addr, 0); + } + output_addr_const (file, const0_rtx); + PRINT_B_I_S ((rtx) 0, ireg, scale, file); + } + break; + + default: + if (GET_CODE (addr) == CONST_INT + && INTVAL (addr) < 0x8000 + && INTVAL (addr) >= -0x8000) + fprintf (file, "%d", INTVAL (addr)); + else + output_addr_const (file, addr); + } +} + +/* Set the cc_status for the results of an insn whose pattern is EXP. + On the 80386, we assume that only test and compare insns, as well + as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT, + ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully. + Also, we assume that jumps and moves don't affect the condition codes. + All else, clobbers the condition codes, by assumption. + + We assume that ALL add, minus, etc. instructions effect the condition + codes. This MUST be consistent with i386.md. */ + +notice_update_cc (exp) + rtx exp; +{ + if (GET_CODE (exp) == SET) + { + /* Jumps do not alter the cc's. */ + if (SET_DEST (exp) == pc_rtx) + return; + /* Moving register or memory into a register: + it doesn't alter the cc's, but it might invalidate + the RTX's which we remember the cc's came from. + (Note that moving a constant 0 or 1 MAY set the cc's). */ + if (REG_P (SET_DEST (exp)) + && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM)) + { + if (cc_status.value1 + && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) + cc_status.value1 = 0; + if (cc_status.value2 + && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) + cc_status.value2 = 0; + return; + } + /* Moving register into memory doesn't alter the cc's. + It may invalidate the RTX's which we remember the cc's came from. */ + if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp))) + { + if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM) + cc_status.value1 = 0; + if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM) + cc_status.value2 = 0; + return; + } + /* Function calls clobber the cc's. */ + else if (GET_CODE (SET_SRC (exp)) == CALL) + { + CC_STATUS_INIT; + return; + } + /* Tests and compares set the cc's in predictable ways. */ + else if (SET_DEST (exp) == cc0_rtx) + { + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (exp); + return; + } + /* Certain instructions effect the condition codes. */ + else if (GET_MODE (SET_SRC (exp)) == SImode + || GET_MODE (SET_SRC (exp)) == HImode + || GET_MODE (SET_SRC (exp)) == QImode) + switch (GET_CODE (SET_SRC (exp))) + { + case ASHIFTRT: case LSHIFTRT: + case ASHIFT: case LSHIFT: + /* Shifts on the 386 don't set the condition codes if the + shift count is zero. */ + if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT) + { + CC_STATUS_INIT; + break; + } + /* We assume that the CONST_INT is non-zero (this rtx would + have been deleted if it were zero. */ + + case PLUS: case MINUS: case NEG: + case AND: case IOR: case XOR: + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_SRC (exp); + cc_status.value2 = SET_DEST (exp); + break; + + default: + CC_STATUS_INIT; + } + else + { + CC_STATUS_INIT; + } + } + else if (GET_CODE (exp) == PARALLEL + && GET_CODE (XVECEXP (exp, 0, 0)) == SET) + { + if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) + return; + if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) + { + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); + return; + } + CC_STATUS_INIT; + } + else + { + CC_STATUS_INIT; + } +} + +/* Nonzero if the top of the fpu stack dies in this insn. */ + +int +top_dead_p (insn) + rtx insn; +{ + extern int optimize; + if (optimize) + return (find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG) + || find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG + 1)); + + if (GET_CODE (insn) == CALL_INSN) + return call_top_dead_p (insn); + + return fp_top_dead_p1 (insn); +} + +/* Following is used after a call_value insn + if obey_regdecls there will not be the REG_DEAD notes + to go by (there won't be any cross jumping to worry about + either), and we depend on seeing if the FP_TOP is used + in the next two insn's. Otherwise we depend on the + REG_DEAD notes. + */ + +static int +call_top_dead_p (insn) + rtx insn; +{ + int i; + for (i = 0; i < 3; i++) + { + insn = NEXT_INSN (insn); + if (insn == 0) + return 1; + if (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL) + continue; + if (GET_CODE (insn) == BARRIER) + abort (); + if (GET_CODE (PATTERN (insn)) == SET + && SET_DEST (PATTERN (insn)) != stack_pointer_rtx) + return (!(mentions_fp_top (SET_SRC (PATTERN (insn))))); + if (GET_CODE (PATTERN (insn)) == CALL) + return 1; + if (GET_CODE (PATTERN (insn)) == USE) + return (! FP_REG_P (XEXP (PATTERN (insn), 0))); + } + return 1; +} + +/* Return 1 if current val of fpu top-of-stack appears unused + in rest of this basic block and also through a jump insn. + This is called from top_dead_p and from fp_call_internal. */ + +static int +fp_top_dead_p1 (insn) + rtx insn; +{ + extern int optimize; + + int past_jump = 0; + + for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) + { + switch (GET_CODE (insn)) + { + case CALL_INSN: + /* Function calls clobber this value, so it's dead. */ + return 1; + + case JUMP_INSN: + /* Follow one jump in case of cross-jumping, + which could insert such a jump into one basic block. */ + if (! optimize) + /* Can't use JUMP_LABEL, but there's no cross-jumping either. */ + return 1; + if (JUMP_LABEL (insn) == 0) + return 1; + /* Don't scan past a jump and another jump. */ + if (past_jump) + return 1; + past_jump = 1; + insn = JUMP_LABEL (insn); + case CODE_LABEL: + if (! optimize) + return 1; + break; + + case INSN: + if (GET_CODE (PATTERN (insn)) == SET) + { + if ((mentions_fp_top (SET_SRC (PATTERN (insn))))) + return 0; + else if (mentions_fp_top (SET_DEST (PATTERN (insn)))) + return 1; + } + else if (mentions_fp_top (PATTERN (insn))) + return 0; + break; + } + } + return 1; +} + +/* Return 1 if X involves an FPU register. */ + +static int +mentions_fp_top (x) + rtx x; +{ + register RTX_CODE code; + + code = GET_CODE (x); + switch (code) + { + case LABEL_REF: + case SYMBOL_REF: + case CONST_INT: + case CONST: + case CC0: + case PC: + case CLOBBER: + case MEM: + return 0; + + case REG: + return FP_REGNO_P (REGNO (x)); + } + + /* Recursively scan the operands of this expression. */ + { + register char *fmt = GET_RTX_FORMAT (code); + register int i; + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (mentions_fp_top (XEXP (x, i))) + return 1; + } + if (fmt[i] == 'E') + { + register int j; + for (j = 0; j < XVECLEN (x, i); j++) + if (mentions_fp_top (XVECEXP (x, i, j))) + return 1; + } + } + } + return 0; +} + +/* Some asm-dependent functions. */ + +#ifdef MASM +#include "masm386.c" +#endif diff --git a/gcc-1.40/config/out-i860.c b/gcc-1.40/config/out-i860.c new file mode 100644 index 0000000..f531810 --- /dev/null +++ b/gcc-1.40/config/out-i860.c @@ -0,0 +1,1507 @@ +/* Subroutines for insn-output.c for Intel 860 + Copyright (C) 1989 Free Software Foundation, Inc. + Derived from out-sparc.c. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Global variables for machine-dependend things. */ + +/* This should go away if we pass floats to regs via + the stack instead of the frame, and if we learn how + to renumber all the registers when we don't do a save (hard!). */ +extern int frame_pointer_needed; + +static rtx find_addr_reg (); + +/* Return non-zero only if OP is a register of mode MODE, + or const0_rtx. */ +int +reg_or_0_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (op == const0_rtx || register_operand (op, mode) + || op == CONST0_RTX (mode)); +} + +/* Return non-zero if this pattern, can be evaluated safely, even if it + was not asked for. */ +int +safe_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + /* Just experimenting. */ + + /* No floating point src is safe if it contains an arithmetic + operation, since that operation may trap. */ + switch (GET_CODE (op)) + { + case CONST_INT: + case LABEL_REF: + case SYMBOL_REF: + case CONST: + return 1; + + case REG: + return 1; + + case MEM: + return CONSTANT_ADDRESS_P (XEXP (op, 0)); + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != SFmode && mode != DFmode); + case NOT: + case ZERO_EXTEND: + return 1; + + case EQ: + case NE: + case LT: + case GT: + case LE: + case GE: + case LTU: + case GTU: + case LEU: + case GEU: + case MINUS: + case PLUS: + return (mode != SFmode && mode != DFmode); + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + default: + return 0; + } +} + +/* Return 1 if REG is clobbered in IN. + Return 2 if REG is used in IN. + Return 3 if REG is both used and clobbered in IN. + Return 0 if neither. */ + +static int +reg_clobbered_p (reg, in) + rtx reg; + rtx in; +{ + register enum rtx_code code; + + if (in == 0) + return 0; + + code = GET_CODE (in); + + if (code == SET || code == CLOBBER) + { + rtx dest = SET_DEST (in); + int set = 0; + int used = 0; + + while (GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == SUBREG + || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + + if (dest == reg) + set = 1; + else if (GET_CODE (dest) == REG + && refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_DEST (in), 0)) + { + set = 1; + /* Anything that sets just part of the register + is considered using as well as setting it. + But note that a straight SUBREG of a single-word value + clobbers the entire value. */ + if (dest != SET_DEST (in) + && ! (GET_CODE (SET_DEST (in)) == SUBREG + || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest)))) + used = 1; + } + + if (code == SET) + { + if (set) + used = refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_SRC (in), 0); + else + used = refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + in, 0); + } + + return set + used * 2; + } + + if (refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + in, 0)) + return 2; + return 0; +} + +/* Return non-zero if OP can be written to without screwing up + GCC's model of what's going on. It is assumed that this operand + appears in the dest position of a SET insn in a conditional + branch's delay slot. AFTER is the label to start looking from. */ +int +operand_clobbered_before_used_after (op, after) + rtx op; + rtx after; +{ + extern char call_used_regs[]; + + /* Just experimenting. */ + if (GET_CODE (op) == CC0) + return 1; + if (GET_CODE (op) == REG) + { + rtx insn; + + if (op == stack_pointer_rtx) + return 0; + + /* Scan forward from the label, to see if the value of OP + is clobbered before the first use. */ + + for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == NOTE) + continue; + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + switch (reg_clobbered_p (op, PATTERN (insn))) + { + default: + return 0; + case 1: + return 1; + case 0: + break; + } + } + /* If we reach another label without clobbering OP, + then we cannot safely write it here. */ + else if (GET_CODE (insn) == CODE_LABEL) + return 0; + if (GET_CODE (insn) == JUMP_INSN) + { + if (condjump_p (insn)) + return 0; + /* This is a jump insn which has already + been mangled. We can't tell what it does. */ + if (GET_CODE (PATTERN (insn)) == PARALLEL) + return 0; + if (! JUMP_LABEL (insn)) + return 0; + /* Keep following jumps. */ + insn = JUMP_LABEL (insn); + } + } + return 1; + } + + /* In both of these cases, the first insn executed + for this op will be a orh whatever%h,r0,r31, + which is tolerable. */ + if (GET_CODE (op) == MEM) + return (CONSTANT_ADDRESS_P (XEXP (op, 0))); + + return 0; +} + +/* Return non-zero if this pattern, as a source to a "SET", + is known to yield an instruction of unit size. */ +int +single_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case CONST_INT: + /* This is not always a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; + + case SYMBOL_REF: + case CONST: + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; + + case REG: + return 1; + + case MEM: + return 1; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + case ZERO_EXTEND: + return 1; + + case PLUS: + case MINUS: + /* Detect cases that require multiple instructions. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && SMALL_INT (XEXP (op, 1)))) + return 0; + case EQ: + case NE: + case LT: + case GT: + case LE: + case GE: + case LTU: + case GTU: + case LEU: + case GEU: + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + return (mode != SFmode && mode != DFmode); + + case AND: + if (GET_CODE (XEXP (op, 1)) == NOT) + { + rtx arg = XEXP (XEXP (op, 1), 0); + if (CONSTANT_P (arg) + && !(GET_CODE (arg) == CONST_INT + && (SMALL_INT (arg) + || INTVAL (arg) & 0xffff == 0))) + return 0; + } + case IOR: + case XOR: + /* Both small and round numbers take one instruction; + others take two. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && (SMALL_INT (XEXP (op, 1)) + || INTVAL (XEXP (op, 1)) & 0xffff == 0))) + return 0; + + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return single_insn_src_p (SUBREG_REG (op), mode); + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* Nonzero only if this *really* is a single insn operand. */ +int +strict_single_insn_op_p (op, mode) + rtx op; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + switch (GET_CODE (op)) + { + case CC0: + return 1; + + case CONST_INT: + if (SMALL_INT (op)) + return 1; + /* We can put this set insn into delay slot, because this is one + insn; 'sethi'. */ + if ((INTVAL (op) & 0x3ff) == 0) + return 1; + return 0; + + case SYMBOL_REF: + return 0; + + case REG: +#if 0 + /* This loses when moving an freg to a general reg. */ + return HARD_REGNO_NREGS (REGNO (op), mode) == 1; +#endif + return (mode != DFmode && mode != DImode); + + case MEM: + if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) + return (mode != DFmode && mode != DImode); + return 0; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + case ZERO_EXTEND: + return 1; + + case PLUS: + case MINUS: + /* Detect cases that require multiple instructions. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && SMALL_INT (XEXP (op, 1)))) + return 0; + case EQ: + case NE: + case LT: + case GT: + case LE: + case GE: + case LTU: + case GTU: + case LEU: + case GEU: + return 1; + + case AND: + if (GET_CODE (XEXP (op, 1)) == NOT) + { + rtx arg = XEXP (XEXP (op, 1), 0); + if (CONSTANT_P (arg) + && !(GET_CODE (arg) == CONST_INT + && (SMALL_INT (arg) + || INTVAL (arg) & 0xffff == 0))) + return 0; + } + case IOR: + case XOR: + /* Both small and round numbers take one instruction; + others take two. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && (SMALL_INT (XEXP (op, 1)) + || INTVAL (XEXP (op, 1)) & 0xffff == 0))) + return 0; + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return strict_single_insn_op_p (SUBREG_REG (op), mode); + + case SIGN_EXTEND: + if (GET_CODE (XEXP (op, 0)) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) + return 1; + return 0; + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* Return truth value of whether OP is a relational operator. */ +int +relop (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case GTU: + case GEU: + case LTU: + case LEU: + return 1; + } + return 0; +} + +/* Return truth value of whether OP can be used as an operands in a three + address add/subtract insn (such as add %o1,7,%l2) of mode MODE. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); +} + +/* Return 1 if OP is a valid first operand for a logical insn of mode MODE. */ + +int +logic_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && LOGIC_INT (op))); +} + +/* Return 1 if OP is a valid first operand for either a logical insn + or an add insn of mode MODE. */ + +int +compare_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op))); +} + +/* Return truth value of whether OP can be used as an operand + of a bte insn. */ + +int +bte_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (unsigned) INTVAL (op) < 0x20)); +} + +/* Return 1 if OP is an indexed memory reference of mode MODE. */ + +int +indexed_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == MEM && GET_MODE (op) == mode + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_MODE (XEXP (op, 0)) == SImode + && register_operand (XEXP (XEXP (op, 0), 0), SImode) + && register_operand (XEXP (XEXP (op, 0), 1), SImode)); +} + +/* Return 1 if OP is a suitable source operand for a load insn + with mode MODE. */ + +int +load_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (memory_operand (op, mode) || indexed_operand (op, mode)); +} + +/* Return truth value of whether OP is a integer which fits the + range constraining immediate operands in add/subtract insns. */ + +int +small_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); +} + +/* Return truth value of whether OP is a integer which fits the + range constraining immediate operands in logic insns. */ + +int +logic_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && LOGIC_INT (op)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[1]) != MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("orh ha%%%m0,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + return "st.l %r1,l%%%m0(r31)"; + } + else + return "st.l %r1,%0"; + else + abort (); +#if 0 + { + rtx xoperands[2]; + + cc_status.flags &= ~CC_F0_IS_0; + xoperands[0] = gen_rtx (REG, SFmode, 32); + xoperands[1] = operands[1]; + output_asm_insn (singlemove_string (xoperands), xoperands); + xoperands[1] = xoperands[0]; + xoperands[0] = operands[0]; + output_asm_insn (singlemove_string (xoperands), xoperands); + return ""; + } +#endif + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("orh ha%%%m1,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return "ld.l l%%%m1(r31),%0"; + } + return "ld.l %1,%0"; + } + return "mov %1,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + +/* ??? Perhaps in some cases move double words + if there is a spare pair of floating regs. */ + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. + + RMS says "This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance." + + but it happens on the sparc when loading parameter registers, + so I am going to define that circumstance, and make it work + as expected. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("adds 0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds 0x4,%0,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("adds -0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds -0x4,%0,%0", &addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + /* Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("adds 0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds 0x4,%0,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("adds -0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds -0x4,%0,%0", &addreg1); + + return ""; +} + +static char * +output_fp_move_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return "fmov.dd %1,%0"; + if (GET_CODE (operands[1]) == REG) + { + output_asm_insn ("ixfr %1,%0", operands); + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + return "ixfr %1,%0"; + } + if (operands[1] == dconst0_rtx) + return "fmov.dd f0,%0"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("orh ha%%%m1,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return "fld.d l%%%m1(r31),%0"; + } + return "fld.d %1,%0"; + } + else if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + output_asm_insn ("fxfr %1,%0", operands); + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + return "fxfr %1,%0"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("orh ha%%%m0,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + return "fst.d %1,l%%%m0(r31)"; + } + return "fst.d %1,%0"; + } + else abort (); +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +/* Return a template for a load instruction with mode MODE and + arguments from the string ARGS. + + This string is in static storage. */ + +static char * +load_opcode (mode, args, reg) + enum machine_mode mode; + char *args; + rtx reg; +{ + static char buf[30]; + char *opcode; + + switch (mode) + { + case QImode: + opcode = "ld.b"; + break; + + case HImode: + opcode = "ld.s"; + break; + + case SImode: + case SFmode: + if (FP_REG_P (reg)) + opcode = "fld.l"; + else + opcode = "ld.l"; + break; + + case DImode: + if (!FP_REG_P (reg)) + abort (); + case DFmode: + opcode = "fld.d"; + break; + + default: + abort (); + } + + sprintf (buf, "%s %s", opcode, args); + return buf; +} + +/* Return a template for a store instruction with mode MODE and + arguments from the string ARGS. + + This string is in static storage. */ + +static char * +store_opcode (mode, args, reg) + enum machine_mode mode; + char *args; + rtx reg; +{ + static char buf[30]; + char *opcode; + + switch (mode) + { + case QImode: + opcode = "st.b"; + break; + + case HImode: + opcode = "st.s"; + break; + + case SImode: + case SFmode: + if (FP_REG_P (reg)) + opcode = "fst.l"; + else + opcode = "st.l"; + break; + + case DImode: + if (!FP_REG_P (reg)) + abort (); + case DFmode: + opcode = "fst.d"; + break; + + default: + abort (); + } + + sprintf (buf, "%s %s", opcode, args); + return buf; +} + +/* Output a store-in-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. + + This function returns a template for an insn. + This is in static storage. + + It may also output some insns directly. + It may alter the values of operands[0] and operands[1]. */ + +char * +output_store (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[0], 0); + char *string; + + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && address == cc_prev_status.mdep)) + { + output_asm_insn ("orh ha%%%m0,r0,r31", operands); + cc_prev_status.mdep = address; + } + + /* Store zero in two parts when appropriate. */ + if (mode == DFmode && operands[1] == dconst0_rtx) + return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]); + + /* Code below isn't smart enough to move a doubleword in two parts, + so use output_move_double to do that in the cases that require it. */ + if ((mode == DImode || mode == DFmode) + && ! FP_REG_P (operands[1])) + return output_move_double (operands); + + return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]); +} + +/* Output a load-from-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a reg, and OPERANDS[1] is a mem. + + This function returns a template for an insn. + This is in static storage. + + It may also output some insns directly. + It may alter the values of operands[0] and operands[1]. */ + +char * +output_load (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[1], 0); + + /* We don't bother trying to see if we know %hi(address). + This is because we are doing a load, and if we know the + %hi value, we probably also know that value in memory. */ + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && address == cc_prev_status.mdep + && cc_prev_status.mdep == cc_status.mdep)) + { + output_asm_insn ("orh ha%%%m1,r0,r31", operands); + cc_prev_status.mdep = address; + } + + /* Code below isn't smart enough to move a doubleword in two parts, + so use output_move_double to do that in the cases that require it. */ + if ((mode == DImode || mode == DFmode) + && ! FP_REG_P (operands[0])) + return output_move_double (operands); + + return load_opcode (mode, "l%%%m1(r31),%0", operands[0]); +} + +/* Load the address specified by OPERANDS[3] into the register + specified by OPERANDS[0]. + + OPERANDS[3] may be the result of a sum, hence it could either be: + + (1) CONST + (2) REG + (2) REG + CONST_INT + (3) REG + REG + CONST_INT + (4) REG + REG (special case of 3). + + Note that (3) is not a legitimate address. + All cases are handled here. */ + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("mov %3,%0", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("mov %3,%0", operands); + return; + } + + if (GET_CODE (operands[3]) != PLUS) + abort (); + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + { + /* Operand is (PLUS (REG) (REG)). */ + base = operands[3]; + offset = const0_rtx; + } + + if (REG_P (base)) + { + operands[6] = base; + operands[7] = offset; + if (SMALL_INT (offset)) + output_asm_insn ("adds %7,%6,%0", operands); + else + output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands); + } + else if (GET_CODE (base) == PLUS) + { + operands[6] = XEXP (base, 0); + operands[7] = XEXP (base, 1); + operands[8] = offset; + + if (SMALL_INT (offset)) + output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands); + else + output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands); + } + else + abort (); +} + +/* Output code to place a size count SIZE in register REG. */ + +static void +output_size_for_block_move (size, reg, align) + rtx size, reg, align; +{ + rtx xoperands[3]; + + xoperands[0] = reg; + xoperands[1] = size; + xoperands[2] = align; + +#if 1 + cc_status.flags &= ~ CC_KNOW_HI_R31; + output_asm_insn ("mov %1,%0", xoperands); +#else + if (GET_CODE (size) == REG) + output_asm_insn ("sub %2,%1,%0", xoperands); + else + { + xoperands[1] + = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); + cc_status.flags &= ~ CC_KNOW_HI_R31; + output_asm_insn ("mov %1,%0", xoperands); + } +#endif +} + +/* Emit code to perform a block move. + + OPERANDS[0] is the destination. + OPERANDS[1] is the source. + OPERANDS[2] is the size. + OPERANDS[3] is the known safe alignment. + OPERANDS[4..6] are pseudos we can safely clobber as temps. */ + +char * +output_block_move (operands) + rtx *operands; +{ + /* A vector for our computed operands. Note that load_output_address + makes use of (and can clobber) up to the 8th element of this vector. */ + rtx xoperands[10]; + rtx zoperands[10]; + static int movstrsi_label = 0; + int i, j; + rtx temp1 = operands[4]; + rtx alignrtx = operands[3]; + int align = INTVAL (alignrtx); + + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = temp1; + + /* We can't move more than four bytes at a time + because we have only one register to move them through. */ + if (align > 4) + { + align = 4; + alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); + } + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Recognize special cases of block moves. These occur + when GNU C++ is forced to treat something as BLKmode + to keep it in memory, when its mode could be represented + with something smaller. + + We cannot do this for global variables, since we don't know + what pages they don't cross. Sigh. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) <= 16 + && ! CONSTANT_ADDRESS_P (operands[0]) + && ! CONSTANT_ADDRESS_P (operands[1])) + { + int size = INTVAL (operands[2]); + rtx op0 = xoperands[0]; + rtx op1 = xoperands[1]; + + cc_status.flags &= ~CC_KNOW_HI_R31; + if (align == 1) + { + if (memory_address_p (QImode, plus_constant (op0, size)) + && memory_address_p (QImode, plus_constant (op1, size))) + { + for (i = size-1; i >= 0; i--) + { + xoperands[0] = plus_constant (op0, i); + xoperands[1] = plus_constant (op1, i); + output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0", + xoperands); + } + return ""; + } + } + else if (align == 2) + { + if (memory_address_p (HImode, plus_constant (op0, size)) + && memory_address_p (HImode, plus_constant (op1, size))) + { + for (i = (size>>1)-1; i >= 0; i--) + { + xoperands[0] = plus_constant (op0, i * 2); + xoperands[1] = plus_constant (op1, i * 2); + output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0", + xoperands); + } + return ""; + } + } + else + { + if (memory_address_p (SImode, plus_constant (op0, size)) + && memory_address_p (SImode, plus_constant (op1, size))) + { + for (i = (size>>2)-1; i >= 0; i--) + { + xoperands[0] = plus_constant (op0, i * 4); + xoperands[1] = plus_constant (op1, i * 4); + output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0", + xoperands); + } + return ""; + } + } + } + + /* This is the size of the transfer. + Either use the register which already contains the size, + or use a free register (used by no operands). */ + output_size_for_block_move (operands[2], operands[4], alignrtx); + +#if 0 + /* Also emit code to decrement the size value by ALIGN. */ + zoperands[0] = operands[0]; + zoperands[3] = plus_constant (operands[0], align); + output_load_address (zoperands); +#endif + + /* Generate number for unique label. */ + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + /* Copy the increment (negative) to a register for bla insn. */ + + xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align); + xoperands[5] = operands[5]; + output_asm_insn ("mov %4,%5", xoperands); + + /* Make available a register which is a temporary. */ + + xoperands[6] = operands[6]; + + /* Now the actual loop. + In xoperands, elements 1 and 0 are the input and output vectors. + Element 2 is the loop index. Element 5 is the increment. */ + + if (align == 1) + { + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + output_asm_insn ("adds %1,%2,%1", xoperands); + output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands); + output_asm_insn ("ld.b 0(%1),r31", xoperands); + output_asm_insn ("adds %5,%1,%1", xoperands); + output_asm_insn ("st.b r31,0(%6)", xoperands); + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %5,%6,%6", xoperands); + } + if (align == 2) + { + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + output_asm_insn ("adds %1,%2,%1", xoperands); + output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands); + output_asm_insn ("ld.s 0(%1),r31", xoperands); + output_asm_insn ("adds %5,%1,%1", xoperands); + output_asm_insn ("st.s r31,0(%6)", xoperands); + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %5,%6,%6", xoperands); + } + if (align == 4) + { + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + output_asm_insn ("adds %1,%2,%1", xoperands); + output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands); + output_asm_insn ("ld.l 0(%1),r31", xoperands); + output_asm_insn ("adds %5,%1,%1", xoperands); + output_asm_insn ("st.l r31,0(%6)", xoperands); + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %5,%6,%6", xoperands); + } + + return ""; +} + +/* Output a delayed branch insn with the delay insn in its + branch slot. The delayed branch insn template is in TEMPLATE, + with operands OPERANDS. The insn in its delay slot is INSN. + + As a special case, since we know that all memory transfers are via + ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory + reference around the branch as + + orh ha%x,r0,r31 + b ... + ld/st l%x(r31),... + + As another special case, we handle loading (SYMBOL_REF ...) and + other large constants around branches as well: + + orh h%x,r0,%0 + b ... + or l%x,%0,%1 + + */ + +char * +output_delayed_branch (template, operands, insn) + char *template; + rtx *operands; + rtx insn; +{ + extern rtx recog_operand[]; + rtx src = XVECEXP (PATTERN (insn), 0, 1); + rtx dest = XVECEXP (PATTERN (insn), 0, 0); + + if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST + || (GET_CODE (src) == CONST_INT + && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0))) + { + rtx xoperands[2]; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `orh' insn. */ + output_asm_insn ("orh h%%%1,r0,%0", xoperands); + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the `or' insn. */ + output_asm_insn ("or l%%%1,%0,%0", xoperands); + } + else if ((GET_CODE (src) == MEM + && CONSTANT_ADDRESS_P (XEXP (src, 0))) + || (GET_CODE (dest) == MEM + && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) + { + rtx xoperands[2]; + char *split_template; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `orh' insn. */ + if (GET_CODE (src) == MEM) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("orh ha%%%m1,r0,r31", xoperands); + split_template = load_opcode (GET_MODE (dest), + "l%%%m1(r31),%0", dest); + } + else + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("orh ha%%%m0,r0,r31", xoperands); + split_template = store_opcode (GET_MODE (dest), + "%r1,l%%%m0(r31)", src); + } + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the load or store. + No need to do a CC_STATUS_INIT, because we are branching anyway. */ + output_asm_insn (split_template, xoperands); + } + else + { + extern char *insn_template[]; + extern char *(*insn_outfun[])(); + extern int insn_n_operands[]; + extern rtx alter_subreg(); + int insn_code_number; + rtx pat = gen_rtx (SET, VOIDmode, dest, src); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + int i; + + /* Output the branch instruction first. */ + output_asm_insn (template, operands); + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog (pat, delay_insn); + if (insn_code_number == -1) + abort (); + + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + + /* Now get the template for what this insn would + have been, without the branch. Its operands are + exactly the same as they would be, so we don't + need to do an insn_extract. */ + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + } + CC_STATUS_INIT; + return ""; +} + +/* Output a newly constructed insn DELAY_INSN. */ +char * +output_delay_insn (delay_insn) + rtx delay_insn; +{ + char *template; + extern rtx recog_operand[]; + extern char call_used_regs[]; + extern char *insn_template[]; + extern int insn_n_operands[]; + extern char *(*insn_outfun[])(); + extern rtx alter_subreg(); + int insn_code_number; + extern int insn_n_operands[]; + int i; + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog_memoized (delay_insn); + if (insn_code_number == -1) + abort (); + + /* Extract the operands of this delay insn. */ + INSN_CODE (delay_insn) = insn_code_number; + insn_extract (delay_insn); + + /* It is possible that this insn has not been properly scaned by final + yet. If this insn's operands don't appear in the peephole's + actual operands, then they won't be fixed up by final, so we + make sure they get fixed up here. -- This is a kludge. */ + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + +#ifdef REGISTER_CONSTRAINTS + if (! constrain_operands (insn_code_number)) + abort (); +#endif + + cc_prev_status = cc_status; + + /* Update `cc_status' for this instruction. + The instruction's output routine may change it further. + If the output routine for a jump insn needs to depend + on the cc status, it should look at cc_prev_status. */ + + NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); + + /* Now get the template for what this insn would + have been, without the branch. */ + + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + return ""; +} diff --git a/gcc-1.40/config/out-m68k.c b/gcc-1.40/config/out-m68k.c new file mode 100644 index 0000000..1f05125 --- /dev/null +++ b/gcc-1.40/config/out-m68k.c @@ -0,0 +1,560 @@ +/* Subroutines for insn-output.c for Motorola 68000 family. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Some output-actions in m68k.md need these. */ +#include <stdio.h> +extern FILE *asm_out_file; + +/* Index into this array by (register number >> 3) to find the + smallest class which contains that register. */ +enum reg_class regno_reg_class[] + = { DATA_REGS, ADDR_REGS, FP_REGS, + LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS }; + +static rtx find_addr_reg (); + +char * +output_btst (operands, countop, dataop, insn, signpos) + rtx *operands; + rtx countop, dataop; + rtx insn; + int signpos; +{ + operands[0] = countop; + operands[1] = dataop; + + if (GET_CODE (countop) == CONST_INT) + { + register int count = INTVAL (countop); + /* If COUNT is bigger than size of storage unit in use, + advance to the containing unit of same size. */ + if (count > signpos) + { + int offset = (count & ~signpos) / 8; + count = count & signpos; + operands[1] = dataop = adj_offsettable_operand (dataop, offset); + } + if (count == signpos) + cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; + else + cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; + + if (count == 31 + && next_insns_test_no_inequality (insn)) + return "tst%.l %1"; + if (count == 15 + && next_insns_test_no_inequality (insn)) + return "tst%.w %1"; + if (count == 7 + && next_insns_test_no_inequality (insn)) + return "tst%.b %1"; + + cc_status.flags = CC_NOT_NEGATIVE; + } + return "btst %0,%1"; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) + return "fpmoves %1,%0"; + if (operands[1] != const0_rtx) + return "move%.l %1,%0"; + if (! ADDRESS_REG_P (operands[0])) + return "clr%.l %0"; + return "sub%.l %0,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + output_asm_insn ("subq%.l %#8,%0", operands); + operands[0] = gen_rtx (MEM, DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + output_asm_insn ("subq%.l %#8,%1", operands); + operands[1] = gen_rtx (MEM, DImode, operands[1]); + optype1 = OFFSOP; + } + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { +#ifndef HOST_WORDS_BIG_ENDIAN + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); +#else /* HOST_WORDS_BIG_ENDIAN */ + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); +#endif /* HOST_WORDS_BIG_ENDIAN */ + } + } + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N(sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1]))) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + return ""; +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +/* Test for -0.0. */ + +int +double_is_minus_zero (arg) + double arg; +{ + union { double d; int i[2];} u; + + u.d = arg; + return (u.i[1] == 0 && u.i[0] == 0x80000000); +} + +char * +output_move_const_double (operands) + rtx *operands; +{ + if (TARGET_FPA && FPA_REG_P(operands[0])) + { + int code = standard_sun_fpa_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff); + return buf; + } + return "fpmove%.d %1,%0"; + } + else + { + int code = standard_68881_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); + return buf; + } + return "fmove%.d %1,%0"; + } +} + +char * +output_move_const_single (operands) + rtx *operands; +{ + if (TARGET_FPA) + { + int code = standard_sun_fpa_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff); + return buf; + } + return "fpmove%.s %1,%0"; + } + else + { + int code = standard_68881_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); + return buf; + } + return "fmove%.s %f1,%0"; + } +} + +/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get + from the "fmovecr" instruction. + The value, anded with 0xff, gives the code to use in fmovecr + to get the desired constant. */ + +int +standard_68881_constant_p (x) + rtx x; +{ + union {double d; int i[2];} u; + register double d; + +#ifdef HOST_WORDS_BIG_ENDIAN + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); +#else + u.i[0] = CONST_DOUBLE_HIGH (x); + u.i[1] = CONST_DOUBLE_LOW (x); +#endif + d = u.d; + + if (d == 0) + return 0x0f; + /* Note: there are various other constants available + but it is a nuisance to put in their values here. */ + if (d == 1) + return 0x32; + if (d == 10) + return 0x33; + if (d == 100) + return 0x34; + if (d == 10000) + return 0x35; + if (d == 1e8) + return 0x36; + if (GET_MODE (x) == SFmode) + return 0; + if (d == 1e16) + return 0x37; + /* larger powers of ten in the constants ram are not used + because they are not equal to a `double' C constant. */ + return 0; +} + +/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get + from the Sun FPA's constant RAM. + The value returned, anded with 0x1ff, gives the code to use in fpmove + to get the desired constant. */ +#define S_E (2.718281745910644531) +#define D_E (2.718281828459045091) +#define S_PI (3.141592741012573242) +#define D_PI (3.141592653589793116) +#define S_SQRT2 (1.414213538169860840) +#define D_SQRT2 (1.414213562373095145) +#define S_LOG2ofE (1.442695021629333496) +#define D_LOG2ofE (1.442695040888963387) +#define S_LOG2of10 (3.321928024291992188) +#define D_LOG2of10 (3.321928024887362182) +#define S_LOGEof2 (0.6931471824645996094) +#define D_LOGEof2 (0.6931471805599452862) +#define S_LOGEof10 (2.302585124969482442) +#define D_LOGEof10 (2.302585092994045901) +#define S_LOG10of2 (0.3010300099849700928) +#define D_LOG10of2 (0.3010299956639811980) +#define S_LOG10ofE (0.4342944920063018799) +#define D_LOG10ofE (0.4342944819032518167) + +int +standard_sun_fpa_constant_p (x) + rtx x; +{ + union {double d; int i[2];} u; + register double d; + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); + d = u.d; + + if (d == 0.0) + return 0x200; /* 0 once 0x1ff is anded with it */ + if (d == 1.0) + return 0xe; + if (d == 0.5) + return 0xf; + if (d == -1.0) + return 0x10; + if (d == 2.0) + return 0x11; + if (d == 3.0) + return 0xB1; + if (d == 4.0) + return 0x12; + if (d == 8.0) + return 0x13; + if (d == 0.25) + return 0x15; + if (d == 0.125) + return 0x16; + if (d == 10.0) + return 0x17; + if (d == -(1.0/2.0)) + return 0x2E; + +/* + * Stuff that looks different if it's single or double + */ + if (GET_MODE(x) == SFmode) + { + if (d == S_E) + return 0x8; + if (d == (2*S_PI)) + return 0x9; + if (d == S_PI) + return 0xA; + if (d == (S_PI / 2.0)) + return 0xB; + if (d == S_SQRT2) + return 0xC; + if (d == (1.0 / S_SQRT2)) + return 0xD; + /* Large powers of 10 in the constant + ram are not used because they are + not equal to a C double constant */ + if (d == -(S_PI / 2.0)) + return 0x27; + if (d == S_LOG2ofE) + return 0x28; + if (d == S_LOG2of10) + return 0x29; + if (d == S_LOGEof2) + return 0x2A; + if (d == S_LOGEof10) + return 0x2B; + if (d == S_LOG10of2) + return 0x2C; + if (d == S_LOG10ofE) + return 0x2D; + } + else + { + if (d == D_E) + return 0x8; + if (d == (2*D_PI)) + return 0x9; + if (d == D_PI) + return 0xA; + if (d == (D_PI / 2.0)) + return 0xB; + if (d == D_SQRT2) + return 0xC; + if (d == (1.0 / D_SQRT2)) + return 0xD; + /* Large powers of 10 in the constant + ram are not used because they are + not equal to a C double constant */ + if (d == -(D_PI / 2.0)) + return 0x27; + if (d == D_LOG2ofE) + return 0x28; + if (d == D_LOG2of10) + return 0x29; + if (d == D_LOGEof2) + return 0x2A; + if (d == D_LOGEof10) + return 0x2B; + if (d == D_LOG10of2) + return 0x2C; + if (d == D_LOG10ofE) + return 0x2D; + } + return 0x0; +} + +#undef S_E +#undef D_E +#undef S_PI +#undef D_PI +#undef S_SQRT2 +#undef D_SQRT2 +#undef S_LOG2ofE +#undef D_LOG2ofE +#undef S_LOG2of10 +#undef D_LOG2of10 +#undef S_LOGEof2 +#undef D_LOGEof2 +#undef S_LOGEof10 +#undef D_LOGEof10 +#undef S_LOG10of2 +#undef D_LOG10of2 +#undef S_LOG10ofE +#undef D_LOG10ofE diff --git a/gcc-1.40/config/out-m88k.c b/gcc-1.40/config/out-m88k.c new file mode 100644 index 0000000..d02ac86 --- /dev/null +++ b/gcc-1.40/config/out-m88k.c @@ -0,0 +1,605 @@ +/* Subroutines for insn-output.c for Motorola 88000. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef FILE +#include <stdio.h> +#endif + +/* This is where the condition code register lives. */ +rtx cc0_reg_rtx; + +static rtx find_addr_reg (); + +#if 0 +char * +output_compare (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + if (GET_CODE (op1) == CONST_INT) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode); + return buf; +} + +char * +output_fcompare (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + if (GET_CODE (op1) == CONST_DOUBLE) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode); + return buf; +} + +char * +output_store (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + + if (GET_CODE (op1) == CONST_INT) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + + sprintf (buf, "cmp r25,%%1,%%2\n\textu %%0,r25,1<%s>", opcode); + return buf; +} +#endif + +/* Nonzero if OP is a valid second operand for an arithmetic insn. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (unsigned) INTVAL (op) < 0x10000)); +} + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +int +int5_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + return "st %r1,%0"; + if (GET_CODE (operands[1]) == MEM) + return "ld %0,%1"; + return "or %0,r0,%1"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (operands[0]); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (operands[1]); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("addu %0,%0,4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("subu %0,%0,4", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("addu %0,%0,4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("subu %0,%0,4", &addreg1); + + return ""; +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) == REG) + return addr; + return 0; +} + +/* Output an ascii string. */ +output_ascii (file, p, size) + FILE *file; + char *p; + int size; +{ + int i; + + fprintf (file, "\tstring \""); + + for (i = 0; i < size; i++) + { + register int c = p[i]; + if (c == '\"' || c == '\\') + putc ('\\', file); + if (c >= ' ' && c < 0177) + putc (c, file); + else + { + fprintf (file, "\\%03o", c); + /* After an octal-escape, if a digit follows, + terminate one string constant and start another. + The Vax assembler fails to stop reading the escape + after three digits, so this is the only way we + can get it to parse the data properly. */ + if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9') + fprintf (file, "\"\n\tstring \""); + } + } + fprintf (file, "\"\n"); +} + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("lda %0,%3", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("or %0,r0,%3", operands); + return; + } + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + abort (); + + operands[6] = base; + operands[7] = offset; + + if (REG_P (base)) + if (FITS_16_BITS (offset)) + output_asm_insn ("addu %0,%6,%7", operands); + else if (INT_FITS_16_BITS (- INTVAL (offset))) + output_asm_insn ("subu %0,%6,%7", operands); + else + output_asm_insn ("or.h %0,r0,hi16(%7)\n\tor %0,%0,lo16(%7)\n\tadd %0,%6,%0", operands); + else + { + if (GET_CODE (base) == MULT) + if (GET_MODE (base) == QImode) + output_asm_insn ("lda.b %0,%6"); + else if (GET_MODE (base) == HImode) + output_asm_insn ("lda.h %0,%6"); + else if (GET_MODE (base) == SImode) + output_asm_insn ("lda %0,%6"); + else + output_asm_insn ("lda.d %0,%6"); + else + output_asm_insn ("lda %0,%6"); + + if (FITS_16_BITS (offset)) + output_asm_insn ("addu %0,%7,%0", operands); + else if (INT_FITS_16_BITS (- INTVAL (offset))) + output_asm_insn ("subu %0,%7,%0", operands); + else + output_asm_insn ("or.h r25,r0,hi16(%7)\n\tor r25,r0,lo16(%7)\n\taddu %0,%0r25", operands); + } +} + +char * +output_block_move (operands) + rtx *operands; +{ + static int movstrsi_label = 0; + int align = 4; + + rtx xoperands[9]; + int available[3]; + int i, j; + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Get past the MEMs. */ + operands[0] = XEXP (operands[0], 0); + operands[1] = XEXP (operands[1], 0); + + xoperands[0] = 0; + xoperands[1] = 0; + xoperands[2] = 0; + + available[0] = 1; + available[1] = 1; + available[2] = 1; +#if 1 + /* Prepare to juggle registers if necessary. */ + if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 10) < 3) + { + xoperands[0] = operands[0]; + available[REGNO (operands[0]) - 10] = 0; + } + if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 10) < 3) + { + xoperands[1] = operands[1]; + available[REGNO (operands[1]) - 10] = 0; + } + if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 10) < 3) + { + xoperands[2] = operands[2]; + available[REGNO (operands[2]) - 10] = 0; + } + for (i = 0; i < 3; i++) + { + if (xoperands[i]) + continue; + if (available[0]) + { + xoperands[i] = gen_rtx (REG, SImode, 10); + available[0] = 0; + continue; + } + if (available[1]) + { + xoperands[i] = gen_rtx (REG, SImode, 11); + available[1] = 0; + continue; + } + xoperands[i] = gen_rtx (REG, SImode, 12); + available[2] = 0; + } +#endif + + /* First, figure out best alignment we may assume. */ + if (REG_P (operands[2])) + { + xoperands[5] = operands[2]; + output_asm_insn ("sub %5,%2,1", xoperands); + align = 1; + } + else + { + int i = INTVAL (operands[2]); + + if (i & 1) + align = 1; + else if (i & 3) + { + align = 2; + i >>= 1; + } + else + i >>= 2; + + /* predecrement count. */ + i -= 1; + if (i < 0) abort (); + + xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i); + + if (INT_FITS_16_BITS (i)) + output_asm_insn ("addu %2,r0,%5", xoperands); + else if (INT_FITS_16_BITS (-i)) + { + xoperands[5] = gen_rtx (CONST_INT, VOIDmode, -i); + output_asm_insn ("subu %2,r0,%5", xoperands); + } + else + output_asm_insn ("or.u %2,r0,hi16(%5)\n\tor %2,%2,lo16(%5)", xoperands); + } + /* Now, set up for pipelined operation: dest must contain + a pre-incremented address, because its index is pre-decremented. */ + + xoperands[3] = plus_constant (operands[0], align); + output_load_address (xoperands); + + xoperands[4] = operands[1]; + output_load_address (xoperands+1); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + if (align == 4) + output_asm_insn ("\n@Lm%3:\n\tld r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst r25,%0[%2]", xoperands); + else if (align == 2) + output_asm_insn ("\n@Lm%3:\n\tld.h r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.h r25,%0[%2]", xoperands); + else + output_asm_insn ("\n@Lm%3:\n\tld.b r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.b r25,%0[%2]", xoperands); + return ""; +} + +char * +output_store_const_int (mode, operands) + enum machine_mode mode; + rtx *operands; +{ + int i = INTVAL (operands[1]); + if (INT_FITS_16_BITS (i)) + return "addu %0,r0,%1"; + if (INT_FITS_16_BITS (-i)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, -i); + return "subu %0,r0,%1"; + } + if ((i & 0xffff) == 0) + return "or.u %0,r0,hi16(%1)"; + /* Could check to see if number is a contiguous field + of 1's. Then we could use the SET instruction. */ + if (mode == HImode) + { + warning ("truncating constant `%d' to fit in half-word", INTVAL (operands[1])); + return "or %0,r0,lo16(%1)"; + } + if (mode == QImode) + { + warning ("truncating constant `%d' to fit in byte"); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i & 0xff); + return "or %0,r0,%1"; + } + + return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)"; +} + +/* This routine assumes that floating point numbers are represented + in a manner which is consistent between host and target machines. */ +char * +output_store_const_float (mode, operands) + enum machine_mode mode; + rtx *operands; +{ + int i = INTVAL (operands[1]); + if (INT_FITS_16_BITS (i)) + return "addu %0,r0,%1"; + if (INT_FITS_16_BITS (-i)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, -i); + return "subu %0,r0,%1"; + } + if ((i & 0xffff) == 0) + return "or.u %0,r0,hi16(%1)"; + /* Could check to see if number is a contiguous field + of 1's. Then we could use the SET instruction. */ + return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)"; +} diff --git a/gcc-1.40/config/out-mips.c b/gcc-1.40/config/out-mips.c new file mode 100644 index 0000000..ab1dac0 --- /dev/null +++ b/gcc-1.40/config/out-mips.c @@ -0,0 +1,1086 @@ +/* Subroutines for insn-output.c for MIPS + Contributed by A. Lichnewsky, lich@inria.inria.fr. + Changes by Michael Meissner, meissner@osf.org. + Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include "tree.h" +#include "flags.h" + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +extern void debug_rtx (); +extern void abort_with_insn (); + +extern FILE *asm_out_file; +extern tree current_function_decl; + +/* Global variables for machine-dependent things. */ + +char *reg_numchar[] = REGISTER_NUMCHAR; + +/* Threshold for data being put into the small data/bss area, instead + of the normal data area (references to the small data/bss area take + 1 instruction, and use the global pointer, references to the normal + data area takes 2 instructions). */ +int mips_section_threshold = -1; + +/* Count the number of .file directives, so that .loc is up to date. */ +int num_source_filenames = 0; + +/* Count the number of words that are pushed to pass arguments. */ +int stack_args_pushed = 0; + +/* # bytes for args preallocated by function_prolog. */ +int stack_args_preallocated = 0; + +/* Count of the number of functions created so far, in order to make + unique labels for omitting the frame pointer. */ +int number_functions_processed = 0; + +/* Count the number of sdb related labels are generated (to find block + start and end boundaries). */ +int sdb_label_count = 0; + +/* Next label # for each statment for Silicon Graphics IRIS systems. */ +int sym_lineno = 0; + +/* Non-zero if inside of a function, because the stupid MIPS asm can't + handle .files inside of functions. */ +int inside_function = 0; + +/* String to be used for the unique name given to the difference between + the stack pointer and frame pointer when the frame pointer is to be + omitted. */ +char *sp_fp_difference = 0; + +/* Files to separate the text and the data output, so that all of the data + can be emitted before the text, which will mean that the assembler will + generate smaller code, based on the global pointer. */ +FILE *asm_out_data_file; +FILE *asm_out_text_file; + +/* Linked list of all externals that are to be emitted when optimizing + for the global pointer if they haven't been declared by the end of + the program with an appropriate .comm or initialization. */ + +struct extern_list { + struct extern_list *next; /* next external */ + char *name; /* name of the external */ + int size; /* size in bytes */ +} *extern_head = 0; + +/* Name of the current function. */ +char *current_function_name; + +/* Size of the frame allocated for this function. */ +int current_function_total_framesize; + +/* Number of bytes used to hold saved registers. */ +int current_function_saved_reg_size; + +/* Return truth value of whether OP can be used as an operands + where a register or 16 bit unsigned integer is needed. */ + +int +uns_arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))); +} + +/* Return truth value of whether OP can be used as an operands + where a 16 bit integer is needed */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); +} + +/* Return truth value of whether OP can be used as an operand in a two + address arithmetic insn (such as set 123456,%o4) of mode MODE. */ + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +/* Return truth value of whether OP is a integer which fits in 16 bits */ + +int +small_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); +} + + +/* Argument support functions. */ + +/* Initialize CUMULATIVE_ARGS for a function. */ + +void +init_cumulative_args (cum, fntype) + CUMULATIVE_ARGS cum; /* argument info to initialize */ + tree fntype; /* tree ptr for function decl */ +{ + tree param, next_param; + + if (TARGET_DEBUGE_MODE) + { + fprintf (stderr, "\ninit_cumulative_args\n"); + if (fntype != (tree)0) + { + putc ('\n', stderr); + debug_tree (fntype); + putc ('\n', stderr); + } + } + + cum->gp_reg_found = 0; + cum->arg_number = 0; + cum->arg_words = 0; + + /* Determine if this function has variable arguments. This is + indicated by the last argument being 'void_type_mode' if there + are no variable arguments. The standard MIPS calling sequence + passes all arguments in the general purpose registers in this + case. */ + + for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; + param != (tree)0; + param = next_param) + { + next_param = TREE_CHAIN (param); + if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) + cum->gp_reg_found = 1; + } + + /* Determine if the function is returning a structure, if so, + advance by one argument. */ + + if (fntype + && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE) + && TREE_TYPE (fntype) != 0) + { + tree ret_type = TREE_TYPE (fntype); + enum tree_code ret_code = TREE_CODE (ret_type); + + if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE) + { + cum->gp_reg_found = 1; + cum->arg_number = 1; + cum->arg_words = 1; + } + } +} + +/* Advance the argument to the next argument position. */ + +void +function_arg_advance (cum, mode, type, named) + CUMULATIVE_ARGS cum; /* current arg information */ + enum machine_mode mode; /* current arg mode */ + tree type; /* type of the argument or 0 if lib support */ +{ + if (TARGET_DEBUGE_MODE) + fprintf (stderr, + "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n", + cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), + type, named); + + cum->arg_number++; + switch (mode) + { + default: + error ("Illegal mode given to function_arg_advance"); + break; + + case VOIDmode: + break; + + case BLKmode: + cum->gp_reg_found = 1; + cum->arg_words += (int_size_in_bytes (type) + 3) / 4; + break; + + case SFmode: + cum->arg_words++; + break; + + case DFmode: + cum->arg_words += 2; + break; + + case DImode: + cum->gp_reg_found = 1; + cum->arg_words += 2; + break; + + case QImode: + case HImode: + case SImode: + cum->gp_reg_found = 1; + cum->arg_words++; + break; + } +} + +/* Return a RTL expression containing the register for the given mode, + or 0 if the argument is too be passed on the stack. */ + +struct rtx_def * +function_arg (cum, mode, type, named) + CUMULATIVE_ARGS cum; /* current arg information */ + enum machine_mode mode; /* current arg mode */ + tree type; /* type of the argument or 0 if lib support */ + int named; /* != 0 for normal args, == 0 for ... args */ +{ + int regbase = -1; + int bias = 0; + + if (TARGET_DEBUGE_MODE) + fprintf (stderr, + "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ", + cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), + type, named); + + switch (mode) + { + default: + error ("Illegal mode given to function_arg"); + break; + + case SFmode: + if (cum->gp_reg_found || cum->arg_number >= 2) + regbase = GP_ARG_FIRST; + else { + regbase = FP_ARG_FIRST; + if (cum->arg_words == 1) /* first arg was float */ + bias = 1; /* use correct reg */ + } + + break; + + case DFmode: + cum->arg_words += (cum->arg_words & 1); + regbase = (cum->gp_reg_found) ? GP_ARG_FIRST : FP_ARG_FIRST; + break; + + case VOIDmode: + case BLKmode: + case QImode: + case HImode: + case SImode: + case DImode: + regbase = GP_ARG_FIRST; + break; + } + + if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) + { + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "<stack>\n"); + + return 0; + } + + if (regbase == -1) + abort (); + + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "%s\n", reg_numchar[ regbase + cum->arg_number + bias ]); + + return gen_rtx (REG, mode, regbase + cum->arg_words + bias); +} + + +int +function_arg_partial_nregs (cum, mode, type, named) + CUMULATIVE_ARGS cum; /* current arg information */ + enum machine_mode mode; /* current arg mode */ + tree type; /* type of the argument or 0 if lib support */ + int named; /* != 0 for normal args, == 0 for ... args */ +{ + if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS) + { + int words = (int_size_in_bytes (type) + 3) / 4; + + if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS) + return 0; /* structure fits in registers */ + + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "function_arg_partial_nregs = %d\n", + MAX_ARGS_IN_REGISTERS - cum->arg_words); + + return MAX_ARGS_IN_REGISTERS - cum->arg_words; + } + + else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1) + { + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "function_arg_partial_nregs = 1\n"); + + return 1; + } + + return 0; +} + + +/* Routines to merge the compare and branch operators into a single entity. */ + +static rtx branch_cmp_op[2]; +static enum machine_mode branch_cmp_mode; + +/* Save the mode and operands on the current compare operator. */ + +void +compare_collect (mode, op0, op1) + enum machine_mode mode; + rtx op0; + rtx op1; +{ + if (TARGET_DEBUGD_MODE) + { + fprintf (stderr, "compare_collect mode = %s, operands::", + GET_MODE_NAME (mode)); + debug_rtx (op0); + debug_rtx (op1); + } + branch_cmp_op[0] = op0; + branch_cmp_op[1] = op1; + branch_cmp_mode = mode; +} + +/* Return the mode and operands saved with compare_collect for use + in a branch operator. */ + +void +compare_restore (operands, mode, insn) + rtx *operands; + enum machine_mode *mode; + rtx insn; +{ + if (!branch_cmp_op[0] || !branch_cmp_op[1]) + abort_with_insn (insn, "Compare_restore did not follow compare_collect"); + + if (TARGET_DEBUGD_MODE) + { + fprintf (stderr, + "compare_restore returning mode = %s, operands:%X,%X:", + GET_MODE_NAME (branch_cmp_mode), + branch_cmp_op[0], + branch_cmp_op[1]); + + debug_rtx (branch_cmp_op[0]); + debug_rtx (branch_cmp_op[1]); + } + + operands[0] = branch_cmp_op[0]; + operands[1] = branch_cmp_op[1]; + *mode = branch_cmp_mode; + + /* If the next insn is not a JUMP (after accounting for line numbers), + zero out the branch_cmp_array. Switch statements implemented as if's + tend to have multiple jumps. */ + do + { + insn = NEXT_INSN (insn); + } + while (insn && GET_CODE (insn) == NOTE); + + if (!insn || GET_CODE (insn) != JUMP_INSN) + { + branch_cmp_op[0] = NULL; + branch_cmp_op[1] = NULL; + branch_cmp_mode = VOIDmode; + } + +} + +/* Print the options used in the assembly file. */ + +static struct {char *name; int value;} target_switches [] + = TARGET_SWITCHES; + +void +print_options (out) + FILE *out; +{ + int line_len; + int len; + int j; + char **p; + int mask = TARGET_DEFAULT; + extern char **save_argv; + extern char *version_string, *language_string; + +#if 0 + /* Allow assembly language comparisons with -mdebug eliminating the + compiler version number and switch lists. */ + if (!TARGET_DEBUG_MODE) + { + fprintf (out, "\n # %s %s", language_string, version_string); +#ifdef TARGET_VERSION_INTERNAL + TARGET_VERSION_INTERNAL (out); +#endif +#ifdef __GNUC__ + fprintf (out, " compiled by GNU C\n\n"); +#else + fprintf (out, " compiled by CC\n\n"); +#endif + + fprintf (out, " # Cc1 defaults:"); + line_len = 32767; + for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++) + if (target_switches[j].name[0] != '\0' + && target_switches[j].value > 0 + && (target_switches[j].value & mask) == target_switches[j].value) + { + len = strlen (target_switches[j].name) + 1; + if (len + line_len > 79) + { + line_len = 2; + fputs ("\n #", out); + } + fprintf (out, " -m%s", target_switches[j].name); + line_len += len; + } + + fprintf (out, "\n\n # Cc1 arguments (-G value = %d):", + mips_section_threshold); + + line_len = 32767; + for (p = &save_argv[1]; *p != (char *)0; p++) + if (**p == '-') + { + len = strlen (*p) + 1; + if (len + line_len > 79) + { + line_len = 2; + fputs ("\n #", out); + } + fprintf (out, " %s", *p); + line_len += len; + } + fputs ("\n\n", out); + } + +#endif +} + + + +/* Abort after printing out a specific insn. */ + +void +abort_with_insn (insn, reason) + rtx insn; + char *reason; +{ + error (reason); + debug_rtx (insn); + abort (); +} + +/* Write a message to stderr (for use in macros expanded in files that do not + include stdio.h). */ + +void +trace (s, s1, s2) + char *s, *s1, *s2; +{ + fprintf (stderr, s, s1, s2); +} + + +/* Set up the threshold for data to go into the small data area, instead + of the normal data area, and detect any conflicts in the switches. */ + +void +overide_options () +{ + register int i; + + i = TARGET_GVALUE; + if (i >= 6) + i += 3; + mips_section_threshold = (i != 0) ? 1 << i : 0; +} + +/* Compute a string to use as a temporary file name. */ + +static FILE * +make_temp_file () +{ + char *temp_filename; + FILE *stream; + extern char *getenv (); + char *base = getenv ("TMPDIR"); + int len; + + if (base == (char *)0) + { +#ifdef P_tmpdir + if (access (P_tmpdir, R_OK | W_OK) == 0) + base = P_tmpdir; + else +#endif + if (access ("/usr/tmp", R_OK | W_OK) == 0) + base = "/usr/tmp/"; + else + base = "/tmp/"; + } + + len = strlen (base); + temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX")); + strcpy (temp_filename, base); + if (len > 0 && temp_filename[len-1] != '/') + temp_filename[len++] = '/'; + + strcpy (temp_filename + len, "ccXXXXXX"); + mktemp (temp_filename); + + stream = fopen (temp_filename, "w+"); + if (!stream) + pfatal_with_name (temp_filename); + + unlink (temp_filename); + return stream; +} + +/* Output at beginning of assembler file. + If we are optimizing to use the global pointer, create a temporary + file to hold all of the text stuff, and write it out to the end. + This is needed because the MIPS assembler is evidently one pass, + and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata + declaration when the code is processed, it generates a two + instruction sequence. */ + +void +mips_asm_file_start (stream) + FILE *stream; +{ + if (TARGET_NAME_REGS) + fprintf (stream, "#include <regdef.h>\n"); + + ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename); + + print_options (stream); + data_section (); /* put gcc_compiled. in data, not text*/ + + if (TARGET_GP_OPT) + { + asm_out_data_file = stream; + asm_out_text_file = make_temp_file (); + } + else + asm_out_data_file = asm_out_text_file = stream; + +} + +/* If optimizing for the global pointer, keep track of all of + the externs, so that at the end of the file, we can emit + the appropriate .extern declaration for them, before writing + out the text section. We assume that all names passed to + us are in the permanent obstack, so that they will be valid + at the end of the compilation. + + If we have -G 0, or the extern size is unknown, don't bother + emitting the .externs. */ + +int +mips_output_external (file, decl, name) + FILE *file; + tree decl; + char *name; +{ + extern char *permalloc (); + register struct extern_list *p; + int len; + + if (TARGET_GP_OPT + && mips_section_threshold != 0 + && ((TREE_CODE (decl)) != FUNCTION_DECL) + && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0)) + { + p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); + p->next = extern_head; + p->name = name; + p->size = len; + extern_head = p; + } + return 0; +} + +/* If we are optimizing the global pointer, emit the text section now + and any small externs which did not have .comm, etc that are + needed. Also, give a warning if the data area is more than 32K and + -pic because 3 instructions are needed to reference the data + pointers. */ + +int +mips_asm_file_end (file) + FILE *file; +{ + char buffer[8192]; + tree name_tree; + struct extern_list *p; + int len; + extern tree lookup_name (); + + if (TARGET_GP_OPT) + { + if (extern_head) + fputs ("\n", file); + + for (p = extern_head; p != 0; p = p->next) + { + name_tree = get_identifier (p->name); + if (!TREE_ADDRESSABLE (name_tree)) + { + TREE_ADDRESSABLE (name_tree) = 1; + fprintf (file, "\t.extern\t%s, %d\n", p->name, p->size); + } + } + + fprintf (file, "\n\t.text\n"); + rewind (asm_out_text_file); + if (ferror (asm_out_text_file)) + fatal_io_error ("write of text assembly file in mips_asm_file_end"); + + while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0) + if (fwrite (buffer, 1, len, file) != len) + pfatal_with_name ("write of final assembly file in mips_asm_file_end"); + + if (len < 0) + pfatal_with_name ("read of text assembly file in mips_asm_file_end"); + + if (fclose (asm_out_text_file) != 0) + pfatal_with_name ("close of tempfile in mips_asm_file_end"); + } +} + +/* Fix references to the frame pointer to be off of the stack pointer. */ + +struct rtx_def * +mips_fix_frame_pointer (oldaddr, depth) + rtx oldaddr; + int depth; +{ + rtx newaddr; + rtx sp_diff_rtx; + char temp[40]; + int frame_offset = 0; + extern rtx eliminate_constant_term (); + + newaddr = eliminate_constant_term (oldaddr, &frame_offset); + if (newaddr != frame_pointer_rtx) + return oldaddr; + + if (sp_fp_difference == (char *)0) + { + sprintf (temp, "$Ls%d", number_functions_processed); + sp_fp_difference = IDENTIFIER_POINTER (get_identifier (temp)); + } + + sp_diff_rtx = gen_rtx (SYMBOL_REF, SImode, sp_fp_difference); + if (frame_offset + depth == 0) + newaddr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, sp_diff_rtx); + else + newaddr = gen_rtx (PLUS, Pmode, + stack_pointer_rtx, + gen_rtx (CONST, Pmode, + gen_rtx (PLUS, Pmode, + sp_diff_rtx, + gen_rtx (CONST_INT, VOIDmode, + frame_offset + depth)))); + + if (TARGET_DEBUGC_MODE) + { + fprintf (stderr, + "\n==================== FIX_FRAME, depth = %d, sp prealloc = %d, offset = %d\n", + depth, stack_args_preallocated, frame_offset); + + fprintf (stderr, "old INSN:"); + debug_rtx (oldaddr); + + fprintf (stderr, "\nnew INSN:"); + debug_rtx (newaddr); + } + + return newaddr; +} + + +/* Set up the stack and frame (if desired) for the function. */ + +void +function_prologue (file, size) + FILE *file; + int size; +{ + extern char call_used_regs[]; + extern char *reg_numchar[]; + extern tree current_function_decl; + int regno; + int mask; + int fmask; + int push_loc; + int tsize; + int num_regs; + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; + char *base_str; + char *sp_str = reg_name_ptr[STACK_POINTER_REGNUM]; + char *fp_str = (!frame_pointer_needed) + ? sp_str + : reg_name_ptr[FRAME_POINTER_REGNUM]; + tree fndecl = current_function_decl; /* current... is tooo long */ + tree fntype = TREE_TYPE (fndecl); + tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) + ? DECL_ARGUMENTS (fndecl) + : 0; + tree next_arg; + tree cur_arg; + char *arg_name = (char *)0; + CUMULATIVE_ARGS args_so_far; + + + inside_function = 1; + + + if (write_symbols != NO_DEBUG) + ASM_OUTPUT_SOURCE_LINE (file, + DECL_SOURCE_LINE (current_function_decl)); + + fprintf (file, "\t.ent\t%s\n%s:\n", current_function_name, + current_function_name); + + fprintf (file, " #PROLOGUE\n"); + + /* Determine the last argument, and get it's name. */ + for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg) + { + next_arg = TREE_CHAIN (cur_arg); + if (next_arg == (tree)0) + { + if (DECL_NAME (cur_arg)) + arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg)); + + break; + } + } + + /* If this function is a varargs function, store any registers that + would normally hold arguments ($4 - $7) on the stack. */ + if ((TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) + || (arg_name + && (strcmp (arg_name, "__builtin_va_alist") == 0 + || strcmp (arg_name, "va_alist") == 0))) + { + tree parm; + + regno = 4; + INIT_CUMULATIVE_ARGS (args_so_far, fntype); + + for (parm = fnargs; (parm && (regno <= 7)); parm = TREE_CHAIN (parm)) + { + rtx entry_parm; + enum machine_mode passed_mode; + tree type; + + type = DECL_ARG_TYPE (parm); + passed_mode = TYPE_MODE (type); + entry_parm = FUNCTION_ARG (args_so_far, passed_mode, + DECL_ARG_TYPE (parm), 1); + + if (entry_parm) + { + int words; + + /* passed in a register, so will get homed automatically */ + if (GET_MODE (entry_parm) == BLKmode) + words = (int_size_in_bytes (type) + 3) / 4; + else + words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; + + regno = REGNO (entry_parm) + words - 1; + } + else + { + regno = 8; + break; + } + + FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, + DECL_ARG_TYPE (parm), 1); + } + + switch (regno) + { + case 4: + fprintf(file, "\tsd\t%s,0(%s)\t#varargs: home regs 4-5\n", + reg_name_ptr[4], sp_str); + + fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n", + reg_name_ptr[6], sp_str); + break; + + case 5: + fprintf(file, "\tsw\t%s,4(%s)\t#varargs: home reg 5\n", + reg_name_ptr[5], sp_str); + + fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n", + reg_name_ptr[6], sp_str); + break; + + case 6: + fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n", + reg_name_ptr[6], sp_str); + break; + + case 7: + fprintf(file, "\tsw\t%s,12(%s)\t#varargs: home reg 7\n", + reg_name_ptr[7], sp_str); + break; + + default: + break; + } + } + + mask = 0; + fmask = 0; + num_regs = 0; + push_loc = stack_args_preallocated; + tsize = AL_ADJUST_ALIGN (size) + stack_args_preallocated; + + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if (MUST_SAVE_REGISTER (regno)) + { + tsize += 4; + num_regs += 4; + mask |= 1 << (regno - GP_REG_FIRST); + } + + tsize = AL_ADJUST_ALIGN (tsize); + num_regs = AL_ADJUST_ALIGN (num_regs); + for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2) + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + tsize += 8; + num_regs += 8; + fmask |= 1 << (regno - FP_REG_FIRST); + } + + if (tsize) + tsize -= STARTING_FRAME_OFFSET; + + + if (!frame_pointer_needed && sp_fp_difference != (char *)0) + fprintf (file,"%s\t= %d\t\t\t#Difference between SP & FP\n\n", + sp_fp_difference, tsize); + + current_function_total_framesize = tsize; + current_function_saved_reg_size = num_regs; + if (tsize > 0) + { + if (tsize <= 32767) + fprintf (file, + "\tsubu\t%s,%s,%d\t# temp= %d, regs= %d, args= %d, sfo= %d\n", + sp_str, sp_str, tsize, size, num_regs, + stack_args_preallocated, STARTING_FRAME_OFFSET); + else + fprintf (file, + "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t# temp= %d, regs= %d, args= %d, sfo= %d\n", + reg_name_ptr[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str, + reg_name_ptr[MIPS_TEMP1_REGNUM], size, num_regs, + stack_args_preallocated, STARTING_FRAME_OFFSET); + } + + fprintf (file, "\t.frame\t%s,%d,%s\n", fp_str, + (frame_pointer_needed) ? 0 : tsize, + reg_name_ptr[31]); + + if (push_loc > 32767 && num_regs > 0) + { + if ((tsize - (push_loc + num_regs)) <= 32767) + { + base_str = reg_name_ptr[MIPS_TEMP1_REGNUM]; + push_loc = tsize - push_loc; + } + else + { + base_str = reg_name_ptr[MIPS_TEMP2_REGNUM]; + fprintf (file, "\tli\t%s,%d\n", base_str, push_loc); + push_loc = 0; + } + } + else + base_str = sp_str; + + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if ((mask & (1 << (regno - GP_REG_FIRST))) != 0) + { + fprintf (file, "\tsw\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 4; + } + + fprintf (file, "\t.mask\t0x%08x,%d\n", mask, push_loc - tsize - 4); + + push_loc = AL_ADJUST_ALIGN (push_loc); + for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2) + if ((fmask & (1 << (regno - FP_REG_FIRST))) != 0) + { + fprintf (file, "\ts.d\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 8; + } + + fprintf (file, "\t.fmask\t0x%08x,%d\n", fmask, push_loc - tsize - 4); + + if (frame_pointer_needed) + { + if (tsize <= 32767) + fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize); + else + fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str, + reg_name_ptr[MIPS_TEMP1_REGNUM]); + } + + fprintf (file," #END PROLOGUE\n"); +} + + +/* Do any necessary cleanup after a function to restore stack, frame, and regs. */ + +void +function_epilogue (file, size) + FILE *file; + int size; +{ + extern FILE *asm_out_data_file, *asm_out_file; + extern char call_used_regs[]; + extern char *reg_numchar[]; + extern char *current_function_name; + extern int frame_pointer_needed; + int regno; + int push_loc = stack_args_preallocated; + int tsize = current_function_total_framesize; + int num_regs = current_function_saved_reg_size; + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; + char *sp_str = reg_name_ptr[STACK_POINTER_REGNUM]; + char *t1_str = reg_name_ptr[MIPS_TEMP1_REGNUM]; + char *base_str; + + + fprintf (file," #EPILOGUE\n"); + + if (tsize > 32767) + fprintf (file, "\tli\t%s,%d\n", t1_str, tsize); + + if (frame_pointer_needed) + { + char *fp_str = reg_name_ptr[FRAME_POINTER_REGNUM]; + if (tsize > 32767) + fprintf (file,"\tsubu\t%s,%s,%s\t# sp not trusted here\n", + sp_str, fp_str, t1_str); + else + fprintf (file,"\tsubu\t%s,%s,%d\t# sp not trusted here\n", + sp_str, fp_str, tsize); + } + + if (push_loc > 32767 && num_regs > 0) + { + if ((tsize - (push_loc + num_regs)) <= 32767) + { + base_str = t1_str; + push_loc = tsize - push_loc; + } + else + { + base_str = reg_name_ptr[MIPS_TEMP2_REGNUM]; + fprintf (file, "\tli\t%s,%d\n", base_str, push_loc); + push_loc = 0; + } + } + else + base_str = sp_str; + + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if (MUST_SAVE_REGISTER (regno)) + { + fprintf (file,"\tlw\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 4; + } + + push_loc = AL_ADJUST_ALIGN (push_loc); + for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2) + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + fprintf (file, "\tl.d\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 8; + } + + if (tsize > 32767) + fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); + + else if (tsize > 0) + fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); + + fprintf (file,"\tj\t%s\n", reg_name_ptr[31]); + fprintf (file," #END EPILOGUE\n"); + fprintf (file,"\t.end\t%s\n", current_function_name); + + /* Reset state info for each function. */ + stack_args_pushed = 0; + stack_args_preallocated = 0; + inside_function = 0; + sp_fp_difference = (char *)0; + number_functions_processed++; + + /* Restore the output file if optimizing the GP (optimizing the GP causes + the text to be diverted to a tempfile, so that data decls come before + references to the data). */ + + if (TARGET_GP_OPT) + asm_out_file = asm_out_data_file; +} diff --git a/gcc-1.40/config/out-ns32k.c b/gcc-1.40/config/out-ns32k.c new file mode 100644 index 0000000..e3df4fe --- /dev/null +++ b/gcc-1.40/config/out-ns32k.c @@ -0,0 +1,575 @@ +/* Subroutines for assembler code output on the NS32000. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Some output-actions in ns32k.md need these. */ +#include <stdio.h> +extern FILE *asm_out_file; + +#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16) + +/* Generate the rtx that comes from an address expression in the md file */ +/* The expression to be build is BASE[INDEX:SCALE]. To recognize this, + scale must be converted from an exponent (from ASHIFT) to a + muliplier (for MULT). */ +rtx +gen_indexed_expr (base, index, scale) + rtx base, index, scale; +{ + rtx addr; + + /* This generates an illegal addressing mode, if BASE is + fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ + if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) + base = gen_rtx (MEM, SImode, base); + addr = gen_rtx (MULT, SImode, index, + gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale))); + addr = gen_rtx (PLUS, SImode, base, addr); + return addr; +} + +/* Return 1 if OP is a valid constant int. These can be modeless + (void mode), so we do not mess with their modes. + + The main use of this function is as a predicate in match_operand + expressions in the machine description. */ + +int +const_int (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT); +} + +/* Return 1 if OP is a valid operand of mode MODE. This + predicate rejects operands which do not have a mode + (such as CONST_INT which are VOIDmode). */ +int +reg_or_mem_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_MODE (op) == mode + && (GET_CODE (op) == REG + || GET_CODE (op) == SUBREG + || GET_CODE (op) == MEM)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) <= 7 + && INTVAL (operands[1]) >= -8) + return "movqd %1,%0"; + return "movd %1,%0"; +} + +char * +output_move_double (operands) + rtx *operands; +{ + enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = POPOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_ADDRESS_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = POPOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_ADDRESS_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + if (optype0 == POPOP || optype1 == POPOP) + { + output_asm_insn (singlemove_string (latehalf), latehalf); + return singlemove_string (operands); + } + + /* Not autodecrementing. Do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + operands[0] = latehalf[0]; + operands[1] = latehalf[1]; + return singlemove_string (operands); +} + +int +check_reg (oper, reg) + rtx oper; + int reg; +{ + register int i; + + if (oper == 0) + return 0; + switch (GET_CODE(oper)) + { + case REG: + return (REGNO(oper) == reg) ? 1 : 0; + case MEM: + return check_reg(XEXP(oper, 0), reg); + case PLUS: + case MULT: + return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg); + } + return 0; +} + +/* PRINT_OPERAND_ADDRESS is defined to call this function, + which is easier to debug than putting all the code in + a macro definition in tm-ns32k.h . */ + +/* Nonzero if we have printed a base register. + If zero, on some systems, it means `(sb)' must be printed. */ +int paren_base_reg_printed = 0; + +print_operand_address (file, addr) + register FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + static char scales[] = { 'b', 'w', 'd', 0, 'q', }; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + addr = XEXP (addr, 0); + if (GET_CODE (addr) == REG) + if (REGNO (addr) == STACK_POINTER_REGNUM) + { fprintf (file, "tos"); break; } + else + { fprintf (file, "%s", reg_names[REGNO (addr)]); break; } + else if (CONSTANT_P (addr)) + { output_addr_const (file, addr); break; } + else if (GET_CODE (addr) == MULT) + { fprintf (file, "@0"); ireg = addr; goto print_index; } + else if (GET_CODE (addr) == MEM) + { + addr = XEXP (addr, 0); + if (GET_CODE (addr) == PLUS) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + offset = const0_rtx; + } + output_addr_const (file, offset); + fprintf (file, "(%s)", reg_names[REGNO (addr)]); + break; + } + + if (GET_CODE (addr) != PLUS) + abort (); + + goto retry; + + case REG: + if (REGNO (addr) == STACK_POINTER_REGNUM) + fprintf (file, "tos"); + else + fprintf (file, "0(%s)", reg_names[REGNO (addr)]); + break; + + case PRE_DEC: + case POST_INC: + fprintf (file, "tos"); + break; + + case MULT: + fprintf (file, "@0"); + ireg = addr; /* [rX:Y] */ + goto print_index; + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = const0_rtx; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + /* The case for memory is somewhat tricky: to get + a MEM here, the only RTX formats that could + get here are either (modulo commutativity) + (PLUS (PLUS (REG *MEM)) CONST) -or- + (PLUS (PLUS (CONST REG/MULT)) *MEM) + We take advantage of that knowledge here. */ + else if (GET_CODE (XEXP (addr, 0)) == MEM + || GET_CODE (XEXP (addr, 1)) == MEM) + { + rtx temp; + + if (GET_CODE (XEXP (addr, 0)) == MEM) + { + temp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + temp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + + if (GET_CODE (temp) == REG) + { + reg1 = temp; + } + else + { + if (GET_CODE (temp) != PLUS) + abort (); + + if (GET_CODE (XEXP (temp, 0)) == MULT) + { + reg1 = XEXP (temp, 0); + offset = XEXP (temp, 1); + } + if (GET_CODE (XEXP (temp, 1)) == MULT) + { + reg1 = XEXP (temp, 1); + offset = XEXP (temp, 0); + } + else + abort (); + } + } + else if (GET_CODE (XEXP (addr, 0)) == REG + || GET_CODE (XEXP (addr, 1)) == REG) + { + rtx temp; + + if (GET_CODE (XEXP (addr, 0)) == REG) + { + temp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else + { + temp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + + if (GET_CODE (addr) == REG) + { + if (REGNO (temp) >= FRAME_POINTER_REGNUM) + { reg1 = addr; addr = temp; } + else + { reg1 = temp; } + } + else if (CONSTANT_P (addr)) + { + if (GET_CODE (offset) == CONST_INT + && INTVAL (offset)) + offset = plus_constant (addr, INTVAL (offset)); + addr = temp; + } + else if (GET_CODE (addr) != PLUS) + abort (); + else + { + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else abort (); + + if (GET_CODE (addr) == REG) + { + if (REGNO (temp) >= FRAME_POINTER_REGNUM) + { reg1 = addr; addr = temp; } + else + { reg1 = temp; } + } + else + reg1 = temp; + } + } + + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } + if (addr != 0) + { + if (CONSTANT_P (addr) && reg1) + { + /* OFFSET comes second, to prevent outputting + operands of the form INT+SYMBOL+INT. + The Genix assembler dies on them. */ + output_addr_const (file, addr); + if (offset != const0_rtx) + { + putc ('+', file); + output_addr_const (file, offset); + } + ireg = reg1; + goto print_index; + } + else if (GET_CODE (addr) != MEM) + abort (); + + output_addr_const (file, offset); +#ifndef SEQUENT_ADDRESS_BUG + putc ('(', file); + paren_base_reg_printed = 0; + output_address (addr); +#ifdef SEQUENT_BASE_REGS + if (!paren_base_reg_printed) + fprintf (file, "(sb)"); +#endif + putc (')', file); +#else /* SEQUENT_ADDRESS_BUG */ + if ((GET_CODE (offset) == SYMBOL_REF + || GET_CODE (offset) == CONST) + && GET_CODE (addr) == REG) + { + if (reg1) abort (); + fprintf (file, "[%s:b]", reg_names[REGNO (addr)]); + } + else + { + putc ('(', file); + paren_base_reg_printed = 0; + output_address (addr); +#ifdef SEQUENT_BASE_REGS + if (!paren_base_reg_printed) + fprintf (file, "(sb)"); +#endif + putc (')', file); + } +#endif /* SEQUENT_ADDRESS_BUG */ + ireg = reg1; + goto print_index; + } + else addr = offset; + if (reg1 && GET_CODE (reg1) == MULT) + { breg = reg2; ireg = reg1; } + else if (reg2 && GET_CODE (reg2) == MULT) + { breg = reg1; ireg = reg2; } + else if (reg2 || GET_CODE (addr) == MEM) + { breg = reg2; ireg = reg1; } + else + { breg = reg1; ireg = reg2; } + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) + { + int scale; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)) >> 1; + ireg = XEXP (ireg, 0); + } + else scale = 0; + output_asm_label (addr); + fprintf (file, "[%s:%c]", + reg_names[REGNO (ireg)], scales[scale]); + break; + } + if (ireg && breg && offset == const0_rtx) + fprintf (file, "0(%s)", reg_names[REGNO (breg)]); + else + { + if (addr != 0) + { + if (ireg != 0 && breg == 0 + && GET_CODE (offset) == CONST_INT) putc('@', file); + output_addr_const (file, offset); + } + if (breg != 0) + { + if (GET_CODE (breg) != REG) abort (); +#ifndef SEQUENT_ADDRESS_BUG + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + paren_base_reg_printed = -1; +#else + if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST) + { + if (ireg) abort (); + fprintf (file, "[%s:b]", reg_names[REGNO (breg)]); + } + else + { + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + paren_base_reg_printed = -1; + } +#endif + } + } + print_index: + if (ireg != 0) + { + int scale; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)) >> 1; + ireg = XEXP (ireg, 0); + } + else scale = 0; + if (GET_CODE (ireg) != REG) abort (); + fprintf (file, "[%s:%c]", + reg_names[REGNO (ireg)], + scales[scale]); + } + break; + default: + output_addr_const (file, addr); + } +} + +/* National 32032 shifting is so bad that we can get + better performance in many common cases by using other + techniques. */ +char * +output_shift_insn (operands) + rtx *operands; +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 3) + if (GET_CODE (operands[0]) == REG) + { + if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + if (operands[2] == const1_rtx) + return "addd %0,%0"; + else if (INTVAL (operands[2]) == 2) + return "addd %0,%0\n\taddd %0,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + } + else if (GET_CODE (operands[1]) == REG) + { + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + else if (INTVAL (operands[2]) == 1 + && GET_CODE (operands[1]) == MEM + && rtx_equal_p (operands [0], operands[1])) + { + rtx temp = XEXP (operands[1], 0); + + if (GET_CODE (temp) == REG + || (GET_CODE (temp) == PLUS + && GET_CODE (XEXP (temp, 0)) == REG + && GET_CODE (XEXP (temp, 1)) == CONST_INT)) + return "addd %0,%0"; + } + else return "ashd %2,%0"; + return "ashd %2,%0"; +} diff --git a/gcc-1.40/config/out-pyr.c b/gcc-1.40/config/out-pyr.c new file mode 100644 index 0000000..c6e85a8 --- /dev/null +++ b/gcc-1.40/config/out-pyr.c @@ -0,0 +1,849 @@ +/* Subroutines for insn-output.c for Pyramid 90 Series. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Some output-actions in pyr.md need these. */ +#include <stdio.h> + +extern FILE *asm_out_file; +#include "tree.h" + +/* + * Do FUNCTION_ARG. + * This cannot be defined as a macro on pyramids, because Pyramid Technology's + * C compiler dies on (several equivalent definitions of) this macro. + * The only way around this cc bug was to make this a function. + * While it would be possible to use a macro version for gcc, it seems + * more reliable to have a single version of the code. + */ +void * +pyr_function_arg(cum, mode, type, named) + CUMULATIVE_ARGS cum; + enum machine_mode mode; + tree type; +{ + return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named)); +} + +/* Do the hard part of PARAM_SAFE_FOR_REG_P. + * This cannot be defined as a macro on pyramids, because Pyramid Technology's + * C compiler dies on (several equivalent definitions of) this macro. + * The only way around this cc bug was to make this a function. + */ +int +inner_param_safe_helper (type) + tree type; +{ + return (INNER_PARAM_SAFE_HELPER(type)); +} + + +/* Return 1 if OP is a non-indexed operand of mode MODE. + This is either a register reference, a memory reference, + or a constant. In the case of a memory reference, the address + is checked to make sure it isn't indexed. + + Register and memory references must have mode MODE in order to be valid, + but some constants have no machine mode and are valid for any mode. + + If MODE is VOIDmode, OP is checked for validity for whatever mode + it has. + + The main use of this function is as a predicate in match_operand + expressions in the machine description. + + It is useful to compare this with general_operand(). They should + be identical except for one line. + + This function seems necessary because of the non-orthogonality of + Pyramid insns. + For any 2-operand insn, and any combination of operand modes, + if indexing is valid for the isn's second operand, it is invalid + for the first operand to be indexed. */ + +extern int volatile_ok; + +int +nonindexed_operand(op, mode) + register rtx op; + enum machine_mode mode; +{ + register RTX_CODE code = GET_CODE (op); + int mode_altering_drug = 0; + + if (mode == VOIDmode) + mode = GET_MODE (op); + + if (CONSTANT_P (op)) + return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode) + && LEGITIMATE_CONSTANT_P (op)); + + /* Except for certain constants with VOIDmode, already checked for, + OP's mode must match MODE if MODE specifies a mode. */ + + if (GET_MODE (op) != mode) + return 0; + + while (code == SUBREG) + { + op = SUBREG_REG (op); + code = GET_CODE (op); +#if 0 + /* No longer needed, since (SUBREG (MEM...)) + will load the MEM into a reload reg in the MEM's own mode. */ + mode_altering_drug = 1; +#endif + } + if (code == REG) + return 1; + if (code == CONST_DOUBLE) + return LEGITIMATE_CONSTANT_P (op); + if (code == MEM) + { + register rtx y = XEXP (op, 0); + if (! volatile_ok && MEM_VOLATILE_P (op)) + return 0; + GO_IF_NONINDEXED_ADDRESS (y, win); + } + return 0; + + win: + if (mode_altering_drug) + return ! mode_dependent_address_p (XEXP (op, 0)); + return 1; +} + +/* Return non-zero if the rtx OP has an immediate component. An + immediate component or additive term equal to zero is rejected + due to assembler problems. */ + +int +has_direct_base (op) + rtx op; +{ + if ((CONSTANT_ADDRESS_P (op) + && op != const0_rtx) + || (GET_CODE (op) == PLUS + && ((CONSTANT_ADDRESS_P (XEXP (op, 1)) + && XEXP (op, 1) != const0_rtx) + || (CONSTANT_ADDRESS_P (XEXP (op, 0)) + && XEXP (op, 0) != const0_rtx)))) + return 1; + + return 0; +} + +int +has_index (op) + rtx op; +{ + if (GET_CODE (op) == PLUS + && (GET_CODE (XEXP (op, 0)) == MULT + || (GET_CODE (XEXP (op, 1)) == MULT))) + return 1; + else + return 0; +} + +int swap_operands; + +/* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or + exchanged with xchw) with one instruction. If the operands need to + be swapped, set the global variable SWAP_OPERANDS. This function + silently assumes that both OP0 and OP1 are valid memory references. + */ + +int +weird_memory_memory (op0, op1) + rtx op0, op1; +{ + int ret; + int c; + RTX_CODE code0, code1; + + op0 = XEXP (op0, 0); + op1 = XEXP (op1, 0); + code0 = GET_CODE (op0); + code1 = GET_CODE (op1); + + swap_operands = 0; + + if (code1 == REG || code1 == SUBREG) + { + return 1; + } + if (code0 == REG || code0 == SUBREG) + { + swap_operands = 1; + return 1; + } + if (has_direct_base (op0) && has_direct_base (op1)) + { + if (has_index (op1)) + { + if (has_index (op0)) + return 0; + swap_operands = 1; + } + + return 1; + } + return 0; +} + +int +signed_comparison (x, mode) + rtx x; + enum machine_mode mode; +{ + return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x)); +} + +extern rtx force_reg (); +rtx test_op0, test_op1; +enum machine_mode test_mode; + +/* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE. */ + +rtx +extend_const (x, extop, from_mode, to_mode) + rtx x; + RTX_CODE extop; + enum machine_mode from_mode, to_mode; +{ + int val; + int negative; + if (from_mode == to_mode) + return x; + if (GET_CODE (x) != CONST_INT) + abort (); + val = INTVAL (x); + negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1)); + if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT) + abort (); + if (negative && extop == SIGN_EXTEND) + val = val | ((-1) << (GET_MODE_BITSIZE (from_mode))); + else + val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode))); + if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT) + return gen_rtx (CONST_INT, VOIDmode, val); + return gen_rtx (CONST_INT, VOIDmode, + val & ~((-1) << (GET_MODE_BITSIZE (to_mode)))); +} + +rtx +ensure_extended (op, extop, from_mode) + rtx op; + RTX_CODE extop; + enum machine_mode from_mode; +{ + if (GET_CODE (op) == CONST_INT) + return extend_const (op, extop, from_mode, SImode); + else + return force_reg (SImode, gen_rtx (extop, SImode, op)); +} + +/* Emit rtl for a branch, as well as any delayed (integer) compare insns. + The compare insn to perform is determined by the global variables + test_op0 and test_op1. */ + +void +extend_and_branch (extop) + RTX_CODE extop; +{ + rtx op0, op1; + RTX_CODE code0, code1; + + op0 = test_op0, op1 = test_op1; + if (op0 == 0) + return; + + code0 = GET_CODE (op0); + if (op1 != 0) + code1 = GET_CODE (op1); + test_op0 = test_op1 = 0; + + if (op1 == 0) + { + op0 = ensure_extended (op0, extop, test_mode); + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0)); + } + else + { + if (CONSTANT_P (op0) && CONSTANT_P (op1)) + { + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (extop == ZERO_EXTEND && test_mode == HImode) + { + /* Pyramids have no unsigned "cmphi" instructions. We need to + zero extend unsigned halfwords into temporary registers. */ + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (CONSTANT_P (op0)) + { + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (CONSTANT_P (op1)) + { + op1 = ensure_extended (op1, extop, test_mode); + op0 = ensure_extended (op0, extop, test_mode); + } + else if ((code0 == REG || code0 == SUBREG) + && (code1 == REG || code1 == SUBREG)) + { + /* I could do this case without extension, by using the virtual + register address (but that would lose for global regs). */ + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (code0 == MEM && code1 == MEM) + { + /* Load into a reg if the address combination can't be handled + directly. */ + if (! weird_memory_memory (op0, op1)) + op0 = force_reg (test_mode, op0); + } + + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, VOIDmode, op0, op1))); + } +} + +/* Return non-zero if the two single-word moves with operands[0] + and operands[1] for the first single-word move, and operands[2] + and operands[3] for the second single-word move, is possible to + combine to a double word move. + + The criterion is whether the operands are in consecutive memory cells, + registers, etc. */ + +int +movdi_possible (operands) + rtx operands[]; +{ + int cnst_diff0, cnst_diff1; + RTX_CODE code0 = GET_CODE (operands[0]); + RTX_CODE code1 = GET_CODE (operands[1]); + + /* Don't dare to combine (possibly overlapping) memory -> memory moves. */ + /* It would be possible to detect the cases where we dare, by using + constant_diff (operands[0], operands[1])!!! */ + if (code0 == MEM && code1 == MEM) + return 0; + + cnst_diff0 = consecutive_operands (operands[0], operands[2]); + if (cnst_diff0 == 0) + return 0; + + cnst_diff1 = consecutive_operands (operands[1], operands[3]); + if (cnst_diff1 == 0) + return 0; + + if (cnst_diff0 & cnst_diff1) + { + /* The source and destination operands are consecutive. */ + + /* If the first move writes into the source of the second move, + we cannot combine. */ + if ((code0 == REG + && reg_overlap_mentioned_p (operands[0], operands[3])) + || (code0 == SUBREG + && subreg_overlap_mentioned_p (operands[0], operands[3]))) + return 0; + + if (cnst_diff0 & 1) + /* operands[0],[1] has higher addresses than operands[2],[3]. */ + swap_operands = 0; + else + /* operands[0],[1] has lower addresses than operands[2],[3]. */ + swap_operands = 1; + return 1; + } + return 0; +} + +/* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead + of a reg. */ + +int +subreg_overlap_mentioned_p (subreg, x) + rtx subreg, x; +{ + rtx reg = SUBREG_REG (subreg); + int regno = REGNO (reg) + SUBREG_WORD (subreg); + int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg)); + return refers_to_regno_p (regno, endregno, x, 0); +} + +/* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a + consecutive operand to OP0. + + This function is used to determine if addresses are consecutive, + and therefore possible to combine to fewer instructions. */ + +int +consecutive_operands (op0, op1) + rtx op0, op1; +{ + RTX_CODE code0, code1; + int cnst_diff; + int regno_off0, regno_off1; + + code0 = GET_CODE (op0); + code1 = GET_CODE (op1); + + regno_off0 = 0; + if (code0 == SUBREG) + { + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD) + return 0; + regno_off0 = SUBREG_WORD (op0); + op0 = SUBREG_REG (op0); + code0 = REG; + } + + regno_off1 = 0; + if (code1 == SUBREG) + { + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD) + return 0; + regno_off1 = SUBREG_WORD (op1); + op1 = SUBREG_REG (op1); + code1 = REG; + } + + if (code0 != code1) + return 0; + + switch (code0) + { + case CONST_INT: + /* Cannot permit any symbolic constants, even if the consecutive + operand is 0, since a movl really performs sign extension. */ + if (code1 != CONST_INT) + return 0; + if ((INTVAL (op0) == 0 && INTVAL (op1) == 0) + || (INTVAL (op0) == -1 && INTVAL (op1) == -1)) + return 3; + if ((INTVAL (op0) == 0 && INTVAL (op1) > 0) + || (INTVAL (op0) == -1 && INTVAL (op1) < 0)) + return 2; + if ((INTVAL (op1) == 0 && INTVAL (op0) > 0) + || (INTVAL (op1) == -1 && INTVAL (op0) < 0)) + return 1; + break; + + case REG: + regno_off0 = REGNO (op0) + regno_off0; + regno_off1 = REGNO (op1) + regno_off1; + + cnst_diff = regno_off0 - regno_off1; + if (cnst_diff == 1) + { + /* movl with the highest numbered parameter (local) register as + source or destination, doesn't wrap to the lowest numbered local + (temporary) register. */ + + if (regno_off0 % 16 != 0) + return 1; + else + return 0; + } + else if (cnst_diff == -1) + { + if (regno_off1 % 16 != 0) + return 2; + else + return 0; + } + break; + + case MEM: + op0 = XEXP (op0, 0); + op1 = XEXP (op1, 0); + if (GET_CODE (op0) == CONST) + op0 = XEXP (op0, 0); + if (GET_CODE (op1) == CONST) + op1 = XEXP (op1, 0); + + cnst_diff = constant_diff (op0, op1); + if (cnst_diff) + { + if (cnst_diff == 4) + return 1; + else if (cnst_diff == -4) + return 2; + } + break; + } + return 0; +} + +/* Return the constant difference of the rtx expressions OP0 and OP1, + or 0 if they don't have a constant difference. + + This function is used to determine if addresses are consecutive, + and therefore possible to combine to fewer instructions. */ + +int +constant_diff (op0, op1) + rtx op0, op1; +{ + RTX_CODE code0, code1; + int cnst_diff; + + code0 = GET_CODE (op0); + code1 = GET_CODE (op1); + + if (code0 != code1) + { + if (code0 == PLUS) + { + if (GET_CODE (XEXP (op0, 1)) == CONST_INT + && rtx_equal_p (op1, XEXP (op0, 0))) + return INTVAL (XEXP (op0, 1)); + } + else if (code1 == PLUS) + { + if (GET_CODE (XEXP (op1, 1)) == CONST_INT + && rtx_equal_p (op0, XEXP (op1, 0))) + return -INTVAL (XEXP (op1, 1)); + } + return 0; + } + + if (code0 == CONST_INT) + return INTVAL (op0) - INTVAL (op1); + + if (code0 == PLUS) + { + cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0)); + if (cnst_diff) + return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1))) + ? cnst_diff : 0; + cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1)); + if (cnst_diff) + return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))) + ? cnst_diff : 0; + } + + return 0; +} + +int +already_sign_extended (insn, from_mode, op) + rtx insn; + enum machine_mode from_mode; + rtx op; +{ + rtx xinsn, xdest, xsrc; + + for (;;) + { + insn = PREV_INSN (insn); + if (insn == 0) + return 0; + if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN) + continue; + if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)]) + continue; + if (GET_CODE (insn) != INSN) + return 0; + xinsn = PATTERN (insn); + + if (GET_CODE (xinsn) != SET) + return 0; + + xdest = SET_DEST (xinsn); + xsrc = SET_SRC (xinsn); + + if (GET_CODE (xdest) == SUBREG) + abort (); + + if ( ! REG_P (xdest)) + continue; + + if (REGNO (op) == REGNO (xdest) + && ((GET_CODE (xsrc) == SIGN_EXTEND + && GET_MODE (XEXP (xsrc, 0)) == from_mode) + || (GET_CODE (xsrc) == MEM + && GET_MODE (xsrc) == from_mode))) + return 1; + + /* The register is modified by another operation. */ + if (reg_overlap_mentioned_p (xdest, op)) + return 0; + } +} + +char * +output_move_double (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) + { + /* In an integer, the low-order word is in CONST_DOUBLE_LOW. */ + rtx const_op = operands[1]; + if ((CONST_DOUBLE_HIGH (const_op) == 0 + && CONST_DOUBLE_LOW (const_op) >= 0) + || (CONST_DOUBLE_HIGH (const_op) == -1 + && CONST_DOUBLE_LOW (const_op) < 0)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (const_op)); + return "movl %1,%0"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (const_op)); + output_asm_insn ("movw %1,%0", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (const_op)); + return "movw %1,%0"; + } + else + { + /* In a real, the low-address word is in CONST_DOUBLE_LOW. */ + rtx const_op = operands[1]; + if ((CONST_DOUBLE_LOW (const_op) == 0 + && CONST_DOUBLE_HIGH (const_op) >= 0) + || (CONST_DOUBLE_LOW (const_op) == -1 + && CONST_DOUBLE_HIGH (const_op) < 0)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (const_op)); + return "movl %1,%0"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (const_op)); + output_asm_insn ("movw %1,%0", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (const_op)); + return "movw %1,%0"; + } + } + + return "movl %1,%0"; +} + +/* Output a shift insns, after having reduced integer arguments to + avoid as warnings. */ + +char * +output_shift (pattern, op2, mod) + char *pattern; + rtx op2; + int mod; +{ + if (GET_CODE (op2) == CONST_INT) + { + int cnt = INTVAL (op2) % mod; + if (cnt == 0) + { + cc_status = cc_prev_status; + return ""; + } + op2 = gen_rtx (CONST_INT, VOIDmode, cnt); + } + return pattern; +} + +/* Return non-zero if the code of this rtx pattern is a relop. */ + +int +relop (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case EQ: + case NE: + case LT: + case LE: + case GE: + case GT: + case LTU: + case LEU: + case GEU: + case GTU: + return 1; + } + return 0; +} + +void +notice_update_cc (EXP, INSN) + rtx EXP, INSN; +{ + switch (GET_CODE (EXP)) + { + case SET: + switch (GET_CODE (SET_DEST (EXP))) + { + case CC0: + cc_status.mdep = 0; + cc_status.flags = 0; + cc_status.value1 = 0; + cc_status.value2 = SET_SRC (EXP); + break; + + case PC: + break; + + case REG: + switch (GET_CODE (SET_SRC (EXP))) + { + case CALL: + goto call; + case MEM: + if (GET_MODE (SET_SRC (EXP)) == QImode + || GET_MODE (SET_SRC (EXP)) == HImode) + { + cc_status.mdep = 0; + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + break; + } + /* else: Fall through. */ + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + case CONST_DOUBLE: + case REG: + if (cc_status.value1 + && reg_overlap_mentioned_p (SET_DEST (EXP), + cc_status.value1)) + cc_status.value1 = 0; + if (cc_status.value2 + && reg_overlap_mentioned_p (SET_DEST (EXP), + cc_status.value2)) + cc_status.value2 = 0; + break; + + case UDIV: + case UMOD: + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + break; + default: + cc_status.mdep = 0; + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + break; + } + break; + + case MEM: + switch (GET_CODE (SET_SRC (EXP))) + { + case REG: + if (GET_MODE (SET_SRC (EXP)) == QImode + || GET_MODE (SET_SRC (EXP)) == HImode) + { + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + cc_status.mdep = 0; + break; + } + /* else: Fall through. */ + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + case CONST_DOUBLE: + case MEM: + /* Need to forget cc_status about memory positions each + time a memory store is made, even if the memory store + insns in question doesn't modify the condition codes. */ + if (cc_status.value1 && + GET_CODE (cc_status.value1) == MEM) + cc_status.value1 = 0; + if (cc_status.value2 && + GET_CODE (cc_status.value2) == MEM) + cc_status.value2 = 0; + break; + case SIGN_EXTEND: + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + cc_status.mdep = 0; + break; + + default: + abort (); + } + break; + + default: + abort (); + } + break; + + case CALL: + call: + CC_STATUS_INIT; + break; + /* Do calls preserve the condition codes? (At least forget + cc_status expressions if they refer to registers + not preserved across calls. Also forget expressions + about memory contents.) */ + if (cc_status.value1 + && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15), + cc_status.value1, 0) + || GET_CODE (cc_status.value1) == MEM)) + cc_status.value1 = 0; + if (cc_status.value2 + && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15), + cc_status.value2, 0) + || GET_CODE (cc_status.value2) == MEM)) + cc_status.value2 = 0; + break; + + default: + CC_STATUS_INIT; + } +} + +void +forget_cc_if_dependent (op) + rtx op; +{ + cc_status = cc_prev_status; + if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1)) + cc_status.value1 = 0; + if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2)) + cc_status.value2 = 0; +} diff --git a/gcc-1.40/config/out-sparc.c b/gcc-1.40/config/out-sparc.c new file mode 100644 index 0000000..d180b1f --- /dev/null +++ b/gcc-1.40/config/out-sparc.c @@ -0,0 +1,2092 @@ +/* Subroutines for insn-output.c for Sun SPARC. + Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Global variables for machine-dependend things. */ + +/* This should go away if we pass floats to regs via + the stack instead of the frame, and if we learn how + to renumber all the registers when we don't do a save (hard!). */ +extern int frame_pointer_needed; + +static rtx find_addr_reg (); + +rtx next_real_insn_no_labels (); + +/* Return non-zero only if OP is a register of mode MODE, + or const0_rtx. */ +int +reg_or_0_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (op == const0_rtx || register_operand (op, mode)); +} + +/* Return non-zero if INSN is a conditional insn with a predicate + valid after an addcc or subcc instruction. */ + +int +ignore_overflow_conditional_p (insn) + rtx insn; +{ + rtx x = SET_SRC (PATTERN (insn)); + RTX_CODE code; + if (GET_CODE (x) == IF_THEN_ELSE) + x = XEXP (x, 0); + code = GET_CODE (x); + return code == EQ || code == NE || code == GE || code == LT; +} + +/* Return non-zero if this pattern, can be evaluated safely, even if it + was not asked for. */ +int +safe_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + /* Just experimenting. */ + + /* No floating point src is safe if it contains an arithmetic + operation, since that operation may trap. */ + switch (GET_CODE (op)) + { + case CONST_INT: + case LABEL_REF: + case SYMBOL_REF: + case CONST: + return 1; + + case REG: + return 1; + + case MEM: + return CONSTANT_ADDRESS_P (XEXP (op, 0)); + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != SFmode && mode != DFmode); + case NOT: + return 1; + + case COMPARE: + case MINUS: + case PLUS: + return (mode != SFmode && mode != DFmode); + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + default: + return 0; + } +} + +/* Return 1 if REG is clobbered in IN. + Return 0 if REG is used in IN (other than being clobbered). + Return 2 if REG does not appear in IN. */ + +static int +reg_clobbered_p (reg, in) + rtx reg; + rtx in; +{ + register char *fmt; + register int i, result = 0; + + register enum rtx_code code; + + if (in == 0) + return 2; + + code = GET_CODE (in); + + switch (code) + { + /* Let these fail out quickly. */ + case CONST_INT: + case SYMBOL_REF: + case CONST: + return 2; + + case SUBREG: + if (SUBREG_WORD (in) != 0) + in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); + else + in = SUBREG_REG (in); + + case REG: + if (in == reg + || refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + in, 0)) + return 0; + return 2; + + case SET: + if (SET_SRC (in) == reg + || refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_SRC (in), 0)) + return 0; + + if (SET_DEST (in) == reg) + return 1; + + if (refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_DEST (in), 0)) + if (GET_CODE (SET_DEST (in)) == REG + || GET_CODE (SET_DEST (in)) == SUBREG) + return 1; + else + return 0; + return 2; + + case USE: + if (XEXP (in, 0) == reg + || refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + XEXP (in, 0), 0)) + return 0; + return 2; + + case CLOBBER: + if (XEXP (in, 0) == reg) + return 1; + /* If the CLOBBER expression is a SUBREG, accept that as a + clobber. But if it is some expression based on this register, + that is like a USE as far as this register is concerned, + so we won't take it. */ + if (refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + XEXP (in, 0), 0)) + if (GET_CODE (XEXP (in, 0)) == REG + || GET_CODE (XEXP (in, 0)) == SUBREG) + return 1; + else + return 0; + return 2; + } + + fmt = GET_RTX_FORMAT (code); + + result = 2; + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (in, i) - 1; j >= 0; j--) + switch (reg_clobbered_p (reg, XVECEXP (in, i, j))) + { + case 0: + return 0; + case 2: + continue; + case 1: + result = 1; + break; + } + } + else if (fmt[i] == 'e') + switch (reg_clobbered_p (reg, XEXP (in, i))) + { + case 0: + return 0; + case 2: + continue; + case 1: + result = 1; + break; + } + } + return result; +} + +/* Return non-zero if OP can be written to without screwing up + GCC's model of what's going on. It is assumed that this operand + appears in the dest position of a SET insn in a conditional + branch's delay slot. AFTER is the label to start looking from. */ +int +operand_clobbered_before_used_after (op, after) + rtx op; + rtx after; +{ + extern char call_used_regs[]; + + /* Just experimenting. */ + if (GET_CODE (op) == CC0) + return 1; + if (GET_CODE (op) == REG) + { + rtx insn; + + if (op == stack_pointer_rtx) + return 0; + + for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == NOTE) + continue; + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + switch (reg_clobbered_p (op, PATTERN (insn))) + { + case 0: + return 0; + case 2: + break; + case 1: + return 1; + } + if (dead_or_set_p (insn, op)) + return 1; + } + else if (GET_CODE (insn) == CODE_LABEL) + return 0; + if (GET_CODE (insn) == JUMP_INSN) + { + if (condjump_p (insn)) + return 0; + /* This is a jump insn which has already + been mangled. We can't tell what it does. */ + if (GET_CODE (PATTERN (insn)) == PARALLEL) + return 0; + if (! JUMP_LABEL (insn)) + return 0; + /* Keep following jumps. */ + insn = JUMP_LABEL (insn); + } + } + return 1; + } + + /* In both of these cases, the first insn executed + for this op will be a sethi %hi(whatever),%g1, + which is tolerable. */ + if (GET_CODE (op) == MEM) + return (CONSTANT_ADDRESS_P (XEXP (op, 0))); + + return 0; +} + +/* Return non-zero if this pattern, as a source to a "SET", + is known to yield an instruction of unit size. */ +int +single_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case CONST_INT: +#if 1 + /* This is not always a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; +#else + if (SMALL_INT (op)) + return 1; + /* We can put this set insn into delay slot, because this is one + insn; 'sethi'. */ + if ((INTVAL (op) & 0x3ff) == 0) + return 1; + + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; +#endif + +#if 1 + case SYMBOL_REF: + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; +#else + return 0; +#endif + + case REG: + return 1; + + case MEM: +#if 0 + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF) + return 0; +#endif + return 1; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + return 1; + + case COMPARE: + case MINUS: + /* If the target is cc0, then these insns will take + two insns (one being a nop). */ + return (mode != SFmode && mode != DFmode); + case PLUS: + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return single_insn_src_p (SUBREG_REG (op), mode); + + case SIGN_EXTEND: + case ZERO_EXTEND: + /* Lazy... could check for more cases. */ + if (GET_CODE (XEXP (op, 0)) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) + return 1; + return 0; + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* This extra test must be done to verify that a move insn + really is just one assembler insn. */ + +int +single_insn_extra_test (dest, src) + rtx dest, src; +{ + /* Moves between FP regs and CPU regs are two insns. */ + return (!(GET_CODE (src) == REG + && GET_CODE (dest) == REG + && (FP_REG_P (src) != FP_REG_P (dest)))); +} + +/* Nonzero only if this *really* is a single insn operand. */ +int +strict_single_insn_op_p (op, mode) + rtx op; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + switch (GET_CODE (op)) + { + case CC0: + return 1; + + case CONST_INT: + if (SMALL_INT (op)) + return 1; + /* We can put this set insn into delay slot, because this is one + insn; 'sethi'. */ + if ((INTVAL (op) & 0x3ff) == 0) + return 1; + return 0; + + case SYMBOL_REF: + return 0; + + case REG: + return (mode != DFmode && mode != DImode); + + case MEM: + if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) + return (mode != DFmode && mode != DImode); + return 0; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + return 1; + + case COMPARE: + case MINUS: + /* If the target is cc0, then these insns will take + two insns (one being a nop). */ + return (mode != SFmode && mode != DFmode); + case PLUS: + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return strict_single_insn_op_p (SUBREG_REG (op), mode); + + case SIGN_EXTEND: + case ZERO_EXTEND: + if (GET_CODE (XEXP (op, 0)) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) + return 1; + return 0; + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* Return truth value of whether OP is a relational operator. */ +int +relop (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case GTU: + case GEU: + case LTU: + case LEU: + return 1; + } + return 0; +} + +/* Return truth value of wheterh OP is EQ or NE. */ +int +eq_or_neq (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == EQ || GET_CODE (op) == NE); +} + +/* Return truth value of whether OP can be used as an operands in a three + address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); +} + +/* Return truth value of whether OP can be used as an operand in a two + address arithmetic insn (such as set 123456,%o4) of mode MODE. */ + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +/* Return truth value of whether OP is a integer which fits the + range constraining immediate operands in three-address insns. */ + +int +small_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[1]) != MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("sethi %%hi(%m0),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + return "st %1,[%%lo(%m0)+%%g1]"; + } + else + return "st %r1,%0"; + else + { + rtx xoperands[2]; + + cc_status.flags &= ~CC_F0_IS_0; + xoperands[0] = gen_rtx (REG, SFmode, 32); + xoperands[1] = operands[1]; + output_asm_insn (singlemove_string (xoperands), xoperands); + xoperands[1] = xoperands[0]; + xoperands[0] = operands[0]; + output_asm_insn (singlemove_string (xoperands), xoperands); + return ""; + } + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return "ld [%%lo(%m1)+%%g1],%0"; + } + return "ld %1,%0"; + } + return "mov %1,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. + + RMS says "This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance." + + but it happens on the sparc when loading parameter registers, + so I am going to define that circumstance, and make it work + as expected. */ + + /* Easy case: try moving both words at once. */ + /* First check for moving between an even/odd register pair + and a memory location. */ + if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP + && (REGNO (operands[0]) & 1) == 0) + || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP + && (REGNO (operands[1]) & 1) == 0)) + { + rtx op1, op2; + rtx base = 0, offset = const0_rtx; + + /* OP1 gets the register pair, and OP2 gets the memory address. */ + if (optype0 == REGOP) + op1 = operands[0], op2 = XEXP (operands[1], 0); + else + op1 = operands[1], op2 = XEXP (operands[0], 0); + + /* Now see if we can trust the address to be 8-byte aligned. */ + /* Trust global variables. */ + if (CONSTANT_ADDRESS_P (op2)) + { + operands[0] = op1; + operands[1] = op2; + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == op2)) + output_asm_insn ("sethi %%hi(%1),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = op2; + if (op1 == operands[0]) + return "ldd [%%lo(%1)+%%g1],%0"; + else + return "std [%%lo(%1)+%%g1],%0"; + } + + if (GET_CODE (op2) == PLUS) + { + if (GET_CODE (XEXP (op2, 0)) == REG) + base = XEXP (op2, 0), offset = XEXP (op2, 1); + else if (GET_CODE (XEXP (op2, 1)) == REG) + base = XEXP (op2, 1), offset = XEXP (op2, 0); + } + + /* Trust round enough offsets from the stack or frame pointer. */ + if (base + && (REGNO (base) == FRAME_POINTER_REGNUM + || REGNO (base) == STACK_POINTER_REGNUM)) + { + if (GET_CODE (offset) == CONST_INT + && (INTVAL (offset) & 0x7) == 0) + { + if (op1 == operands[0]) + return "ldd %1,%0"; + else + return "std %1,%0"; + } + } + else + { + /* We know structs not on the stack are properly aligned. + Since a double asks for 8-byte alignment, + we know it must have got that if it is in a struct. + But a DImode need not be 8-byte aligned, because it could be a + struct containing two ints or pointers. */ + + /* Sun fucks us here. We cannot trust references + to doubles via varying addresses. It might be on the stack + even if we don't know that it is; and then it might not be + double-word aligned. */ +#if 0 + if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode + && MEM_IN_STRUCT_P (operands[1])) + return "ldd %1,%0"; + else if (GET_CODE (operands[0]) == MEM + && GET_MODE (operands[0]) == DFmode + && MEM_IN_STRUCT_P (operands[0])) + return "std %1,%0"; +#endif + } + } + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("add %0,0x4,%0", &addreg0); + if (addreg1) + output_asm_insn ("add %0,0x4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("add %0,-0x4,%0", &addreg0); + if (addreg1) + output_asm_insn ("add %0,-0x4,%0", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + /* Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("add %0,0x4,%0", &addreg0); + if (addreg1) + output_asm_insn ("add %0,0x4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("add %0,-0x4,%0", &addreg0); + if (addreg1) + output_asm_insn ("add %0,-0x4,%0", &addreg1); + + return ""; +} + +static char * +output_fp_move_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + { + output_asm_insn ("fmovs %1,%0", operands); + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + return "fmovs %1,%0"; + } + if (GET_CODE (operands[1]) == REG) + { + if ((REGNO (operands[1]) & 1) == 0) + return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; + else + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); + return ""; + } + } + /* Use ldd if known to be aligned. */ + if (GET_CODE (XEXP (operands[1], 0)) == PLUS + && (((XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx + || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) == 0) +#if 0 /* An array in a structure that is a parm need not be aligned! */ + /* Arrays are known to be aligned, + and reg+reg addresses are used (on this machine) + only for array accesses. */ + || (REG_P (XEXP (XEXP (operands[1], 0), 0)) + && REG_P (XEXP (XEXP (operands[1], 0), 1))) +#endif + )) + return "ldd %1,%0"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return "ldd [%%lo(%m1)+%%g1],%0"; + } + /* Otherwise use two ld insns. */ + { + rtx xoperands[2]; + output_asm_insn ("ld %1,%0", operands); + xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), + REGNO (operands[0]) + 1); + if (GET_CODE (XEXP (operands[1], 0)) == PLUS + && offsettable_address_p (1, GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + xoperands[1] = adj_offsettable_operand (operands[1], 4); + output_asm_insn ("ld %1,%0", xoperands); + } + else if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + rtx memref = operands[1]; + rtx inc_reg = XEXP (XEXP (operands[1], 0), 0); + if (inc_reg == frame_pointer_rtx + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == REG + && XEXP (XEXP (operands[1], 0), 1) != frame_pointer_rtx) + inc_reg = XEXP (XEXP (operands[1], 0), 1); + if (inc_reg == frame_pointer_rtx) + { + output_asm_insn ("mov %%fp,%%g1", xoperands); + inc_reg = gen_rtx (REG, SImode, 1); + memref = gen_rtx (GET_CODE (operands[1]), + GET_MODE (operands[1]), + gen_rtx (PLUS, GET_MODE (XEXP (operands[1], 0)), + inc_reg, + XEXP (XEXP (operands[1], 0), 1))); + } + xoperands[1] = inc_reg; + output_asm_insn ("add 4,%1,%1", xoperands); + xoperands[1] = memref; + output_asm_insn ("ld %1,%0", xoperands); + xoperands[1] = inc_reg; + output_asm_insn ("add -4,%1,%1", xoperands); + } + else + { + xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), + plus_constant (XEXP (operands[1], 0), 4)); + output_asm_insn ("ld %1,%0", xoperands); + } + return ""; + } + } + else if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + if ((REGNO (operands[0]) & 1) == 0) + return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; + else + { + rtx xoperands[3]; + xoperands[2] = operands[1]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + xoperands[0] = operands[0]; + output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); + return ""; + } + } + /* Use std if we can be sure it is well-aligned. */ + if (GET_CODE (XEXP (operands[0], 0)) == PLUS + && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx + || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) + && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0) +#if 0 /* An array in a structure that is a parm need not be aligned! */ + /* Arrays are known to be aligned, + and reg+reg addresses are used (on this machine) + only for array accesses. */ + || (REG_P (XEXP (XEXP (operands[0], 0), 0)) + && REG_P (XEXP (XEXP (operands[0], 0), 1))) +#endif + )) + return "std %1,%0"; + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("sethi %%hi(%m0),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + return "std %1,[%%lo(%m0)+%%g1]"; + } + /* Otherwise use two st insns. */ + { + rtx xoperands[2]; + output_asm_insn ("st %r1,%0", operands); + xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), + REGNO (operands[1]) + 1); + if (GET_CODE (XEXP (operands[0], 0)) == PLUS + && offsettable_address_p (1, GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + xoperands[0] = adj_offsettable_operand (operands[0], 4); + output_asm_insn ("st %r1,%0", xoperands); + } + else if (GET_CODE (XEXP (operands[0], 0)) == PLUS) + { + rtx memref = operands[0]; + rtx inc_reg = XEXP (XEXP (operands[0], 0), 0); + if (inc_reg == frame_pointer_rtx + && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG + && XEXP (XEXP (operands[0], 0), 1) != frame_pointer_rtx) + inc_reg = XEXP (XEXP (operands[0], 0), 1); + if (inc_reg == frame_pointer_rtx) + { + output_asm_insn ("mov %%fp,%%g1", xoperands); + inc_reg = gen_rtx (REG, SImode, 1); + memref = gen_rtx (GET_CODE (operands[0]), + GET_MODE (operands[0]), + gen_rtx (PLUS, GET_MODE (XEXP (operands[0], 0)), + inc_reg, + XEXP (XEXP (operands[0], 0), 1))); + } + xoperands[0] = inc_reg; + output_asm_insn ("add 4,%0,%0", xoperands); + xoperands[0] = memref; + output_asm_insn ("st %r1,%0", xoperands); + xoperands[0] = inc_reg; + output_asm_insn ("add -4,%0,%0", xoperands); + } + else + { + xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), + plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn ("st %r1,%0", xoperands); + } + return ""; + } + } + else abort (); +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG + && !(GET_CODE (XEXP (addr, 1)) == REG + && XEXP (addr, 0) == frame_pointer_rtx)) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +void +output_sized_memop (opname, mode) + char *opname; + enum machine_mode mode; +{ + extern struct _iobuf *asm_out_file; + + static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" }; + static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; + char *modename + = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1]; + + fprintf (asm_out_file, "\t%s%s", opname, modename); +} + +/* Output a store-in-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */ + +char * +output_store (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[0], 0); + + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && address == cc_prev_status.mdep)) + { + output_asm_insn ("sethi %%hi(%m0),%%g1", operands); + cc_prev_status.mdep = address; + } + + /* Store zero in two parts when appropriate. */ + if (mode == DFmode && operands[1] == dconst0_rtx) + { + /* We can't cross a page boundary here because the + SYMBOL_REF must be double word aligned, and for this + to be the case, SYMBOL_REF+4 cannot cross. */ + output_sized_memop ("st", SImode); + output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands); + output_sized_memop ("st", SImode); + return "%r1,[%%g1+%%lo(%m0)+4]"; + } + + /* Code below isn't smart enough to move a doubleword in two parts, + so use output_move_double to do that in the cases that require it. */ + if ((mode == DImode || mode == DFmode) + && (GET_CODE (operands[1]) == REG + && (REGNO (operands[1]) & 1))) + return output_move_double (operands); + + output_sized_memop ("st", mode); + return "%r1,[%%g1+%%lo(%m0)]"; +} + +/* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */ + +char * +output_load_fixed (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[1], 0); + + /* We don't bother trying to see if we know %hi(address). + This is because we are doing a load, and if we know the + %hi value, we probably also know that value in memory. */ + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && address == cc_prev_status.mdep + && cc_prev_status.mdep == cc_status.mdep)) + { + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_prev_status.mdep = address; + } + + /* Code below isn't smart enough to do a doubleword in two parts. + So handle that case the slow way. */ + if (mode == DImode + && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */ + && (REGNO (operands[0]) & 1)) + return output_move_double (operands); + + output_sized_memop ("ld", mode); + if (GET_CODE (operands[0]) == REG) + return "[%%g1+%%lo(%m1)],%0"; + abort (); +} + +/* Output a floating-point load-from-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a reg, and OPERANDS[1] is a mem. + We also handle the case where OPERANDS[0] is a mem. */ + +char * +output_load_floating (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[1], 0); + + /* We don't bother trying to see if we know %hi(address). + This is because we are doing a load, and if we know the + %hi value, we probably also know that value in memory. */ + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && address == cc_prev_status.mdep + && cc_prev_status.mdep == cc_status.mdep)) + { + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_prev_status.mdep = address; + } + + if (mode == DFmode) + { + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) & 1) + return output_move_double (operands); + else + return "ldd [%%g1+%%lo(%m1)],%0"; + } + cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0); + output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands); + operands[1] = gen_rtx (REG, DFmode, 32); + return output_fp_move_double (operands); + } + + if (GET_CODE (operands[0]) == MEM) + { + cc_status.flags &= ~CC_F1_IS_0; + output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands); + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + cc_status.mdep = XEXP (operands[0], 0); + return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]"; + } + else + return "st %%f1,%0"; + } + return "ld [%%g1+%%lo(%m1)],%0"; +} + +/* Load the address specified by OPERANDS[3] into the register + specified by OPERANDS[0]. + + OPERANDS[3] may be the result of a sum, hence it could either be: + + (1) CONST + (2) REG + (2) REG + CONST_INT + (3) REG + REG + CONST_INT + (4) REG + REG (special case of 3). + + Note that (3) is not a legitimate address. + All cases are handled here. */ + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("set %3,%0", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("mov %3,%0", operands); + return; + } + + if (GET_CODE (operands[3]) != PLUS) + abort (); + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + { + /* Operand is (PLUS (REG) (REG)). */ + base = operands[3]; + offset = const0_rtx; + } + + if (REG_P (base)) + { + operands[6] = base; + operands[7] = offset; + if (SMALL_INT (offset)) + output_asm_insn ("add %6,%7,%0", operands); + else + output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); + } + else if (GET_CODE (base) == PLUS) + { + operands[6] = XEXP (base, 0); + operands[7] = XEXP (base, 1); + operands[8] = offset; + + if (SMALL_INT (offset)) + output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); + else + output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); + } + else + abort (); +} + +/* Output code to place a size count SIZE in register REG. + ALIGN is the size of the unit of transfer. + + Because block moves are pipelined, we don't include the + first element in the transfer of SIZE to REG. */ + +static void +output_size_for_block_move (size, reg, align) + rtx size, reg; + rtx align; +{ + rtx xoperands[3]; + + xoperands[0] = reg; + xoperands[1] = size; + xoperands[2] = align; + if (GET_CODE (size) == REG) + output_asm_insn ("sub %1,%2,%0", xoperands); + else + { + xoperands[1] + = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); + cc_status.flags &= ~ CC_KNOW_HI_G1; + output_asm_insn ("set %1,%0", xoperands); + } +} + +/* Emit code to perform a block move. + + OPERANDS[0] is the destination. + OPERANDS[1] is the source. + OPERANDS[2] is the size. + OPERANDS[3] is the alignment safe to use. + OPERANDS[4] is a register we can safely clobber as a temp. */ + +char * +output_block_move (operands) + rtx *operands; +{ + /* A vector for our computed operands. Note that load_output_address + makes use of (and can clobber) up to the 8th element of this vector. */ + rtx xoperands[10]; + rtx zoperands[10]; + static int movstrsi_label = 0; + int i, j; + rtx temp1 = operands[4]; + rtx alignrtx = operands[3]; + int align = INTVAL (alignrtx); + + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = temp1; + + /* We can't move more than four bytes at a time + because we have only one register to move them through. */ + if (align > 4) + { + align = 4; + alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); + } + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Recognize special cases of block moves. These occur + when GNU C++ is forced to treat something as BLKmode + to keep it in memory, when its mode could be represented + with something smaller. + + We cannot do this for global variables, since we don't know + what pages they don't cross. Sigh. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) <= 16 + && ! CONSTANT_ADDRESS_P (operands[0]) + && ! CONSTANT_ADDRESS_P (operands[1])) + { + int size = INTVAL (operands[2]); + + cc_status.flags &= ~CC_KNOW_HI_G1; + if (align == 1) + { + if (memory_address_p (QImode, plus_constant (xoperands[0], size)) + && memory_address_p (QImode, plus_constant (xoperands[1], size))) + { + /* We will store different integers into this particular RTX. */ + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); + for (i = size-1; i >= 0; i--) + { + INTVAL (xoperands[2]) = i; + output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", + xoperands); + } + return ""; + } + } + else if (align == 2) + { + if (memory_address_p (HImode, plus_constant (xoperands[0], size)) + && memory_address_p (HImode, plus_constant (xoperands[1], size))) + { + /* We will store different integers into this particular RTX. */ + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); + for (i = (size>>1)-1; i >= 0; i--) + { + INTVAL (xoperands[2]) = i<<1; + output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", + xoperands); + } + return ""; + } + } + else + { + if (memory_address_p (SImode, plus_constant (xoperands[0], size)) + && memory_address_p (SImode, plus_constant (xoperands[1], size))) + { + /* We will store different integers into this particular RTX. */ + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); + for (i = (size>>2)-1; i >= 0; i--) + { + INTVAL (xoperands[2]) = i<<2; + output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", + xoperands); + } + return ""; + } + } + } + + /* This is the size of the transfer. + Either use the register which already contains the size, + or use a free register (used by no operands). + Also emit code to decrement the size value by ALIGN. */ + output_size_for_block_move (operands[2], temp1, alignrtx); + + zoperands[0] = operands[0]; + zoperands[3] = plus_constant (operands[0], align); + output_load_address (zoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); + +#ifdef NO_UNDERSCORES + if (align == 1) + output_asm_insn ("\n.Lm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tstb %%g1,[%0+%2]", xoperands); + else if (align == 2) + output_asm_insn ("\n.Lm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tsth %%g1,[%0+%2]", xoperands); + else + output_asm_insn ("\n.Lm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tst %%g1,[%0+%2]", xoperands); +#else + if (align == 1) + output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands); + else if (align == 2) + output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands); + else + output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands); +#endif + return ""; +} + +/* What the sparc lacks in hardware, make up for in software. + Compute a fairly good sequence of shift and add insns + to make a multiply happen. */ + +#define ABS(x) ((x) < 0 ? -(x) : x) + +char * +output_mul_by_constant (insn, operands, unsignedp) + rtx insn; + rtx *operands; + int unsignedp; +{ + int c; /* Size of constant */ + int shifts[BITS_PER_WORD]; /* Table of shifts */ + unsigned int p, log; /* A power of two, and its log */ + int d1, d2; /* Differences of c and p */ + int first = 1; /* True if dst has unknown data in it */ + int i; + + CC_STATUS_INIT; + + c = INTVAL (operands[2]); + if (c == 0) + { + /* Does happen, at least when not optimizing. */ + if (GET_CODE (operands[0]) == MEM) + return "st %%g0,%0"; + return "mov %%g0,%0"; + } + + output_asm_insn ("! start open coded multiply"); + + /* Clear out the table of shifts. */ + for (i = 0; i < BITS_PER_WORD; ++i) + shifts[i] = 0; + + while (c) + { + /* Find the power of two nearest ABS(c) */ + p = 1, log = 0; + do + { + d1 = ABS(c) - p; + p *= 2; + ++log; + } + while (p < ABS(c)); + d2 = p - ABS(c); + + /* Make an appropriate entry in shifts for p. */ + if (d2 < d1) + { + shifts[log] = c < 0 ? -1 : 1; + c = c < 0 ? d2 : -d2; + } + else + { + shifts[log - 1] = c < 0 ? -1 : 1; + c = c < 0 ? -d1 : d1; + } + } + + /* Take care of the first insn in sequence. + We know we have at least one. */ + + /* A value of -1 in shifts says to subtract that power of two, and a value + of 1 says to add that power of two. */ + for (i = 0; ; i++) + if (shifts[i]) + { + if (i) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn ("sll %1,%2,%%g1", operands); + } + else output_asm_insn ("mov %1,%%g1", operands); + + log = i; + if (shifts[i] < 0) + output_asm_insn ("sub %%g0,%%g1,%0", operands); + else + output_asm_insn ("mov %%g1,%0", operands); + break; + } + + /* A value of -1 in shifts says to subtract that power of two, and a value + of 1 says to add that power of two--continued. */ + for (i += 1; i < BITS_PER_WORD; ++i) + if (shifts[i]) + { + if (i - log > 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); + output_asm_insn ("sll %%g1,%2,%%g1", operands); + } + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); + output_asm_insn ("sra %%g1,%2,%%g1", operands); + } + log = i; + if (shifts[i] < 0) + output_asm_insn ("sub %0,%%g1,%0", operands); + else + output_asm_insn ("add %0,%%g1,%0", operands); + } + + output_asm_insn ("! end open coded multiply"); + + return ""; +} + +char * +output_mul_insn (operands, unsignedp) + rtx *operands; + int unsignedp; +{ + int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; + int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; + + CC_STATUS_INIT; + + if (lucky1) + { + if (lucky2) + { + if (REGNO (operands[1]) == REGNO (operands[2])) + { + if (REGNO (operands[1]) == 8) + output_asm_insn ("mov %%o0,%%o1"); + else + output_asm_insn ("mov %%o1,%%o0"); + } + output_asm_insn ("call .mul,2\n\tnop", operands); + } + else + { + rtx xoperands[2]; + xoperands[0] = gen_rtx (REG, SImode, + 8 ^ (REGNO (operands[1]) == 8)); + xoperands[1] = operands[2]; + output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); + } + } + else if (lucky2) + { + rtx xoperands[2]; + xoperands[0] = gen_rtx (REG, SImode, + 8 ^ (REGNO (operands[2]) == 8)); + xoperands[1] = operands[1]; + output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); + } + else + { + output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", + operands); + } + + if (REGNO (operands[0]) == 8) + return ""; + return "mov %%o0,%0"; +} + +/* Make floating point register f0 contain 0. + SIZE is the number of registers (including f0) + which should contain 0. */ + +void +make_f0_contain_0 (size) + int size; +{ + if (size == 1) + { + if ((cc_status.flags & (CC_F0_IS_0)) == 0) + output_asm_insn ("ld [%%fp-16],%%f0", 0); + cc_status.flags |= CC_F0_IS_0; + } + else if (size == 2) + { + if ((cc_status.flags & CC_F0_IS_0) == 0) + output_asm_insn ("ld [%%fp-16],%%f0", 0); + if ((cc_status.flags & (CC_F1_IS_0)) == 0) + output_asm_insn ("ld [%%fp-12],%%f1", 0); + cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0; + } +} + +/* Since condition codes don't have logical links, we need to keep + their setting and use together for set-cc insns. */ +void +gen_scc_insn (code, mode, operands) + enum rtx_code code; + enum machine_mode mode; + rtx *operands; +{ + extern rtx sequence_stack; + rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0); + rtx last_pat; + + /* Skip back over the CLOBBERs that may precede this insn. */ + while (last_insn && GET_CODE (last_insn) == INSN + && GET_CODE (PATTERN (last_insn)) == CLOBBER) + last_insn = PREV_INSN (last_insn); + /* We should have found the preceding compare. */ + if (last_insn == 0 || GET_CODE (last_insn) != INSN) + abort (); + last_pat = PATTERN (last_insn); + if (GET_CODE (last_pat) != SET + || GET_CODE (SET_DEST (last_pat)) != CC0) + abort (); + + /* Turn off that previous insn, now that we have got the data out of it. */ + PUT_CODE (last_insn, NOTE); + NOTE_LINE_NUMBER (last_insn) = NOTE_INSN_DELETED; + + /* Emit one replacement insn to compare operands and store result. */ + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx))); +} + +/* Output reasonable peephole for set-on-condition-code insns. + Note that these insns assume a particular way of defining + labels. Therefore, *both* tm-sparc.h and this function must + be changed if a new syntax is needed. */ + +char * +output_scc_insn (code, operand) + enum rtx_code code; + rtx operand; +{ + rtx xoperands[2]; + rtx label = gen_label_rtx (); + int cc_in_fccr = cc_status.flags & CC_IN_FCCR; + int antisymmetric = 0; + + xoperands[0] = operand; + xoperands[1] = label; + + switch (code) + { + case NE: + if (cc_in_fccr) + output_asm_insn ("fbne,a %l0", &label); + else + output_asm_insn ("bne,a %l0", &label); + break; + case EQ: + if (cc_in_fccr) + output_asm_insn ("fbe,a %l0", &label); + else + output_asm_insn ("be,a %l0", &label); + break; + case GE: + if (cc_in_fccr) + output_asm_insn ("fbge,a %l0", &label); + else + output_asm_insn ("bge,a %l0", &label); + antisymmetric = 1; + break; + case GT: + if (cc_in_fccr) + output_asm_insn ("fbg,a %l0", &label); + else + output_asm_insn ("bg,a %l0", &label); + antisymmetric = 1; + break; + case LE: + if (cc_in_fccr) + output_asm_insn ("fble,a %l0", &label); + else + output_asm_insn ("ble,a %l0", &label); + antisymmetric = 1; + break; + case LT: + if (cc_in_fccr) + output_asm_insn ("fbl,a %l0", &label); + else + output_asm_insn ("bl,a %l0", &label); + antisymmetric = 1; + break; + case GEU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("bgeu,a %l0", &label); + antisymmetric = 1; + break; + case GTU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("bgu,a %l0", &label); + antisymmetric = 1; + break; + case LEU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("bleu,a %l0", &label); + antisymmetric = 1; + break; + case LTU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("blu,a %l0", &label); + antisymmetric = 1; + break; + default: + abort (); + } + + if (antisymmetric + && (cc_status.flags & CC_REVERSED)) + output_asm_insn ("orcc %%g0,0,%0\n\torcc %%g0,1,%0\n%l1:", xoperands); + else + output_asm_insn ("orcc %%g0,1,%0\n\torcc %%g0,0,%0\n%l1:", xoperands); + cc_status.flags &= ~CC_IN_FCCR; + + return ""; +} + +/* Output a delayed branch insn with the delay insn in its + branch slot. The delayed branch insn template is in TEMPLATE, + with operands OPERANDS. The insn in its delay slot is INSN. + + As a special case, since we know that all memory transfers are via + ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory + reference around the branch as + + sethi %hi(x),%%g1 + b ... + ld/st [%g1+%lo(x)],... + + As another special case, we handle loading (SYMBOL_REF ...) and + other large constants around branches as well: + + sethi %hi(x),%0 + b ... + or %0,%lo(x),%1 + + */ + +char * +output_delayed_branch (template, operands, insn) + char *template; + rtx *operands; + rtx insn; +{ + extern rtx recog_operand[]; + rtx src = XVECEXP (PATTERN (insn), 0, 1); + rtx dest = XVECEXP (PATTERN (insn), 0, 0); + + if (GET_CODE (src) == SYMBOL_REF + || (GET_CODE (src) == CONST_INT + && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0))) + { + rtx xoperands[2]; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `sethi' insn. */ + output_asm_insn ("sethi %%hi(%1),%0", xoperands); + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the `or' insn. */ + output_asm_insn ("or %0,%%lo(%1),%0", xoperands); + } + else if ((GET_CODE (src) == MEM + && CONSTANT_ADDRESS_P (XEXP (src, 0))) + || (GET_CODE (dest) == MEM + && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) + { + rtx xoperands[2]; + char *split_template; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `sethi' insn. */ + if (GET_CODE (src) == MEM) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands); + split_template = "ld [%%g1+%%lo(%m1)],%0"; + } + else + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands); + split_template = "st %r1,[%%g1+%%lo(%m0)]"; + } + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the load or store. + No need to do a CC_STATUS_INIT, because we are branching anyway. */ + output_asm_insn (split_template, xoperands); + } + else + { + extern char *insn_template[]; + extern char *(*insn_outfun[])(); + int insn_code_number; + rtx pat = gen_rtx (SET, VOIDmode, dest, src); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + int i; + extern rtx alter_subreg(); + extern int insn_n_operands[]; + + /* Output the branch instruction first. */ + output_asm_insn (template, operands); + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog (pat, delay_insn); + if (insn_code_number == -1) + abort (); + + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + + /* Now get the template for what this insn would + have been, without the branch. Its operands are + exactly the same as they would be, so we don't + need to do an insn_extract. */ + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + } + CC_STATUS_INIT; + return ""; +} + +/* Output a newly constructed insn DELAY_INSN. */ +char * +output_delay_insn (delay_insn) + rtx delay_insn; +{ + char *template; + extern rtx recog_operand[]; + extern char call_used_regs[]; + extern char *insn_template[]; + extern int insn_n_operands[]; + extern char *(*insn_outfun[])(); + extern rtx alter_subreg(); + int insn_code_number; + extern int insn_n_operands[]; + int i; + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog_memoized (delay_insn); + if (insn_code_number == -1) + abort (); + + /* Extract the operands of this delay insn. */ + INSN_CODE (delay_insn) = insn_code_number; + insn_extract (delay_insn); + + /* It is possible that this insn has not been properly scaned by final + yet. If this insn's operands don't appear in the peephole's + actual operands, then they won't be fixed up by final, so we + make sure they get fixed up here. -- This is a kludge. */ + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + +#ifdef REGISTER_CONSTRAINTS + if (! constrain_operands (insn_code_number)) + abort (); +#endif + + cc_prev_status = cc_status; + + /* Update `cc_status' for this instruction. + The instruction's output routine may change it further. + If the output routine for a jump insn needs to depend + on the cc status, it should look at cc_prev_status. */ + + NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); + + /* Now get the template for what this insn would + have been, without the branch. */ + + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + return ""; +} + +/* Output the insn HEAD, keeping OPERANDS protected (wherever they are). + HEAD comes from the target of some branch, so before we output it, + we delete it from the target, lest we execute it twice. The caller + of this function promises that such code motion is permissable. */ +char * +output_eager_then_insn (head, operands) + rtx head; + rtx *operands; +{ + extern rtx alter_subreg (); + extern int insn_n_operands[]; + extern rtx recog_operand[]; + rtx xoperands[MAX_RECOG_OPERANDS]; + int insn_code_number, i, nbytes; + rtx nhead; + + /* Micro-hack: run peephole on head if it looks like a good idea. + Right now there's only one such case worth doing... + + This could be made smarter if the peephole for ``2-insn combine'' + were also made smarter. */ + if (GET_CODE (PATTERN (head)) == SET + && REG_P (SET_SRC (PATTERN (head))) + && REG_P (SET_DEST (PATTERN (head))) + && (nhead = next_real_insn_no_labels (head)) + && GET_CODE (nhead) == INSN + && GET_CODE (PATTERN (nhead)) == SET + && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0 + && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head)) + || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head)))) + /* Something's wrong if this does not fly. */ + if (! peephole (head)) + abort (); + + /* Save our contents of `operands', since output_delay_insn sets them. */ + insn_code_number = recog_memoized (head); + nbytes = insn_n_operands[insn_code_number] * sizeof (rtx); + bcopy (operands, xoperands, nbytes); + + /* Output the delay insn, and prevent duplication later. */ + delete_insn (head); + output_delay_insn (head); + + /* Restore this insn's operands. */ + bcopy (xoperands, operands, nbytes); +} + +/* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL; + or 0, if there is none. Also return 0 if we cross a label. */ + +rtx +next_real_insn_no_labels (label) + rtx label; +{ + register rtx insn = NEXT_INSN (label); + register RTX_CODE code; + + while (insn) + { + code = GET_CODE (insn); + if (code == INSN) + { + if (GET_CODE (PATTERN (insn)) != CLOBBER + && GET_CODE (PATTERN (insn)) != USE) + return insn; + } + if (code == CALL_INSN || code == JUMP_INSN) + return insn; + if (code == CODE_LABEL) + return 0; + insn = NEXT_INSN (insn); + } + + return 0; +} + +int +operands_satisfy_eager_branch_peephole (operands, conditional) + rtx *operands; + int conditional; +{ + rtx label; + + if (conditional) + { + if (GET_CODE (operands[0]) != IF_THEN_ELSE) + return 0; + + if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF) + label = XEXP (XEXP (operands[0], 1), 0); + else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF) + label = XEXP (XEXP (operands[0], 2), 0); + else return 0; + } + else + { + label = operands[0]; + } + + if (LABEL_NUSES (label) == 1) + { + rtx prev = PREV_INSN (label); + while (prev && GET_CODE (prev) == NOTE) + prev = PREV_INSN (prev); + if (prev == 0 + || GET_CODE (prev) == BARRIER) + { + rtx head = next_real_insn_no_labels (label); + + if (head + && ! INSN_DELETED_P (head) + && GET_CODE (head) == INSN + && GET_CODE (PATTERN (head)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (head)), + GET_MODE (SET_DEST (PATTERN (head)))) + && strict_single_insn_op_p (SET_DEST (PATTERN (head)), + GET_MODE (SET_DEST (PATTERN (head)))) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (head))) == REG + && GET_CODE (SET_DEST (PATTERN (head))) == REG + && (FP_REG_P (SET_SRC (PATTERN (head))) + != FP_REG_P (SET_DEST (PATTERN (head)))))) + { + if (conditional == 2) + return (GET_CODE (operands[1]) != PC + && safe_insn_src_p (operands[2], VOIDmode) + && strict_single_insn_op_p (operands[2], VOIDmode) + && operand_clobbered_before_used_after (operands[1], label)); + return 1; + } + } + } + + if (conditional == 1 + && GET_CODE (operands[1]) != PC + && safe_insn_src_p (operands[2], VOIDmode) + && strict_single_insn_op_p (operands[2], VOIDmode) + && operand_clobbered_before_used_after (operands[1], label)) + return 1; + + return 0; +} + diff --git a/gcc-1.40/config/out-spur.c b/gcc-1.40/config/out-spur.c new file mode 100644 index 0000000..0e5c5a8 --- /dev/null +++ b/gcc-1.40/config/out-spur.c @@ -0,0 +1,316 @@ +/* Subroutines for insn-output.c for SPUR. Adapted from routines for + the Motorola 68000 family. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static rtx find_addr_reg (); + +char * +output_compare (operands, opcode, exchange_opcode, + neg_opcode, neg_exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; + char *neg_opcode; + char *neg_exchange_opcode; +{ + static char buf[100]; + operands[2] = operands[0]; + if (GET_CODE (cc_prev_status.value1) == CONST_INT) + { + operands[1] = cc_prev_status.value1; + operands[0] = cc_prev_status.value2; + opcode = exchange_opcode, neg_opcode = neg_exchange_opcode; + } + else + { + operands[0] = cc_prev_status.value1; + operands[1] = cc_prev_status.value2; + } + if (TARGET_LONG_JUMPS) + sprintf (buf, + "cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:", + neg_opcode); + else + sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode); + return buf; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + return "st_32 %r1,%0"; + if (GET_CODE (operands[1]) == MEM) + return "ld_32 %0,%1\n\tnop"; + if (GET_CODE (operands[1]) == REG) + return "add_nt %0,%1,$0"; + return "add_nt %0,r0,%1"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$-4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$-4", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$-4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$-4", &addreg1); + + return ""; +} + +static char * +output_fp_move_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return "fmov %0,%1"; + if (GET_CODE (operands[1]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); + output_asm_insn ("st_32 %1,r25,%0", xoperands); + xoperands[1] = operands[1]; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + output_asm_insn ("st_32 %1,r25,%0", xoperands); + xoperands[1] = operands[0]; + output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands); + return ""; + } + return "ld_dbl %0,%1\n\tnop"; + } + else if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + xoperands[1] = operands[1]; + output_asm_insn ("st_dbl %1,r25,%0", xoperands); + xoperands[1] = operands[0]; + output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); + output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); + return ""; + } + return "st_dbl %1,%0"; + } +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +/* Generate code to add a large integer constant to register, reg, storing + * the result in a register, target. Offset must be 27-bit signed quantity */ + +static char * +output_add_large_offset (target, reg, offset) + rtx target, reg; + int offset; +{ + rtx operands[3]; + int high, n, i; + operands[0] = target, operands[1] = reg; + + for (high = offset, n = 0; + (unsigned) (high + 0x2000) >= 0x4000; + high >>= 1, n += 1) + ; + operands[2] = gen_rtx (CONST_INT, VOIDmode, high); + output_asm_insn ("add_nt r2,r0,%2", operands); + i = n; + while (i >= 3) + output_asm_insn ("sll r2,r2,$3", operands), i -= 3; + if (i == 2) + output_asm_insn ("sll r2,r2,$2", operands); + else if (i == 1) + output_asm_insn ("sll r2,r2,$1", operands); + output_asm_insn ("add_nt %0,r2,%1", operands); + if (offset - (high << n) != 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, offset - (high << n)); + output_asm_insn ("add_nt %0,%0,%2", operands); + } + return ""; +} + +/* Additional TESTFN for matching. Like immediate_operand, but matches big + * constants */ + +int +big_immediate_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT); +} diff --git a/gcc-1.40/config/out-tahoe.c b/gcc-1.40/config/out-tahoe.c new file mode 100644 index 0000000..47f9591 --- /dev/null +++ b/gcc-1.40/config/out-tahoe.c @@ -0,0 +1,550 @@ +/* Subroutines for insn-output.c for Tahoe. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + * File: output-tahoe.c + * + * This port made at the University of Buffalo by Devon Bowen, + * Dale Wiles and Kevin Zachmann. + * + * Mail bugs reports or fixes to: gcc@cs.buffalo.edu + */ + + +/* most of the print_operand_address function was taken from the vax */ +/* since the modes are basically the same. I had to add a special case, */ +/* though, for symbol references with offsets. */ + +#include <stdio.h> + +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + static char *reg_name[] = REGISTER_NAMES; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + fprintf (file, "*"); + addr = XEXP (addr, 0); + goto retry; + + case REG: + fprintf (file, "(%s)", reg_name [REGNO (addr)]); + break; + + case PRE_DEC: + fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]); + break; + + case POST_INC: + fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]); + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = 0; + + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) + && GET_CODE (XEXP (addr, 1)) == CONST_INT) + output_addr_const (file, addr); + + if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) + && GET_CODE (XEXP (addr, 0)) == CONST_INT) + output_addr_const (file, addr); + + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) + || GET_CODE (XEXP (addr, 0)) == MEM) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) + || GET_CODE (XEXP (addr, 1)) == MEM) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) + ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { + if (reg1 == 0) + reg1 = addr; + else + reg2 = addr; + addr = 0; + } + if (offset != 0) + { + if (addr != 0) abort (); + addr = offset; + } + if (reg1 != 0 && GET_CODE (reg1) == MULT) + { + breg = reg2; + ireg = reg1; + } + else if (reg2 != 0 && GET_CODE (reg2) == MULT) + { + breg = reg1; + ireg = reg2; + } + else if (reg2 != 0 || GET_CODE (addr) == MEM) + { + breg = reg2; + ireg = reg1; + } + else + { + breg = reg1; + ireg = reg2; + } + if (addr != 0) + output_address (offset); + if (breg != 0) + { + if (GET_CODE (breg) != REG) + abort (); + fprintf (file, "(%s)", reg_name[REGNO (breg)]); + } + if (ireg != 0) + { + if (GET_CODE (ireg) == MULT) + ireg = XEXP (ireg, 0); + if (GET_CODE (ireg) != REG) + abort (); + fprintf (file, "[%s]", reg_name[REGNO (ireg)]); + } + break; + + default: + output_addr_const (file, addr); + } +} + + +/* Do a quick check and find out what the best way to do the */ +/* mini-move is. Could be a push or a move..... */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0],0)) == PRE_DEC) + return "pushl %1"; + return "movl %1,%0"; +} + + +/* given the rtx for an address, return true if the given */ +/* register number is used in the address somewhere. */ + +int +regisused (addr,regnum) + rtx addr; + int regnum; +{ + if (GET_CODE (addr) == REG) + { + if (REGNO (addr) == regnum) + return (1); + else + return (0); + } + + if (GET_CODE (addr) == MEM) + return regisused (XEXP (addr,0),regnum); + + if (GET_CODE (addr) == MULT || GET_CODE (addr) == PLUS) + return (regisused (XEXP (addr,0),regnum) + || regisused (XEXP (addr,1),regnum)); + + return 0; +} + + +/* Given some rtx, traverse it and return the register used in a */ +/* index. If no index is found, return 0. */ + +rtx +index_reg (addr) + rtx addr; +{ + rtx temp; + + if (GET_CODE (addr) == MEM) + return index_reg (XEXP (addr,0)); + + if (GET_CODE (addr) == MULT) + { + if (GET_CODE (XEXP (addr,0)) == REG) + return XEXP (addr,0); + else + return XEXP (addr,1); + } + + if (GET_CODE (addr) == PLUS) + { + if (temp = index_reg (XEXP (addr,0))) + return temp; + else + return index_reg (XEXP (addr,1)); + } + + return 0; +} + + +/* simulate the move double by generating two movl's. You have */ +/* to be careful about mixing modes here. A future improvement */ +/* would be to allow immediate doubles. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx shftreg0 = 0, shftreg1 = 0; + rtx temp0 = 0, temp1 = 0; + rtx addreg0 = 0, addreg1 = 0; + int dohighfirst = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if ((GET_CODE (operands[0])==MEM) && (shftreg0=index_reg (operands[0]))) + optype0 = INDOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + optype0 = PUSHOP; + dohighfirst++; + } + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if ((GET_CODE (operands[1])==MEM) && (shftreg1=index_reg (operands[1]))) + optype1 = INDOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else if (GET_CODE (operands[1]) == CONST_DOUBLE || CONSTANT_P (operands[1])) + optype1 = CNSTOP; + else + optype1 = RNDOP; + + /* set up for the high byte move for operand zero */ + + switch (optype0) + { + + /* if it's a register, just use the next highest in the */ + /* high address move. */ + + case REGOP: + latehalf[0] = gen_rtx (REG,SImode,REGNO (operands[0])+1); + break; + + /* for an offsettable address, use the gcc function to */ + /* modify the operand to get an offset of 4 higher for */ + /* the second move. */ + + case OFFSOP: + latehalf[0] = adj_offsettable_operand (operands[0], 4); + break; + + /* if the operand is MEMOP type, it must be a pointer */ + /* to a pointer. So just remember to increase the mem */ + /* location and use the same operand. */ + + case MEMOP: + latehalf[0] = operands[0]; + addreg0 = XEXP (operands[0],0); + break; + + /* if we're dealing with a push instruction, just leave */ + /* the operand alone since it auto-increments. */ + + case PUSHOP: + latehalf[0] = operands[0]; + break; + + /* YUCK! Indexed addressing!! If the address is considered */ + /* offsettable, go use the offset in the high part. Otherwise */ + /* find what exactly is being added to the mutiplication. If */ + /* it's a mem reference, increment that with the high part */ + /* being unchanged to cause the shift. If it's a reg, do the */ + /* same. If you can't identify it, abort. Remember that the */ + /* shift register was already set during identification. */ + + case INDOP: + if (offsettable_memref_p (operands[0])) + { + latehalf[0] = adj_offsettable_operand (operands[0],4); + break; + } + + latehalf[0] = operands[0]; + + temp0 = XEXP (XEXP (operands[0],0),0); + if (GET_CODE (temp0) == MULT) + { + temp1 = temp0; + temp0 = XEXP (XEXP (operands[0],0),1); + } + else + { + temp1 = XEXP (XEXP (operands[0],0),1); + if (GET_CODE (temp1) != MULT) + abort (); + } + + if (GET_CODE (temp0) == MEM) + addreg0 = temp0; + else if (GET_CODE (temp0) == REG) + addreg0 = temp0; + else + abort (); + + break; + + /* if we don't know the operand type, print a friendly */ + /* little error message... 8-) */ + + case RNDOP: + default: + abort (); + } + + /* do the same setup for operand one */ + + switch (optype1) + { + + case REGOP: + latehalf[1] = gen_rtx (REG,SImode,REGNO (operands[1])+1); + break; + + case OFFSOP: + latehalf[1] = adj_offsettable_operand (operands[1], 4); + break; + + case MEMOP: + latehalf[1] = operands[1]; + addreg1 = XEXP (operands[1],0); + break; + + case POPOP: + latehalf[1] = operands[1]; + break; + + case INDOP: + if (offsettable_memref_p (operands[1])) + { + latehalf[1] = adj_offsettable_operand (operands[1],4); + break; + } + + latehalf[1] = operands[1]; + + temp0 = XEXP (XEXP (operands[1],0),0); + if (GET_CODE (temp0) == MULT) + { + temp1 = temp0; + temp0 = XEXP (XEXP (operands[1],0),1); + } + else + { + temp1 = XEXP (XEXP (operands[1],0),1); + if (GET_CODE (temp1) != MULT) + abort (); + } + + if (GET_CODE (temp0) == MEM) + addreg1 = temp0; + else if (GET_CODE (temp0) == REG) + addreg1 = temp0; + else + abort (); + + break; + + case CNSTOP: + /* Since this machine is big-endian, + the late half must be the low-order word for an integer, + or the latter word for a float. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + else + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + } + } + else + { + latehalf[1] = operands[1]; + operands[1] = const0_rtx; + } + break; + + case RNDOP: + default: + abort (); + } + + + /* double the register used for shifting in both of the operands */ + /* but make sure the same register isn't doubled twice! */ + + if (shftreg0 && shftreg1 && rtx_equal_p (shftreg0, shftreg1)) + output_asm_insn ("addl2 %0,%0", &shftreg0); + else + { + if (shftreg0) + output_asm_insn ("addl2 %0,%0", &shftreg0); + if (shftreg1) + output_asm_insn ("addl2 %0,%0", &shftreg1); + } + + /* if the destination is a register and that register is needed in */ + /* the source addressing mode, swap the order of the moves since we */ + /* don't want this destroyed til last. If both regs are used, not */ + /* much we can do, so abort. If these becomes a problem, maybe we */ + /* can do it on the stack? */ + + if (GET_CODE (operands[0])==REG && regisused (operands[1],REGNO (operands[0]))) + if (regisused (latehalf[1],REGNO (latehalf[0]))) + 8; + else + dohighfirst++; + + /* if we're pushing, do the high address part first. */ + + if (dohighfirst) + { + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("addl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("addl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addl2 $4,%0", &addreg1); + } + + output_asm_insn (singlemove_string (latehalf), latehalf); + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("subl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("subl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subl2 $4,%0", &addreg1); + } + + return singlemove_string (operands); + } + + output_asm_insn (singlemove_string (operands), operands); + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("addl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("addl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addl2 $4,%0", &addreg1); + } + + output_asm_insn (singlemove_string (latehalf), latehalf); + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("subl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("subl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subl2 $4,%0", &addreg1); + } + + if (shftreg0 && shftreg1 && (rtx_equal_p (shftreg0,shftreg1))) + output_asm_insn ("shar $1,%0,%0", &shftreg0); + else + { + if (shftreg0) + output_asm_insn ("shar $1,%0,%0", &shftreg0); + if (shftreg1) + output_asm_insn ("shar $1,%0,%0", &shftreg1); + } + + return ""; +} diff --git a/gcc-1.40/config/out-vax.c b/gcc-1.40/config/out-vax.c new file mode 100644 index 0000000..a17590b --- /dev/null +++ b/gcc-1.40/config/out-vax.c @@ -0,0 +1,152 @@ +/* Subroutines for insn-output.c for Vax. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> + +/* This function allows any constant operand, even on VMS where some + constants are not normally legitimate. */ + +int +supergeneral_operand (x, mode) + rtx x; + enum machine_mode mode; +{ + return (CONSTANT_P (x) || general_operand (x, mode)); +} + +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + fprintf (file, "*"); + addr = XEXP (addr, 0); + goto retry; + + case REG: + fprintf (file, "(%s)", reg_names[REGNO (addr)]); + break; + + case PRE_DEC: + fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); + break; + + case POST_INC: + fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = 0; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) + || GET_CODE (XEXP (addr, 0)) == MEM) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) + || GET_CODE (XEXP (addr, 1)) == MEM) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) + ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { + if (reg1 == 0) + reg1 = addr; + else + reg2 = addr; + addr = 0; + } + if (offset != 0) + { + if (addr != 0) abort (); + addr = offset; + } + if (reg1 != 0 && GET_CODE (reg1) == MULT) + { + breg = reg2; + ireg = reg1; + } + else if (reg2 != 0 && GET_CODE (reg2) == MULT) + { + breg = reg1; + ireg = reg2; + } + else if (reg2 != 0 || GET_CODE (addr) == MEM) + { + breg = reg2; + ireg = reg1; + } + else + { + breg = reg1; + ireg = reg2; + } + if (addr != 0) + output_address (addr); + if (breg != 0) + { + if (GET_CODE (breg) != REG) + abort (); + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + } + if (ireg != 0) + { + if (GET_CODE (ireg) == MULT) + ireg = XEXP (ireg, 0); + if (GET_CODE (ireg) != REG) + abort (); + fprintf (file, "[%s]", reg_names[REGNO (ireg)]); + } + break; + + default: + output_addr_const (file, addr); + } +} diff --git a/gcc-1.40/config/pyr.md b/gcc-1.40/config/pyr.md new file mode 100644 index 0000000..e8b09d0 --- /dev/null +++ b/gcc-1.40/config/pyr.md @@ -0,0 +1,1377 @@ +;; Machine description for Pyramid 90 Series for GNU C compiler +;; Copyright (C) 1989 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; Instruction patterns. When multiple patterns apply, +;; the first one in the file is chosen. +;; +;; See file "rtl.def" for documentation on define_insn, match_*, et. al. +;; +;; cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;; updates for most instructions. + +;; * Try using define_insn instead of some peepholes in more places. +;; * Set REG_NOTES:REG_EQUIV for cvt[bh]w loads. This would make the +;; backward scan in sign_extend needless. +;; * Match (pc) (label_ref) case in peephole patterns. +;; * Should optimize +;; "cmpX op1,op2; b{eq,ne} LY; ucmpX op1.op2; b{lt,le,gt,ge} LZ" +;; to +;; "ucmpX op1,op2; b{eq,ne} LY; b{lt,le,gt,ge} LZ" +;; by pre-scanning insn and running notice_update_cc for them. +;; * Is it necessary to do copy_rtx in the test and compare patterns? +;; * Fix true frame pointer omission. +;; * Make the jump tables contain branches, not addresses! This would +;; save us one instruction. +;; * Could the compilcated scheme for compares be simplyfied, if we had +;; no named cmpqi or cmphi patterns, and instead anonymous patterns for +;; the less-than-word compare cases pyr can handle??? +;; * The jump insn seems to accept more than just IR addressing. Would +;; we win by telling GCC? Or can we use movw into the global reg which +;; is a synonym for pc? +;; * More DImode patterns. +;; * Scan backwards in "zero_extendhisi2", "zero_extendqisi2" to find out +;; if the extension can be omitted. +;; * "divmodsi" with Pyramid "ediv" insn. Is it possible in rtl?? +;; * Would "rcsp tmpreg; u?cmp[bh] op1_regdispl(tmpreg),op2" win in +;; comparison with the two extensions and single test generated now? +;; The rcsp insn could be expanded, and moved out of loops by the +;; optimizer, making 1 (64 bit) insn of 3 (32 bit) insns in loops. +;; The rcsp insn could be followed by an add insn, making non-displacement +;; IR addressing sufficient. + +;______________________________________________________________________ +; +; Test and Compare Patterns. +;______________________________________________________________________ + +; The argument for the rather complicated test and compare expansion +; scheme, is the irregular pyramid instructions for these operations. +; 1) Pyramid has different signed and unsigned compares. 2) HImode +; and QImode integers are memory-memory and immediate-memory only. 3) +; Unsigned HImode compares doesn't exist. 4) Only certain +; combinations of addresses are allowed for memory-memory compares. +; Whenever necessary, in order to fulfill these addressing +; constraints, the compare operands are swapped. + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" ""))] + "" "operands[0] = force_reg (SImode, operands[0]);") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %0,%1\"; + } + return \"cmpw %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %1,%0\"; + } + return \"cmpw %1,%0\"; +}") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "r,g") + (match_operand:SI 1 "general_operand" "g,r")))] + "" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %0,%1\"; + } + return \"cmpw %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %1,%0\"; + } + return \"cmpw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "general_operand" "r"))] + "" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw $0,%0\"; + } + return \"mtstw %0,%0\"; +}") + +(define_expand "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" "")))] + "" + " +{ + extern rtx test_op0, test_op1; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_op1 = copy_rtx (operands[1]); + test_mode = HImode; + DONE; +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + cc_status.flags = CC_NO_OVERFLOW; + return \"cvthw %0,lr15\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "memory_operand" "m") + (match_operand:HI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + return \"cmph %0,%1\"; + } + + return \"cmph %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "r,m") + (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "(GET_CODE (operands[0]) != GET_CODE (operands[1]))" + "* +{ + rtx br_insn = NEXT_INSN (insn); + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + return \"cmph %0,%1\"; + } + + return \"cmph %1,%0\"; +}") + +(define_expand "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "" + " +{ + extern rtx test_op0, test_op1; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_op1 = copy_rtx (operands[1]); + test_mode = QImode; + DONE; +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + cc_status.flags = CC_NO_OVERFLOW; + return \"cvtbw %0,lr15\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %0,%1\"; + } + return \"cmpb %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %1,%0\"; + } + return \"cmpb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "r,m") + (match_operand:QI 1 "nonimmediate_operand" "m,r")))] + "(GET_CODE (operands[0]) != GET_CODE (operands[1]))" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %0,%1\"; + } + return \"cmpb %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %1,%0\"; + } + return \"cmpb %1,%0\"; +}") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "r") + (match_operand:DF 1 "register_operand" "r")))] + "" + "cmpd %1,%0") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "r") + (match_operand:SF 1 "register_operand" "r")))] + "" + "cmpf %1,%0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "r"))] + "" + "mtstd %0,%0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "r"))] + "" + "mtstf %0,%0") + +;______________________________________________________________________ +; +; Fixed-point Arithmetic. +;______________________________________________________________________ + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,!r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,rJ")))] + "" + "* +{ + if (which_alternative == 0) + return \"addw %2,%0\"; + else + { + forget_cc_if_dependent (operands[0]); + return REG_P (operands[2]) + ? \"mova (%2)[%1*1],%0\" : \"mova %a2[%1*1],%0\"; + } +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,0")))] + "" + "* return (which_alternative == 0) ? \"subw %2,%0\" : \"rsubw %1,%0\";") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "umulw %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (div:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,0")))] + "" + "* return (which_alternative == 0) ? \"divw %2,%0\" : \"rdivw %1,%0\";") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "udivw %2,%0") + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "modw %2,%0") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "umodw %2,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mnegw %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mcomw %1,%0") + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (abs:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mabsw %1,%0") + +;______________________________________________________________________ +; +; Floating-point Arithmetic. +;______________________________________________________________________ + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "addd %2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "addf %2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "subd %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "subf %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "muld %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "mulf %2,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "divd %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "divf %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "mnegd %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (neg:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "mnegf %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (abs:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "mabsd %1,%0") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (abs:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "mabsf %1,%0") + +;______________________________________________________________________ +; +; Logical and Shift Instructions. +;______________________________________________________________________ + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "%r") + (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"bitw %1,%0\"; +}") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (and:SI (match_operand:SI 1 "general_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,K")))] + "" + "* +{ + if (which_alternative == 0) + return \"andw %2,%0\"; + + cc_status.flags = CC_NOT_NEGATIVE; + return (INTVAL (operands[2]) == 255 + ? \"movzbw %1,%0\" : \"movzhw %1,%0\"); +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "0") + (not:SI (match_operand:SI 2 "general_operand" "g"))))] + "" + "bicw %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "register_operand" "0")))] + "" + "bicw %1,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "orw %2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "xorw %2,%0") + +; The arithmetic left shift instructions work strangely on pyramids. +; They fail to modify the sign bit. Therefore, use logic shifts. + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"lshlw %2,%0\", operands[2], 32); ") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"ashrw %2,%0\", operands[2], 32); ") + +(define_insn "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"ashrl %2,%0\", operands[2], 64); ") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"lshrw %2,%0\", operands[2], 32); ") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"rotlw %2,%0\", operands[2], 32); ") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"rotrw %2,%0\", operands[2], 32); ") + +;______________________________________________________________________ +; +; Fixed and Floating Moves. +;______________________________________________________________________ + +;; If the destination is a memory operand, indexed source operands are +;; disallowed. Big DImode constants are always loaded into a reg pair, +;; although offsetable memory addresses really could be dealt with. + +(define_insn "" + [(set (match_operand:DI 0 "memory_operand" "=m") + (match_operand:DI 1 "nonindexed_operand" "gF"))] + "(GET_CODE (operands[1]) == CONST_DOUBLE + ? ((CONST_DOUBLE_HIGH (operands[1]) == 0 + && CONST_DOUBLE_LOW (operands[1]) >= 0) + || (CONST_DOUBLE_HIGH (operands[1]) == -1 + && CONST_DOUBLE_LOW (operands[1]) < 0)) + : 1)" + "* +{ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + return \"movl %1,%0\"; +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r") + (match_operand:DI 1 "general_operand" "gF"))] + "" + "* return output_move_double (operands); ") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "nonindexed_operand" "g"))] + "" + "movw %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operand:SI 1 "general_operand" "g"))] + "" + "movw %1,%0") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:HI 0 "memory_operand" "=m") + (match_operand:HI 1 "nonindexed_operand" "g"))] + "" + "* +{ + if (REG_P (operands[1])) + return \"cvtwh %1,%0\"; /* reg -> mem */ + else + return \"movh %1,%0\"; /* mem imm -> mem */ +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) != MEM) + return \"movw %1,%0\"; /* reg imm -> reg */ + return \"cvthw %1,%0\"; /* mem -> reg */ +}") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:QI 0 "memory_operand" "=m") + (match_operand:QI 1 "nonindexed_operand" "g"))] + "" + "* +{ + if (REG_P (operands[1])) + return \"cvtwb %1,%0\"; /* reg -> mem */ + else + return \"movb %1,%0\"; /* mem imm -> mem */ +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) != MEM) + return \"movw %1,%0\"; /* reg imm -> reg */ + return \"cvtbw %1,%0\"; /* mem -> reg */ +}") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:DF 0 "memory_operand" "=m") + (match_operand:DF 1 "nonindexed_operand" "g"))] + "GET_CODE (operands[1]) != CONST_DOUBLE" + "movl %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r") + (match_operand:DF 1 "general_operand" "gF"))] + "" + "* return output_move_double (operands); ") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:SF 0 "memory_operand" "=m") + (match_operand:SF 1 "nonindexed_operand" "g"))] + "" + "movw %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=r") + (match_operand:SF 1 "general_operand" "g"))] + "" + "movw %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + forget_cc_if_dependent (operands[0]); + return \"mova %a1,%0\"; +}") + +;______________________________________________________________________ +; +; Conversion patterns. +;______________________________________________________________________ + +;; The trunc patterns are used only when non compile-time constants are used. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + cc_status = cc_prev_status; + return \"\"; + } + forget_cc_if_dependent (operands[0]); + return \"movw %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + cc_status = cc_prev_status; + return \"\"; + } + forget_cc_if_dependent (operands[0]); + return \"movw %1,%0\"; +}") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))] + "" + "* +{ + extern int optimize; + if (optimize && REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && already_sign_extended (insn, HImode, operands[0])) + { + cc_status = cc_prev_status; + return \"\"; + } + return \"cvthw %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm,r")))] + "" + "* +{ + extern int optimize; + if (optimize && REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && already_sign_extended (insn, QImode, operands[0])) + { + cc_status = cc_prev_status; + return \"\"; + } + return \"cvtbw %1,%0\"; +}") + +; Pyramid doesn't have insns *called* "cvtbh" or "movzbh". +; But we can cvtbw/movzbw into a register, where there is no distinction +; between words and halfwords. + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "cvtbw %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzhw %1,%0\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzbw %1,%0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzbw %1,%0\"; +}") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=&r,m") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtfd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=&r,m") + (float_truncate:SF (match_operand:DF 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtdf %1,%0") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=&r,m") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtwf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=&r,m") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtwd %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=&r,m") + (fix:SI (fix:SF (match_operand:SF 1 "nonimmediate_operand" "rm,r"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=&r,m") + (fix:SI (fix:DF (match_operand:DF 1 "nonimmediate_operand" "rm,r"))))] + "" + "cvtdw %1,%0") + +;______________________________________________________________________ +; +; Flow Control Patterns. +;______________________________________________________________________ + +;; Prefer "br" to "jump" for unconditional jumps, since it's faster. +;; (The assembler can manage with out-of-range branches.) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + extern int optimize; + if (optimize) + switch (GET_CODE (operands[0])) + { + case EQ: case NE: + break; + case LT: case LE: case GE: case GT: + if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED) + return 0; + break; + case LTU: case LEU: case GEU: case GTU: + if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED) + return 0; + break; + } + + return \"b%N0 %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + extern int optimize; + if (optimize) + switch (GET_CODE (operands[0])) + { + case EQ: case NE: + break; + case LT: case LE: case GE: case GT: + if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED) + return 0; + break; + case LTU: case LEU: case GEU: case GTU: + if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED) + return 0; + break; + } + + return \"b%C0 %l1\"; +}") + +(define_insn "call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "immediate_operand" "n"))] + "" + "call %0") + +(define_insn "call_value" + [(set (match_operand 0 "" "=r") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "immediate_operand" "n")))] + ;; Operand 2 not really used on Pyramid architecture. + "" + "call %1") + +(define_insn "return" + [(return)] + "" + "* +{ + if (get_frame_size () + current_function_pretend_args_size + + current_function_args_size != 0 + || current_function_calls_alloca) + { + int dealloc_size = current_function_pretend_args_size; + if (current_function_pops_args) + dealloc_size += current_function_args_size; + operands[0] = gen_rtx (CONST_INT, VOIDmode, dealloc_size); + return \"retd %0\"; + } + else + return \"ret\"; +}") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jump (%0)") + +(define_insn "nop" + [(const_int 0)] + "" + "movw gr0,gr0 # nop") + +;______________________________________________________________________ +; +; Peep-hole Optimization Patterns. +;______________________________________________________________________ + +;; Optimize fullword move followed by a test of the moved value. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "nonimmediate_operand" "rm")) + (set (cc0) (match_operand:SI 2 "nonimmediate_operand" "rm"))] + "rtx_equal_p (operands[2], operands[0]) + || rtx_equal_p (operands[2], operands[1])" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"mtstw %1,%0\"; +") + +;; Same for HI and QI mode move-test as well. + +(define_peephole + [(set (match_operand:HI 0 "register_operand" "=r") + (match_operand:HI 1 "nonimmediate_operand" "rm")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 3 "nonimmediate_operand" "rm"))) + (set (cc0) (match_dup 2))] + "dead_or_set_p (insn, operands[2]) + && (rtx_equal_p (operands[3], operands[0]) + || rtx_equal_p (operands[3], operands[1]))" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"cvthw %1,%0\"; +") + +(define_peephole + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "nonimmediate_operand" "rm")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 3 "nonimmediate_operand" "rm"))) + (set (cc0) (match_dup 2))] + "dead_or_set_p (insn, operands[2]) + && (rtx_equal_p (operands[3], operands[0]) + || rtx_equal_p (operands[3], operands[1]))" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"cvtbw %1,%0\"; +") + +;; Optimize loops with an incremented/decremented variable. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 0) + (const_int -1))) + (set (cc0) + (compare (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "ri"))) + (set (pc) + (if_then_else (match_operator:SI 3 "signed_comparison" + [(cc0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] + "(GET_CODE (operands[2]) == CONST_INT + ? (unsigned)INTVAL (operands[2]) + 32 >= 64 + : 1) && (rtx_equal_p (operands[0], operands[1]) + || rtx_equal_p (operands[0], operands[2]))" + "* + if (rtx_equal_p (operands[0], operands[1])) + { + output_asm_insn (\"dcmpw %2,%0\", operands); + return \"b%N3 %l4\"; + } + else + { + output_asm_insn (\"dcmpw %1,%0\", operands); + return \"b%R3 %l4\"; + } +") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 0) + (const_int 1))) + (set (cc0) + (compare (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "ri"))) + (set (pc) + (if_then_else (match_operator:SI 3 "signed_comparison" + [(cc0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] + "(GET_CODE (operands[2]) == CONST_INT + ? (unsigned)INTVAL (operands[2]) + 32 >= 64 + : 1) && (rtx_equal_p (operands[0], operands[1]) + || rtx_equal_p (operands[0], operands[2]))" + "* + if (rtx_equal_p (operands[0], operands[1])) + { + output_asm_insn (\"icmpw %2,%0\", operands); + return \"b%N3 %l4\"; + } + else + { + output_asm_insn (\"icmpw %1,%0\", operands); + return \"b%R3 %l4\"; + } +") + +;; Combine two word moves with consecutive operands into one long move. +;; Also combines immediate moves, if the high-order destination operand +;; is loaded with 0 or -1 and the low-order destination operand is loaded +;; with a constant with the same sign. + +(define_peephole + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "general_operand" "g")) + (set (match_operand:SI 2 "general_operand" "=g") + (match_operand:SI 3 "general_operand" "g"))] + "movdi_possible (operands)" + "* + output_asm_insn (\"# COMBINE movw %1,%0\", operands); + output_asm_insn (\"# COMBINE movw %3,%2\", operands); + movdi_possible (operands); + if (CONSTANT_P (operands[1])) + return (swap_operands) ? \"movl %3,%0\" : \"movl %1,%2\"; + + return (swap_operands) ? \"movl %1,%0\" : \"movl %3,%2\"; +") + +;; Optimize certain tests after memory stores. + +(define_peephole + [(set (match_operand 0 "memory_operand" "=m") + (match_operand 1 "register_operand" "r")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_dup 1))) + (set (cc0) + (match_dup 2))] + "dead_or_set_p (insn, operands[2])" + "* + cc_status.flags |= CC_NO_OVERFLOW; + if (GET_MODE (operands[0]) == QImode) + return \"cvtwb %1,%0\"; + else + return \"cvtwh %1,%0\"; +") + +;______________________________________________________________________ +; +; DImode Patterns. +;______________________________________________________________________ + +(define_expand "extendsidi2" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1) + (match_operand:SI 1 "general_operand" "g")) + (set (subreg:SI (match_dup 0) 0) + (subreg:SI (match_dup 0) 1)) + (set (subreg:SI (match_dup 0) 0) + (ashiftrt:SI (subreg:SI (match_dup 0) 0) + (const_int 31)))] + "" + "") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"addw %1,%0\", xoperands); + return \"addwc %2,%0\"; +}") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"subw %1,%0\", xoperands); + return \"subwb %2,%0\"; +}") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ior:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"orw %1,%0\", xoperands); + return \"orw %2,%0\"; +}") + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"andw %1,%0\", xoperands); + return \"andw %2,%0\"; +}") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"xorw %1,%0\", xoperands); + return \"xorw %2,%0\"; +}") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/sparc.md b/gcc-1.40/config/sparc.md new file mode 100644 index 0000000..e3d7b64 --- /dev/null +++ b/gcc-1.40/config/sparc.md @@ -0,0 +1,2370 @@ + +;;- Machine description for SPARC chip for GNU C compiler +;; Copyright (C) 1988, 1989 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@mcc.com) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +;; Compare instructions. +;; This controls RTL generation and register allocation. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + if (! REG_P (operands[0])) + { + cc_status.flags |= CC_REVERSED; + return \"cmp %1,%0\"; + } + return \"cmp %0,%1\"; +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "nonmemory_operand" "f,fG") + (match_operand:DF 1 "nonmemory_operand" "G,f")))] + "" + "emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, DFmode, 32)));") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "nonmemory_operand" "f,fG") + (match_operand:DF 1 "nonmemory_operand" "G,f")))] + "GET_CODE (operands[0]) != CONST_INT && GET_CODE (operands[1]) != CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_DOUBLE) + make_f0_contain_0 (2); + + cc_status.flags |= CC_IN_FCCR; + if (GET_CODE (operands[0]) == CONST_DOUBLE) + return \"fcmped %%f0,%1\;nop\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"fcmped %0,%%f0\;nop\"; + return \"fcmped %0,%1\;nop\"; +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "f,fG") + (match_operand:SF 1 "nonmemory_operand" "G,f")))] + "" + "emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SFmode, 32)));") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "f,fG") + (match_operand:SF 1 "nonmemory_operand" "G,f")))] + "GET_CODE (operands[0]) != CONST_INT && GET_CODE (operands[1]) != CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_DOUBLE) + make_f0_contain_0 (1); + + cc_status.flags |= CC_IN_FCCR; + if (GET_CODE (operands[0]) == CONST_DOUBLE) + return \"fcmpes %%f0,%1\;nop\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"fcmpes %0,%%f0\;nop\"; + return \"fcmpes %0,%1\;nop\"; +}") + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "tst %0") + +;; Need this to take a general operand because cse can make +;; a CONST which won't be in a register. +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "immediate_operand" "i"))] + "" + "set %0,%%g1\;tst %%g1") + +;; Optimize the case of following a reg-reg move with a test +;; of reg just moved. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "register_operand" "r")) + (set (cc0) (match_operand:SI 2 "register_operand" "r"))] + "operands[2] == operands[0] + || operands[2] == operands[1]" + "orcc %1,%%g0,%0 ! 2-insn combine") + +;; Optimize 5(6) insn sequence to 3(4) insns. +;; These patterns could also optimize more complicated sets +;; before conditional branches. + +;; Turned off because (1) this case is rarely encounted +;; (2) to be correct, more conditions must be checked +;; (3) the conditions must be checked with rtx_equal_p, not == +;; (4) when branch scheduling is added to the compiler, +;; this optimization will be performed by the branch scheduler +;; Bottom line: it is not worth the trouble of fixing or +;; maintaining it. + +;(define_peephole +; [(set (match_operand:SI 0 "register_operand" "=r") +; (match_operand:SI 1 "general_operand" "g")) +; (set (match_operand:SI 2 "register_operand" "=r") +; (match_operand:SI 3 "reg_or_0_operand" "rJ")) +; (set (cc0) (match_operand:SI 4 "register_operand" "r")) +; (set (pc) (match_operand 5 "" ""))] +; "GET_CODE (operands[5]) == IF_THEN_ELSE +; && operands[0] != operands[3] +; && ! reg_mentioned_p (operands[2], operands[1]) +; && (operands[4] == operands[0] +; || operands[4] == operands[2] +; || operands[4] == operands[3])" +; "* +;{ +; rtx xoperands[2]; +; int parity; +; xoperands[0] = XEXP (operands[5], 0); +; if (GET_CODE (XEXP (operands[5], 1)) == PC) +; { +; parity = 1; +; xoperands[1] = XEXP (XEXP (operands[5], 2), 0); +; } +; else +; { +; parity = 0; +; xoperands[1] = XEXP (XEXP (operands[5], 1), 0); +; } +; +; if (operands[4] == operands[0]) +; { +; /* Although the constraints for operands[1] permit a general +; operand (and hence possibly a const_int), we know that +; in this branch it cannot be a CONST_INT, since that would give +; us a fixed condition, and those should have been optimized away. */ +; if (REG_P (operands[1])) +; output_asm_insn (\"orcc %1,%%g0,%0 ! 3-insn reorder\", operands); +; else if (GET_CODE (operands[1]) != MEM) +; abort (); +; else +; { +; if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) +; output_asm_insn (\"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;tst %0 ! 4-insn reorder\", operands); +; else +; output_asm_insn (\"ld %1,%0\;tst %0 ! 3.5-insn reorder\", operands); +; } +; XVECEXP (PATTERN (insn), 0, 0) = XVECEXP (PATTERN (insn), 0, 2); +; XVECEXP (PATTERN (insn), 0, 1) = XVECEXP (PATTERN (insn), 0, 3); +; } +; else +; { +; output_asm_insn (\"orcc %3,%%g0,%2 ! 3-insn reorder\", operands); +; } +; if (parity) +; return output_delayed_branch (\"b%N0 %l1\", xoperands, insn); +; else +; return output_delayed_branch (\"b%C0 %l1\", xoperands, insn); +;}") + +;; By default, operations don't set the condition codes. +;; These patterns allow cc's to be set, while doing some work + +(define_insn "" + [(set (cc0) + (zero_extend:SI (subreg:QI (match_operand:SI 0 "register_operand" "r") 0)))] + "" + "andcc %0,0xff,%%g0") + +(define_insn "" + [(set (cc0) + (plus:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"addcc %0,%1,%%g0\"; +}") + +(define_insn "" + [(set (cc0) + (plus:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (plus:SI (match_dup 0) (match_dup 1)))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"addcc %0,%1,%2\"; +}") + +(define_insn "" + [(set (cc0) + (minus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI")))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"subcc %0,%1,%%g0\"; +}") + +(define_insn "" + [(set (cc0) + (minus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (minus:SI (match_dup 0) (match_dup 1)))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"subcc %0,%1,%2\"; +}") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "andcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (and:SI (match_dup 0) (match_dup 1)))] + "" + "andcc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] + "" + "andncc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))) + (set (match_operand:SI 2 "register_operand" "=r") + (and:SI (match_dup 0) (not:SI (match_dup 1))))] + "" + "andncc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "orcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (ior:SI (match_dup 0) (match_dup 1)))] + "" + "orcc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] + "" + "orncc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))) + (set (match_operand:SI 2 "register_operand" "=r") + (ior:SI (match_dup 0) (not:SI (match_dup 1))))] + "" + "orncc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "xorcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (xor:SI (match_dup 0) (match_dup 1)))] + "" + "xorcc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] + "" + "xnorcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))) + (set (match_operand:SI 2 "register_operand" "=r") + (xor:SI (match_dup 0) (not:SI (match_dup 1))))] + "" + "xnorcc %0,%1,%2") + +(define_expand "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "f"))] + "" + "emit_insn (gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, DFmode, 32)));") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "register_operand" "f"))] + "" + "* +{ + make_f0_contain_0 (2); + cc_status.flags |= CC_IN_FCCR; + return \"fcmped %0,%%f0\;nop\"; +}") + +(define_expand "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "f"))] + "" + "emit_insn (gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SFmode, 32)));") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "register_operand" "f"))] + "" + "* +{ + make_f0_contain_0 (1); + cc_status.flags |= CC_IN_FCCR; + return \"fcmpes %0,%%f0\;nop\"; +}") + +;; There are no logical links for the condition codes. This +;; would not normally be a problem, but on the SPARC (and possibly +;; other RISC machines), when argument passing, the insn which sets +;; the condition code and the insn which uses the set condition code +;; may not be performed adjacently (due to optimizations performed +;; in combine.c). To make up for this, we emit insn patterns which +;; cannot possibly be rearranged on us. +(define_expand "seq" + [(set (match_operand:SI 0 "general_operand" "=r") + (eq (cc0) (const_int 0)))] + "" + "gen_scc_insn (EQ, VOIDmode, operands); DONE;") + +(define_expand "sne" + [(set (match_operand:SI 0 "general_operand" "=r") + (ne (cc0) (const_int 0)))] + "" + "gen_scc_insn (NE, VOIDmode, operands); DONE;") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (match_operator 1 "eq_or_neq" + [(compare (match_operand:SI 2 "general_operand" "r,rI") + (match_operand:SI 3 "general_operand" "I,r")) + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + if (! REG_P (operands[2])) + { + output_asm_insn (\"cmp %3,%2\", operands); + cc_status.flags |= CC_REVERSED; + } + else + output_asm_insn (\"cmp %2,%3\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operator 1 "eq_or_neq" + [(match_operand:SI 2 "general_operand" "r") + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + output_asm_insn (\"tst %2\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (match_operator 1 "eq_or_neq" + [(compare (match_operand:DF 2 "general_operand" "f,fG") + (match_operand:DF 3 "general_operand" "G,f")) + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[3]) == CONST_DOUBLE) + make_f0_contain_0 (2); + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + output_asm_insn (\"fcmped %%f0,%3\;nop\", operands); + else if (GET_CODE (operands[3]) == CONST_DOUBLE) + output_asm_insn (\"fcmped %2,%%f0\;nop\", operands); + else output_asm_insn (\"fcmped %2,%3\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operator 1 "eq_or_neq" + [(match_operand:DF 2 "general_operand" "f") + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + make_f0_contain_0 (2); + output_asm_insn (\"fcmped %2,%%f0\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (match_operator 1 "eq_or_neq" + [(compare (match_operand:SF 2 "general_operand" "f,fG") + (match_operand:SF 3 "general_operand" "G,f")) + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[3]) == CONST_DOUBLE) + make_f0_contain_0 (1); + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + output_asm_insn (\"fcmpes %%f0,%3\;nop\", operands); + else if (GET_CODE (operands[3]) == CONST_DOUBLE) + output_asm_insn (\"fcmpes %2,%%f0\;nop\", operands); + else output_asm_insn (\"fcmpes %2,%3\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operator 1 "eq_or_neq" + [(match_operand:SF 2 "general_operand" "f") + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + make_f0_contain_0 (1); + output_asm_insn (\"fcmpes %2,%%f0\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +;; These control RTL generation for conditional jump insns +;; and match them for register allocation. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"be %l0\;nop\", \"be %l0\;nop\", \"fbe %l0\;nop\"); +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bne %l0\;nop\", \"bne %l0\;nop\", \"fbne %l0\;nop\"); +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bg %l0\;nop\", 0, \"fbg %l0\;nop\"); +}") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"bgu %l0\;nop\"; +}") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bl %l0\;nop\", \"bneg %l0\;nop\", \"fbl %l0\;nop\"); +}") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"blu %l0\;nop\"; +}") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bge %l0\;nop\", \"bpos %l0\;nop\", \"fbge %l0\;nop\"); +}") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"bgeu %l0\;nop\"; +}") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"ble %l0\;nop\", 0, \"fble %l0\;nop\"); +}") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"bleu %l0\;nop\"; +}") + +;; This matches inverted jump insns for register allocation. + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (GET_CODE (operands[0]) == GT || GET_CODE (operands[0]) == LE) + /* These two conditions can't ignore overflow, + so reinsert the deleted test instruction. */ + return 0; + return \"b%U0 %l1\;nop\"; + } + if (cc_prev_status.flags & CC_IN_FCCR) + return \"fb%F0 %l1\;nop\"; + return \"b%N0 %l1\;nop\"; +}") + +;; Move instructions + +(define_insn "swapsi" + [(set (match_operand:SI 0 "general_operand" "r,rm") + (match_operand:SI 1 "general_operand" "m,r")) + (set (match_dup 1) (match_dup 0))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + output_asm_insn (\"set %a1,%%g1\", operands), + operands[1] = gen_rtx (MEM, SImode, gen_rtx (REG, SImode, 1)), + cc_status.flags &= ~CC_KNOW_HI_G1; + output_asm_insn (\"swap %1,%0\", operands); + } + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + return \"xor %0,%1,%0\;xor %1,%0,%1\;xor %0,%1,%0\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + output_asm_insn (\"set %a0,%%g1\", operands); + operands[0] = gen_rtx (MEM, SImode, gen_rtx (REG, SImode, 1)); + cc_status.flags &= ~CC_KNOW_HI_G1; + } + return \"swap %0,%1\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (match_operand:SI 1 "general_operand" "rmif,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"st %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + return \"ld %1,%0\"; + } + if (FP_REG_P (operands[1])) + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; + if (REG_P (operands[1]) + || (GET_CODE (operands[1]) == CONST_INT + && SMALL_INT (operands[1]))) + return \"mov %1,%0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 0x3ff) == 0) + return \"sethi %%hi(%1),%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r,m") + (match_operand:HI 1 "general_operand" "rmi,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"sth %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + return \"ldsh %1,%0\"; + } + if (REG_P (operands[1]) + || (GET_CODE (operands[1]) == CONST_INT + && SMALL_INT (operands[1]))) + return \"mov %1,%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r,m") + (match_operand:QI 1 "general_operand" "rmi,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"stb %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + return \"ldsb %1,%0\"; + } + if (REG_P (operands[1]) + || (GET_CODE (operands[1]) == CONST_INT + && SMALL_INT (operands[1]))) + return \"mov %1,%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_expand "movstrsi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) + (mem:BLK (match_operand:BLK 1 "general_operand" ""))) + (use (match_operand:SI 2 "arith32_operand" "")) + (use (match_operand:SI 3 "immediate_operand" "")) + (clobber (match_dup 4)) + (clobber (match_dup 0)) + (clobber (match_dup 1))])] + "" + " +{ + operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + operands[4] = gen_reg_rtx (SImode); +}") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) + (mem:BLK (match_operand:SI 1 "register_operand" "r"))) + (use (match_operand:SI 2 "arith32_operand" "rn")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "register_operand" "=r")) + (clobber (match_operand:SI 5 "register_operand" "=0")) + (clobber (match_operand:SI 6 "register_operand" "=1"))] + "" + "* return output_block_move (operands);") + +;; Floating point move insns + +;; This pattern forces (set (reg:DF ...) (const_double ...)) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general movdf pattern. +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=r,f,o") + (match_operand:DF 1 "" "mG,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov %%g0,%0\;mov %%g0,%1\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %%g0,[%%g1+%%lo(%%m0)]\;st %%g0,[%%g1+%%lo(%%m0)+4]\"; + } + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st %%g0,%0\;st %%g0,%1\"; + } + return output_move_double (operands); +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=rm,&r,?f,?rm") + (match_operand:DF 1 "general_operand" "r,m,rfm,f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_floating (operands); + + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=rm,&r,?f,?rm") + (match_operand:DI 1 "general_operand" "r,mi,rfm,f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=rf,m") + (match_operand:SF 1 "general_operand" "rfm,rf"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_floating (operands); + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmovs %1,%0\"; + if (GET_CODE (operands[1]) == REG) + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\"; + } + return \"ld %1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %r1,[%%g1+%%lo(%m0)]\"; + } + return \"st %r1,%0\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld %1,%0\"; + return \"mov %1,%0\"; +}") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"stb %1,[%%g1+%%lo(%m0)]\"; + } + else + return \"stb %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"stb %1,[%%g1+%%lo(%m0)]\"; + } + else + return \"stb %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"sth %1,[%%g1+%%lo(%m0)]\"; + } + else + return \"sth %1,%0\"; + return \"mov %1,%0\"; +}") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x10,%0\;srl %0,0x10,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) & 0xffff); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;lduh [%%g1+%%lo(%m1)],%0\"; + } + else + return \"lduh %1,%0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"and %1,0xff,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) & 0xff); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldub %1,%0\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"and %1,0xff,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) & 0xff); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldub %1,%0\"; +}") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x10,%0\;sra %0,0x10,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = (short)INTVAL (operands[1]); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsh [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldsh %1,%0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x18,%0\;sra %0,0x18,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = (char)INTVAL (operands[1]); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldsb %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x18,%0\;sra %0,0x18,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = (char)INTVAL (operands[1]); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldsb %1,%0\"; +}") + +;; Signed bitfield extractions come out looking like +;; (shiftrt (shift (sign_extend <Y>) <C1>) <C2>) +;; which we expand poorly as four shift insns. +;; These patters yeild two shifts: +;; (shiftrt (shift <Y> <C3>) <C4>) +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (match_operand:QI 1 "register_operand" "r")) + (match_operand:SI 2 "small_int" "n")))] + "" + "sll %1,0x18,%0\;sra %0,0x18+%2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (subreg:QI (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "small_int" "n")) 0)) + (match_operand:SI 3 "small_int" "n")))] + "" + "sll %1,0x18+%2,%0\;sra %0,0x18+%3,%0") + +;; Special patterns for optimizing bit-field instructions. + +;; First two patterns are for bitfields that came from memory +;; testing only the high bit. They work with old combiner. +;; @@ Actually, the second pattern does not work if we +;; @@ need to set the N bit. +(define_insn "" + [(set (cc0) + (zero_extend:SI (subreg:QI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)))] + "0" + "andcc %0,128,%%g0") + +(define_insn "" + [(set (cc0) + (sign_extend:SI (subreg:QI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)))] + "0" + "andcc %0,128,%%g0") + +;; next two patterns are good for bitfields coming from memory +;; (via pseudo-register) or from a register, though this optimization +;; is only good for values contained wholly within the bottom 13 bits +(define_insn "" + [(set (cc0) + (and:SI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "small_int" "n")) + (match_operand:SI 2 "small_int" "n")))] + "(unsigned)((INTVAL (operands[2]) << INTVAL (operands[1])) + 0x1000) < 0x2000" + "andcc %0,%2<<%1,%%g0") + +(define_insn "" + [(set (cc0) + (and:SI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "small_int" "n")) + (match_operand:SI 2 "small_int" "n")))] + "(unsigned)((INTVAL (operands[2]) << INTVAL (operands[1])) + 0x1000) < 0x2000" + "andcc %0,%2<<%1,%%g0") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF + (match_operand:SF 1 "register_operand" "f")))] + "" + "fstod %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "f")))] + "" + "fdtos %1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +;; This pattern forces (set (reg:SF ...) (float:SF (const_int ...))) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general floatsisf2 pattern. +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand 1 "" "m")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitos %0,%0\"; + } + return \"ld %1,%0\;fitos %0,%0\"; +}") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:SI 1 "general_operand" "rfm")))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitos %0,%0\"; + } + else + return \"ld %1,%0\;fitos %0,%0\"; + else if (FP_REG_P (operands[1])) + return \"fitos %1,%0\"; + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\;fitos %0,%0\"; +}") + +;; This pattern forces (set (reg:DF ...) (float:DF (const_int ...))) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general floatsidf2 pattern. +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand 1 "" "m")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitod %0,%0\"; + } + return \"ld %1,%0\;fitod %0,%0\"; +}") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:SI 1 "general_operand" "rfm")))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitod %0,%0\"; + } + else + return \"ld %1,%0\;fitod %0,%0\"; + else if (FP_REG_P (operands[1])) + return \"fitod %1,%0\"; + else + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\;fitod %0,%0\"; +}") + +;; Convert a float to an actual integer. +;; Truncation is performed as part of the conversion. +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "" + "* +{ + cc_status.flags &= ~(CC_F1_IS_0); + if (FP_REG_P (operands[1])) + output_asm_insn (\"fstoi %1,%%f1\", operands); + else if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + output_asm_insn (\"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%%f1\;fstoi %%f1,%%f1\", operands); + } + else + output_asm_insn (\"ld %1,%%f1\;fstoi %%f1,%%f1\", operands); + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %%f1,[%%g1+%%lo(%m0)]\"; + } + else + return \"st %%f1,%0\"; + else + return \"st %%f1,[%%fp-4]\;ld [%%fp-4],%0\"; +}") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "" + "* +{ + cc_status.flags &= ~CC_F0_IS_0; + if (FP_REG_P (operands[1])) + output_asm_insn (\"fdtoi %1,%%f0\", operands); + else + { + rtx xoperands[2]; + xoperands[0] = gen_rtx (REG, DFmode, 32); + xoperands[1] = operands[1]; + output_asm_insn (output_fp_move_double (xoperands), xoperands); + output_asm_insn (\"fdtoi %%f0,%%f0\", 0); + } + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %%f0,[%%g1+%%lo(%m0)]\"; + } + else + return \"st %%f0,%0\"; + else + return \"st %%f0,[%%fp-4]\;ld [%%fp-4],%0\"; +}") + +;;- arithmetic instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2])) + return \"add %1,%2,%0\"; + if (SMALL_INT (operands[2])) + return \"add %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;add %1,%%g1,%0\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2])) + return \"sub %1,%2,%0\"; + if (SMALL_INT (operands[2])) + return \"sub %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;sub %1,%%g1,%0\"; +}") + +(define_expand "mulsi3" + [(set (match_operand:SI 0 "register_operand" "r") + (mult:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx src; + + if (GET_CODE (operands[1]) == CONST_INT) + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_move_insn (operands[0], + gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) * INTVAL (operands[2]))); + DONE; + } + else + src = gen_rtx (MULT, SImode, + copy_to_mode_reg (SImode, operands[2]), + operands[1]); + else if (GET_CODE (operands[2]) == CONST_INT) + src = gen_rtx (MULT, SImode, + copy_to_mode_reg (SImode, operands[1]), + operands[2]); + else src = 0; + + if (src) + emit_insn (gen_rtx (SET, VOIDmode, operands[0], src)); + else + emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, + gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (MULT, SImode, operands[1], operands[2])), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 8)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 9)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 12)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 13))))); + DONE; +}") + +(define_expand "umulsi3" + [(set (match_operand:SI 0 "register_operand" "r") + (umult:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx src; + + if (GET_CODE (operands[1]) == CONST_INT) + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_move_insn (operands[0], + gen_rtx (CONST_INT, VOIDmode, + (unsigned)INTVAL (operands[1]) * (unsigned)INTVAL (operands[2]))); + DONE; + } + else + src = gen_rtx (UMULT, SImode, + copy_to_mode_reg (SImode, operands[2]), + operands[1]); + else if (GET_CODE (operands[2]) == CONST_INT) + src = gen_rtx (UMULT, SImode, + copy_to_mode_reg (SImode, operands[1]), + operands[2]); + else src = 0; + + if (src) + emit_insn (gen_rtx (SET, VOIDmode, operands[0], src)); + else + emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, + gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (UMULT, SImode, operands[1], operands[2])), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 8)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 9)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 12)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 13))))); + DONE; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "n")))] + "" + "* return output_mul_by_constant (insn, operands, 0);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "n")))] + "" + "* return output_mul_by_constant (insn, operands, 1);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "general_operand" "%r") + (match_operand:SI 2 "general_operand" "r"))) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "* return output_mul_insn (operands, 0);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "general_operand" "%r") + (match_operand:SI 2 "general_operand" "r"))) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "* return output_mul_insn (operands, 1);") + +;; this pattern is needed because cse may eliminate the multiplication, +;; but leave the clobbers behind. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (SMALL_INT (operands[1])) + return \"mov %1,%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + return \"ld %1,%0\"; + return \"mov %1,%0\"; +}") + +;; In case constant factor turns out to be -1. +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "general_operand" "rI"))) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "sub %%g0,%1,%0") + +;;- and instructions (with compliment also) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2]) || SMALL_INT (operands[2])) + return \"and %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;and %1,%%g1,%0\"; +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "andn %1,%2,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2]) || SMALL_INT (operands[2])) + return \"or %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;or %1,%%g1,%0\"; +}") + +(define_insn "iorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "orn %1,%2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2]) || SMALL_INT (operands[2])) + return \"xor %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;xor %1,%%g1,%0\"; +}") + +(define_insn "xorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "xnor %1,%2,%0") + +;; We cannot use the "neg" pseudo insn because the Sun assembler +;; does not know how to make it work for constants. +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "sub %%g0,%1,%0") + +;; We cannot use the "not" pseudo insn because the Sun assembler +;; does not know how to make it work for constants. +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "xnor %%g0,%1,%0") + +;; Floating point arithmetic instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "faddd %1,%2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fadds %1,%2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fsubd %1,%2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fsubs %1,%2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fmuld %1,%2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fmuls %1,%2,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fdivd %1,%2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (div:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "" + "fdivs %1,%2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "* +{ + output_asm_insn (\"fnegs %1,%0\", operands); + if (REGNO (operands[0]) != REGNO (operands[1])) + { + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + output_asm_insn (\"fmovs %1,%0\", operands); + } + return \"\"; +}") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "fnegs %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "* +{ + output_asm_insn (\"fabss %1,%0\", operands); + if (REGNO (operands[0]) != REGNO (operands[1])) + { + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + output_asm_insn (\"fmovs %1,%0\", operands); + } + return \"\"; +}") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "fabss %1,%0") + +;; Shift instructions + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; + } + return \"ldsb %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; + } + return \"ldub %1,%0\"; +}") + +;;- arithmetic shift instructions +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); + return \"sll %1,%2,%0\"; +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); + return \"sra %1,%2,%0\"; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); + return \"srl %1,%2,%0\"; +}") + +;; Unconditional and other jump instructions +;; Note that for the Sparc, by setting the annul bit on an unconditional +;; branch, the following insn is never executed. This saves us a nop, +;; but requires a debugger which can handle annuled branches. +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* +{ + extern int optimize; + extern int flag_no_peephole; + + if (optimize && !flag_no_peephole) + return \"b,a %l0\"; + return \"b %l0\;nop\"; +}") + +;; Peephole optimizers recognize a few simple cases when delay insns are safe. +;; Complex ones are up front. Simple ones after. + +;; This pattern is just like the following one, but matches when there +;; is a jump insn after the "delay" insn. Without this pattern, we +;; de-optimize that case. + +(define_peephole + [(set (pc) (match_operand 0 "" "")) + (set (match_operand:SI 1 "" "") + (match_operand:SI 2 "" "")) + (set (pc) (label_ref (match_operand 3 "" "")))] + "TARGET_EAGER && operands_satisfy_eager_branch_peephole (operands, 2)" + "* +{ + rtx xoperands[2]; + rtx pat = gen_rtx (SET, VOIDmode, operands[1], operands[2]); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + rtx label, head; + int parity; + + if (GET_CODE (XEXP (operands[0], 1)) == PC) + { + parity = 1; + label = XEXP (XEXP (operands[0], 2), 0); + } + else + { + parity = 0; + label = XEXP (XEXP (operands[0], 1), 0); + } + xoperands[0] = XEXP (operands[0], 0); + xoperands[1] = label; + + head = next_real_insn_no_labels (label); + + /* If at the target of this label we set the condition codes, + and the condition codes are already set for that value, + advance, if we can, to the following insn. */ + if (GET_CODE (PATTERN (head)) == SET + && GET_CODE (SET_DEST (PATTERN (head))) == CC0 + && cc_status.value2 == SET_SRC (PATTERN (head))) + { + rtx nhead = next_real_insn_no_labels (head); + if (nhead + && GET_CODE (nhead) == INSN + && GET_CODE (PATTERN (nhead)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (nhead)), + GET_MODE (SET_DEST (PATTERN (nhead)))) + && strict_single_insn_op_p (SET_DEST (PATTERN (nhead)), VOIDmode) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (nhead))) == REG + && GET_CODE (SET_DEST (PATTERN (nhead))) == REG + && (FP_REG_P (SET_SRC (PATTERN (nhead))) + != FP_REG_P (SET_DEST (PATTERN (nhead)))))) + { + head = nhead; + } + } + + /* Output the branch instruction first. */ + if (cc_prev_status.flags & CC_IN_FCCR) + { + if (parity) + output_asm_insn (\"fb%F0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"fb%C0,a %l1 ! eager\", xoperands); + } + else if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (parity) + output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); + } + else + { + if (parity) + output_asm_insn (\"b%N0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%C0,a %l1 ! eager\", xoperands); + } + + /* Now steal the first insn of the target. */ + output_eager_then_insn (head, operands); + + XVECEXP (PATTERN (insn), 0, 0) = XVECEXP (PATTERN (insn), 0, 1); + XVECEXP (PATTERN (insn), 0, 1) = XVECEXP (PATTERN (insn), 0, 2); + + return output_delayed_branch (\"b %l3 ! eager2\", operands, insn); +}") + +;; Here is a peephole which recognizes where delay insns can be made safe: +;; (1) following a conditional branch, if the target of the conditional branch +;; has only one user (this insn), move the first insn into our delay slot +;; and emit an annulled branch. +;; (2) following a conditional branch, if we can execute the fall-through +;; insn without risking any evil effects, then do that instead of a nop. + +(define_peephole + [(set (pc) (match_operand 0 "" "")) + (set (match_operand:SI 1 "" "") + (match_operand:SI 2 "" ""))] + "TARGET_EAGER && operands_satisfy_eager_branch_peephole (operands, 1)" + "* +{ + rtx xoperands[2]; + rtx pat = gen_rtx (SET, VOIDmode, operands[1], operands[2]); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + rtx label, head, prev = (rtx)1; + int parity; + + if (GET_CODE (XEXP (operands[0], 1)) == PC) + { + parity = 1; + label = XEXP (XEXP (operands[0], 2), 0); + } + else + { + parity = 0; + label = XEXP (XEXP (operands[0], 1), 0); + } + xoperands[0] = XEXP (operands[0], 0); + xoperands[1] = label; + + if (LABEL_NUSES (label) == 1) + { + prev = PREV_INSN (label); + while (prev + && (GET_CODE (prev) == NOTE + || (GET_CODE (prev) == INSN + && (GET_CODE (PATTERN (prev)) == CLOBBER + || GET_CODE (PATTERN (prev)) == USE)))) + prev = PREV_INSN (prev); + if (prev == 0 + || GET_CODE (prev) == BARRIER) + { + prev = 0; + head = next_real_insn_no_labels (label); + } + } + if (prev == 0 + && head != 0 + && ! INSN_DELETED_P (head) + && GET_CODE (head) == INSN + && GET_CODE (PATTERN (head)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (head)), + GET_MODE (SET_DEST (PATTERN (head)))) + && strict_single_insn_op_p (SET_DEST (PATTERN (head)), VOIDmode) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (head))) == REG + && GET_CODE (SET_DEST (PATTERN (head))) == REG + && (FP_REG_P (SET_SRC (PATTERN (head))) + != FP_REG_P (SET_DEST (PATTERN (head)))))) + { + /* If at the target of this label we set the condition codes, + and the condition codes are already set for that value, + advance, if we can, to the following insn. */ + if (GET_CODE (PATTERN (head)) == SET + && GET_CODE (SET_DEST (PATTERN (head))) == CC0 + && cc_status.value2 == SET_SRC (PATTERN (head))) + { + rtx nhead = next_real_insn_no_labels (head); + if (nhead + && GET_CODE (nhead) == INSN + && GET_CODE (PATTERN (nhead)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (nhead)), + GET_MODE (SET_DEST (nhead))) + && strict_single_insn_op_p (SET_DEST (PATTERN (nhead)), VOIDmode) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (nhead))) == REG + && GET_CODE (SET_DEST (PATTERN (nhead))) == REG + && (FP_REG_P (SET_SRC (PATTERN (nhead))) + != FP_REG_P (SET_DEST (PATTERN (nhead)))))) + head = nhead; + } + + /* Output the branch instruction first. */ + if (cc_prev_status.flags & CC_IN_FCCR) + { + if (parity) + output_asm_insn (\"fb%F0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"fb%C0,a %l1 ! eager\", xoperands); + } + else if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (parity) + output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); + } + else + { + if (parity) + output_asm_insn (\"b%N0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%C0,a %l1 ! eager\", xoperands); + } + + /* Now steal the first insn of the target. */ + output_eager_then_insn (head, operands); + } + else + { + /* Output the branch instruction first. */ + if (cc_prev_status.flags & CC_IN_FCCR) + { + if (parity) + output_asm_insn (\"fb%F0 %l1 ! eager\", xoperands); + else + output_asm_insn (\"fb%C0 %l1 ! eager\", xoperands); + } + else if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (parity) + output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); + } + else + { + if (parity) + output_asm_insn (\"b%N0 %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%C0 %l1 ! eager\", xoperands); + } + } + return output_delay_insn (delay_insn); +}") + +;; Here are two simple peepholes which fill the delay slot of +;; an unconditional branch. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "single_insn_extra_test (operands[0], operands[1])" + "* return output_delayed_branch (\"b %l2\", operands, insn);") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "" + "* return output_delayed_branch (\"b %l2\", operands, insn);") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %0\;nop") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (parallel [(set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))])] + "REGNO (operands[0]) != REGNO (operands[2]) + && single_insn_extra_test (operands[0], operands[1])" + "* return output_delayed_branch (\"jmp %2\", operands, insn);") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (parallel [(set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))])] + "" + "* return output_delayed_branch (\"jmp %2\", operands, insn);") + +;;- jump to subroutine +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i"))] + ;; operand[2] is next_arg_register + "" + " +{ + rtx fn_rtx, nregs_rtx; + + if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[0], 0)) == REG) + { + rtx g1_rtx = gen_rtx (REG, SImode, 1); + emit_move_insn (g1_rtx, XEXP (operands[0], 0)); + fn_rtx = gen_rtx (MEM, SImode, g1_rtx); + } + else + fn_rtx = operands[0]; + + /* Count the number of parameter registers being used by this call. + if that argument is NULL, it means we are using them all, which + means 6 on the sparc. */ +#if 0 + if (operands[2]) + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[2]) - 8); + else + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6); +#else + nregs_rtx = const0_rtx; +#endif + + emit_call_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, + gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx), + gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31))))); + DONE; +}") + +(define_insn "" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i")) + (use (reg:SI 31))] + ;;- Don't use operand 1 for most machines. + "CONSTANT_P (XEXP (operands[0], 0)) + || GET_CODE (XEXP (operands[0], 0)) == REG" + "* +{ + /* strip the MEM. */ + operands[0] = XEXP (operands[0], 0); + CC_STATUS_INIT; + if (TARGET_SUN_ASM && GET_CODE (operands[0]) == REG) + return \"jmpl %a0,%%o7\;nop\"; + return \"call %a0,%1\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (parallel [(call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i")) + (use (reg:SI 31))])] + ;;- Don't use operand 1 for most machines. + "! reg_mentioned_p (operands[0], operands[2]) + && single_insn_extra_test (operands[0], operands[1])" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"jmpl %a2,%%o7\", operands, insn); + return output_delayed_branch (\"call %a2,%3\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (parallel [(call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i")) + (use (reg:SI 31))])] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"jmpl %a2,%%o7\", operands, insn); + return output_delayed_branch (\"call %a2,%3\", operands, insn); +}") + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i")))] + ;; operand 3 is next_arg_register + "" + " +{ + rtx fn_rtx, nregs_rtx; + rtvec vec; + + if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[1], 0)) == REG) + { + rtx g1_rtx = gen_rtx (REG, SImode, 1); + emit_move_insn (g1_rtx, XEXP (operands[1], 0)); + fn_rtx = gen_rtx (MEM, SImode, g1_rtx); + } + else + fn_rtx = operands[1]; + +#if 0 + if (operands[3]) + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[3]) - 8); + else + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6); +#else + nregs_rtx = const0_rtx; +#endif + + vec = gen_rtvec (2, + gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx)), + gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31))); + + emit_call_insn (gen_rtx (PARALLEL, VOIDmode, vec)); + DONE; +}") + +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i"))) + (use (reg:SI 31))] + ;;- Don't use operand 2 for most machines. + "CONSTANT_P (XEXP (operands[1], 0)) + || GET_CODE (XEXP (operands[1], 0)) == REG" + "* +{ + /* strip the MEM. */ + operands[1] = XEXP (operands[1], 0); + CC_STATUS_INIT; + if (TARGET_SUN_ASM && GET_CODE (operands[1]) == REG) + return \"jmpl %a1,%%o7\;nop\"; + return \"call %a1,%2\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (parallel [(set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i"))) + (use (reg:SI 31))])] + ;;- Don't use operand 4 for most machines. + "! reg_mentioned_p (operands[0], operands[3]) + && single_insn_extra_test (operands[0], operands[1])" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"jmpl %a3,%%o7\", operands, insn); + return output_delayed_branch (\"call %a3,%4\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (parallel [(set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i"))) + (use (reg:SI 31))])] + ;;- Don't use operand 4 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"jmpl %a3,%%o7\", operands, insn); + return output_delayed_branch (\"call %a3,%4\", operands, insn); +}") + +(define_insn "return" + [(return)] + "! TARGET_EPILOGUE" + "ret\;restore") + +(define_peephole + [(set (reg:SI 24) + (match_operand:SI 0 "reg_or_0_operand" "rJ")) + (return)] + "! TARGET_EPILOGUE" + "ret\;restore %r0,0x0,%%o0") + +(define_peephole + [(set (reg:SI 24) + (plus:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (return)] + "! TARGET_EPILOGUE" + "ret\;restore %r0,%1,%%o0") + +(define_peephole + [(set (reg:SI 24) + (minus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "small_int" "I"))) + (return)] + "! TARGET_EPILOGUE" + "ret\;restore %0,-(%1),%%o0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/spur.md b/gcc-1.40/config/spur.md new file mode 100644 index 0000000..62070be --- /dev/null +++ b/gcc-1.40/config/spur.md @@ -0,0 +1,1119 @@ +;;- Machine description for SPUR chip for GNU C compiler +;; Copyright (C) 1988 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +;; Compare instructions. +;; This pattern is used for generating an "insn" +;; which does just a compare and sets a (fictitious) condition code. + +;; The actual SPUR insns are compare-and-conditional-jump. +;; The define_peephole's below recognize the combinations of +;; compares and jumps, and output each pair as a single assembler insn. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +;; This controls RTL generation and register allocation. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonmemory_operand" "rK") + (match_operand:SI 1 "nonmemory_operand" "rK")))] + "" + "* +{ + cc_status.value1 = operands[0], cc_status.value2 = operands[1]; + return \"\"; +}") + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +;; We have to have this because cse can optimize the previous pattern +;; into this one. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "* +{ + cc_status.value1 = operands[0], cc_status.value2 = const0_rtx; + return \"\"; +}") + + +;; These control RTL generation for conditional jump insns +;; and match them for register allocation. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"eq\", \"eq\", \"ne\", \"ne\"); ") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ne\", \"ne\", \"eq\", \"eq\"); ") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"gt\", \"lt\", \"le\", \"ge\"); ") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ugt\", \"ult\", \"ule\", \"uge\"); ") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"lt\", \"gt\", \"ge\", \"le\"); ") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ult\", \"ugt\", \"uge\", \"ule\"); ") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ge\", \"le\", \"lt\", \"gt\"); ") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"uge\", \"ule\", \"ult\", \"ugt\"); ") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"le\", \"ge\", \"gt\", \"lt\"); ") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ule\", \"uge\", \"ugt\", \"ult\"); ") + +;; These match inverted jump insns for register allocation. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ne\", \"ne\", \"eq\", \"eq\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"eq\", \"eq\", \"ne\", \"ne\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"le\", \"ge\", \"gt\", \"lt\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ule\", \"uge\", \"ugt\", \"ult\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ge\", \"le\", \"lt\", \"gt\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"uge\", \"ule\", \"ult\", \"ugt\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"lt\", \"gt\", \"ge\", \"le\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ult\", \"ugt\", \"uge\", \"ule\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"gt\", \"lt\", \"le\", \"ge\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ugt\", \"ult\", \"ule\", \"uge\"); ") + +;; Move instructions + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (match_operand:SI 1 "general_operand" "rmi,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + if (GET_CODE (operands[1]) == SYMBOL_REF && operands[1]->unchanging) + return \"add_nt %0,r24,$(%1-0b)\"; + return \"add_nt %0,r0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))))] + "" + "ld_32 %0,%1,%2\;nop") + +;; Generate insns for moving single bytes. + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = copy_to_reg (operands[1]); + + if (GET_CODE (operands[1]) == MEM) + { + rtx tem = gen_reg_rtx (SImode); + rtx addr = force_reg (SImode, XEXP (operands[1], 0)); + rtx subreg; + + emit_move_insn (tem, gen_rtx (MEM, SImode, addr)); + if (GET_CODE (operands[0]) == SUBREG) + subreg = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[0]), + SUBREG_WORD (operands[0])); + else + subreg = gen_rtx (SUBREG, SImode, operands[0], 0); + + emit_insn (gen_rtx (SET, VOIDmode, subreg, + gen_rtx (ZERO_EXTRACT, SImode, tem, + gen_rtx (CONST_INT, VOIDmode, 8), + addr))); + } + else if (GET_CODE (operands[0]) == MEM) + { + rtx tem = gen_reg_rtx (SImode); + rtx addr = force_reg (SImode, XEXP (operands[0], 0)); + rtx subreg; + + emit_move_insn (tem, gen_rtx (MEM, SImode, addr)); + if (! CONSTANT_ADDRESS_P (operands[1])) + { + if (GET_CODE (operands[1]) == SUBREG) + subreg = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + subreg = gen_rtx (SUBREG, SImode, operands[1], 0); + } + + emit_insn (gen_rtx (SET, VOIDmode, + gen_rtx (ZERO_EXTRACT, SImode, tem, + gen_rtx (CONST_INT, VOIDmode, 8), + addr), + subreg)); + emit_move_insn (gen_rtx (MEM, SImode, addr), tem); + } + else + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], operands[1])); + } + DONE; +}") + +;; Recognize insns generated for moving single bytes. + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=r,m") + (match_operand:QI 1 "general_operand" "rmi,r"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + return \"add_nt %0,r0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (const_int 8) + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "extract %0,%1,%2") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (const_int 8) + (match_operand:SI 1 "nonmemory_operand" "rI")) + (match_operand:SI 2 "nonmemory_operand" "ri"))] + "" + "wr_insert %1\;insert %0,%0,%2") + +;; Constant propagation can optimize the previous pattern into this pattern. +;[Not any more. It could when the position-operand contains a MULT.] + +;(define_insn "" +; [(set (zero_extract:QI (match_operand:SI 0 "register_operand" "+r") +; (const_int 8) +; (match_operand:SI 1 "immediate_operand" "I")) +; (match_operand:QI 2 "register_operand" "r"))] +; "GET_CODE (operands[1]) == CONST_INT +; && INTVAL (operands[1]) % 8 == 0 +; && (unsigned) INTVAL (operands[1]) < 32" +; "* +;{ +; operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) / 8); +; return \"wr_insert 0,0,%1\;insert %0,%0,%2\"; +;}") + +;; The three define_expand patterns on this page +;; serve as subroutines of "movhi". + +;; Generate code to fetch an aligned halfword from memory. +;; Operand 0 is the destination register (HImode). +;; Operand 1 is the memory address (SImode). +;; Operand 2 is a temporary (SImode). +;; Operand 3 is a temporary (SImode). +;; Operand 4 is a temporary (QImode). + +;; Operand 5 is an internal temporary (HImode). + +(define_expand "loadhi" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" ""))) + ;; Extract the low byte. + (set (subreg:SI (match_dup 5) 0) + (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 1))) + ;; Form address of high byte. + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 1) (const_int 1))) + ;; Extract the high byte. + (set (subreg:SI (match_operand:QI 4 "register_operand" "") 0) + (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3))) + ;; Put the high byte in with the low one. + (set (zero_extract:SI (match_dup 5) (const_int 8) (const_int 1)) + (subreg:SI (match_dup 4) 0)) + (set (match_operand:HI 0 "register_operand" "") (match_dup 5))] + "" + "operands[5] = gen_reg_rtx (HImode);") + +;; Generate code to store an aligned halfword into memory. +;; Operand 0 is the destination address (SImode). +;; Operand 1 is the source register (HImode, not constant). +;; Operand 2 is a temporary (SImode). +;; Operand 3 is a temporary (SImode). +;; Operand 4 is a temporary (QImode). + +;; Operand 5 is an internal variable made from operand 1. + +(define_expand "storehi" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 0 "register_operand" ""))) + ;; Insert the low byte. + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 0)) + (match_dup 5)) + ;; Form address of high byte. + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 0) (const_int 1))) + ;; Extract the high byte from the source. + (set (subreg:SI (match_operand:QI 4 "register_operand" "") 0) + (zero_extract:SI (match_operand:HI 1 "register_operand" "") + (const_int 8) (const_int 1))) + ;; Store high byte into the memory word + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3)) + (subreg:SI (match_dup 4) 0)) + ;; Put memory word back into memory. + (set (mem:SI (match_dup 0)) + (match_dup 2))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[5] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[5] = gen_rtx (SUBREG, SImode, operands[1], 0); +}") + +;; Like storehi but operands[1] is a CONST_INT. + +(define_expand "storeinthi" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 0 "register_operand" ""))) + ;; Insert the low byte. + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 0)) + (match_dup 5)) + ;; Form address of high byte. + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 0) (const_int 1))) + ;; Store high byte into the memory word + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3)) + (match_dup 6)) + ;; Put memory word back into memory. + (set (mem:SI (match_dup 0)) + (match_dup 2))] + "" + " operands[5] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) & 255); + operands[6] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) >> 8) & 255); +") + +;; Main entry for generating insns to move halfwords. + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = copy_to_reg (operands[1]); + + if (GET_CODE (operands[1]) == MEM) + { + rtx insn = + emit_insn (gen_loadhi (operands[0], + force_reg (SImode, XEXP (operands[1], 0)), + gen_reg_rtx (SImode), gen_reg_rtx (SImode), + gen_reg_rtx (QImode))); + /* Tell cse what value the loadhi produces, so it detect duplicates. */ + REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, operands[1], + REG_NOTES (insn)); + } + else if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[1]) == CONST_INT) + emit_insn (gen_storeinthi (force_reg (SImode, XEXP (operands[0], 0)), + operands[1], + gen_reg_rtx (SImode), gen_reg_rtx (SImode), + gen_reg_rtx (QImode))); + else + { + if (CONSTANT_P (operands[1])) + operands[1] = force_reg (HImode, operands[1]); + emit_insn (gen_storehi (force_reg (SImode, XEXP (operands[0], 0)), + operands[1], + gen_reg_rtx (SImode), gen_reg_rtx (SImode), + gen_reg_rtx (QImode))); + } + } + else + emit_insn (gen_rtx (SET, VOIDmode, operands[0], operands[1])); + DONE; +}") + +;; Recognize insns generated for moving halfwords. +;; (Note that the extract and insert patterns for single-byte moves +;; are also involved in recognizing some of the insns used for this purpose.) + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=r,m") + (match_operand:HI 1 "general_operand" "rmi,r"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + return \"add_nt %0,r0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:HI 1 "register_operand" "r") + (const_int 8) + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "extract %0,%1,%2") + +(define_insn "" + [(set (zero_extract:SI (match_operand:HI 0 "register_operand" "+r") + (const_int 8) + (match_operand:SI 1 "nonmemory_operand" "rI")) + (match_operand:SI 2 "nonmemory_operand" "ri"))] + "" + "wr_insert %1\;insert %0,%0,%2") + +;; Constant propagation can optimize the previous pattern into this pattern. + +;(define_insn "" +; [(set (zero_extract:QI (match_operand:HI 0 "register_operand" "+r") +; (const_int 8) +; (match_operand:SI 1 "immediate_operand" "I")) +; (match_operand:QI 2 "register_operand" "r"))] +; "GET_CODE (operands[1]) == CONST_INT +; && INTVAL (operands[1]) % 8 == 0 +; && (unsigned) INTVAL (operands[1]) < 32" +; "* +;{ +; operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) / 8); +; return \"wr_insert 0,0,%1\;insert %0,%0,%2\"; +;}") + +;; This pattern forces (set (reg:DF ...) (const_double ...)) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general movdf pattern. +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=&r,f,&o") + (match_operand:DF 1 "" "mG,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"add_nt %0,r0,$0\;add_nt %1,r0,$0\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st_32 r0,%0\;st_32 r0,%1\"; + } + return output_move_double (operands); +} +") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r,&r,m,?f,?rm") + (match_operand:DF 1 "general_operand" "r,m,r,rfm,f"))] + "" + "* +{ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +} +") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r,&r,m,?f,?rm") + (match_operand:DI 1 "general_operand" "r,m,r,rfm,f"))] + "" + "* +{ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +} +") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=rf,m") + (match_operand:SF 1 "general_operand" "rfm,rf"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmov %0,%1\"; + if (GET_CODE (operands[1]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[1] = operands[1]; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + output_asm_insn (\"st_32 %1,r25,%0\", xoperands); + xoperands[1] = operands[0]; + output_asm_insn (\"ld_sgl %1,r25,%0\;nop\", xoperands); + return \"\"; + } + return \"ld_sgl %0,%1\;nop\"; + } + if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + xoperands[1] = operands[1]; + output_asm_insn (\"st_sgl %1,r25,%0\", xoperands); + xoperands[1] = operands[0]; + output_asm_insn (\"ld_32 %1,r25,%0\;nop\", xoperands); + return \"\"; + } + return \"st_sgl %1,%0\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + return \"add_nt %0,r0,%1\"; +}") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "add_nt %0,%1,$0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "add_nt %0,%1,$0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "add_nt %0,%1,$0") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:HI 1 "register_operand" "") ;Changed to SI below + ;; This constant is invalid, but reloading will handle it. + ;; It's useless to generate here the insns to construct it + ;; because constant propagation would simplify them anyway. + (match_dup 2)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0); + + operands[2] = force_reg (SImode, gen_rtx (CONST_INT, VOIDmode, 65535)); +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "register_operand" "r")))] + "" + "extract %0,%1,$0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "register_operand" "r")))] + "" + "extract %0,%1,$0") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_expand "extendhisi2" + [(set (match_dup 2) + (and:SI (match_operand:HI 1 "register_operand" "") ;Changed to SI below + (match_dup 4))) + (set (match_dup 3) (plus:SI (match_dup 2) (match_dup 5))) + (set (match_operand:SI 0 "register_operand" "") + (xor:SI (match_dup 3) (match_dup 5)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0); + + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[4] = force_reg (SImode, gen_rtx (CONST_INT, VOIDmode, 65535)); + operands[5] = force_reg (SImode, gen_rtx (CONST_INT, VOIDmode, -32768)); +}") + +(define_expand "extendqihi2" + [(set (match_dup 2) + (and:HI (match_operand:QI 1 "register_operand" "") ;Changed to SI below + (const_int 255))) + (set (match_dup 3) + (plus:SI (match_dup 2) (const_int -128))) + (set (match_operand:HI 0 "register_operand" "") + (xor:SI (match_dup 3) (const_int -128)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, HImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, HImode, operands[1], 0); + + operands[2] = gen_reg_rtx (HImode); + operands[3] = gen_reg_rtx (HImode); +}") + +(define_expand "extendqisi2" + [(set (match_dup 2) + (and:SI (match_operand:QI 1 "register_operand" "") ;Changed to SI below + (const_int 255))) + (set (match_dup 3) (plus:SI (match_dup 2) (const_int -128))) + (set (match_operand:SI 0 "register_operand" "") + (xor:SI (match_dup 3) (const_int -128)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0); + + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); +}") + +;;- arithmetic instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "add %0,%1,%2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "big_immediate_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned) (INTVAL (operands[2]) + 0x8000000) < 0x10000000" + "* +{ + return + output_add_large_offset (operands[0], operands[1], INTVAL (operands[2])); +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "sub %0,%1,%2") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "and %0,%1,%2") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "or %0,%1,%2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "xor %0,%1,%2") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "nonmemory_operand" "rI")))] + "" + "sub %0,r0,%1") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "xor %0,%1,$-1") + +;; Floating point arithmetic instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fadd %0,%1,%2") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "TARGET_FPU" + "fadd %0,%1,%2") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fsub %0,%1,%2") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "TARGET_FPU" + "fsub %0,%1,%2") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fmul %0,%1,%2") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "TARGET_FPU" + "fmul %0,%1,%2") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fdiv %0,%1,%2") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (div:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")))] + "TARGET_FPU" + "fdiv %0,%1,%2") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fneg %0,%1") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fneg %0,%1") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fabs %0,%1") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fabs %0,%1") + +;; Shift instructions + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "I")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ + unsigned int amount = INTVAL (operands[2]); + + switch (amount) + { + case 0: + return \"add_nt %0,%1,$0\"; + case 1: + return \"sll %0,%1,$1\"; + case 2: + return \"sll %0,%1,$2\"; + default: + output_asm_insn (\"sll %0,%1,$3\", operands); + + for (amount -= 3; amount >= 3; amount -= 3) + output_asm_insn (\"sll %0,%0,$3\", operands); + + if (amount > 0) + output_asm_insn (amount == 1 ? \"sll %0,%0,$1\" : \"sll %0,%0,$2\", + operands); + return \"\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "I")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ + unsigned int amount = INTVAL (operands[2]); + + if (amount == 0) + return \"add_nt %0,%1,$0\"; + else + output_asm_insn (\"sra %0,%1,$1\", operands); + + for (amount -= 1; amount > 0; amount -= 1) + output_asm_insn (\"sra %0,%0,$1\", operands); + + return \"\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "I")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ + unsigned int amount = INTVAL (operands[2]); + + if (amount == 0) + return \"add_nt %0,%1,$0\"; + else + output_asm_insn (\"srl %0,%1,$1\", operands); + + for (amount -= 1; amount > 0; amount -= 1) + output_asm_insn (\"srl %0,%0,$1\", operands); + + return \"\"; +}") + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 3)) + FAIL; +}") + +(define_expand "lshlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 3)) + FAIL; +}") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 1)) + FAIL; +}") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 1)) + FAIL; +}") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jump %l0\;nop") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jump_reg r0,%0\;nop") + +;;- jump to subroutine +(define_insn "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "general_operand" "g"))] + ;;- Don't use operand 1 for most machines. + "" + "add_nt r2,%0\;call .+8\;jump_reg r0,r2\;nop") + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "general_operand" "g")))] + ;;- Don't use operand 1 for most machines. + "" + "add_nt r2,%1\;call .+8\;jump_reg r0,r2\;nop") + +;; A memory ref with constant address is not normally valid. +;; But it is valid in a call insns. This pattern allows the +;; loading of the address to combine with the call. +(define_insn "" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "general_operand" "g"))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[0]) == SYMBOL_REF" + "call %0\;nop") + +(define_insn "" + [(set (match_operand 0 "" "=g") + (call (mem:SI (match_operand:SI 1 "" "i")) + (match_operand:SI 2 "general_operand" "g")))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[1]) == SYMBOL_REF" + "call %1\;nop") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/tahoe.md b/gcc-1.40/config/tahoe.md new file mode 100644 index 0000000..a96dd45 --- /dev/null +++ b/gcc-1.40/config/tahoe.md @@ -0,0 +1,1497 @@ +;;- Machine description for GNU compiler +;;- Tahoe version +;; Copyright (C) 1989 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +; File: tahoe.md +; +; This port made at the University of Buffalo by Devon Bowen, +; Dale Wiles and Kevin Zachmann. +; +; Mail bugs reports or fixes to: gcc@cs.buffalo.edu + + +; movdi must call the output_move_double routine to move it around since +; the tahoe doesn't efficiently support 8 bit moves. + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g") + (match_operand:DI 1 "general_operand" "g"))] + "" + "* +{ + CC_STATUS_INIT; + return output_move_double (operands); +}") + + +; The trick in the movsi is accessing the contents of the sp register. The +; tahoe doesn't allow you to access it directly so you have to access the +; address of the top of the stack instead. + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + rtx link; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + && no_labels_between_p (XEXP (link, 0), insn)) + return \"incl %0\"; + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 14) + return \"moval (sp),%0\"; + return \"movl %1,%0\"; +}") + + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + rtx link; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + && no_labels_between_p (XEXP (link, 0), insn)) + return \"incw %0\"; + if (operands[1] == const0_rtx) + return \"clrw %0\"; + return \"movw %1,%0\"; +}") + + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const0_rtx) + return \"clrb %0\"; + return \"movb %1,%0\"; +}") + + +; movsf has three cases since they can move from one place to another +; or to/from the fpp and since different instructions are needed for +; each case. The fpp related instructions don't set the flags properly. + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g,=a,=g") + (match_operand:SF 1 "general_operand" "g,g,a"))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"movl %1,%0\"; + case 1: + return \"ldf %1\"; + case 2: + return \"stf %0\"; + } +}") + + +; movdf has a number of different cases. If it's going to or from +; the fpp, use the special instructions to do it. If not, use the +; output_move_double function. + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=a,=g,?=g") + (match_operand:DF 1 "general_operand" "g,a,g"))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"ldd %1\"; + case 1: + if (push_operand (operands[0], DFmode)) + return \"pushd\"; + else + return \"std %0\"; + case 2: + return output_move_double (operands); + } +}") + + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == -1) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[1]) == REG) + { + if (push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + return \"movab %c2(%1),%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + return \"addl3 %1,%2,%0\"; +}") + + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + + +; addsf3 can only add into the fpp register since the fpp is treated +; as a separate unit in the machine. It also doesn't set the flags at +; all. + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"addf %2\"; +}") + + +; adddf3 can only add into the fpp reg since the fpp is treated as a +; separate entity. Doubles can only be read from a register or memory +; since a double is not an immediate mode. Flags are not set by this +; instruction. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"addd %2\"; +}") + + +; Subtraction from the sp (needed by the built in alloc funtion) needs +; to be different since the sp cannot be directly read on the tahoe. +; If it's a simple constant, you just use displacment. Otherwise, you +; push the sp, and then do the subtraction off the stack. + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decl %0\"; + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 14) + if (GET_CODE (operands[2]) == CONST_INT) + return \"movab %n2(sp),sp\"; + else + return \"pushab (sp)\;subl3 %2,(sp),sp\"; + return \"subl2 %2,%0\"; + } + if (rtx_equal_p (operands[1], operands[2])) + return \"clrl %0\"; + return \"subl3 %2,%1,%0\"; +}") + + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decw %0\"; + return \"subw2 %2,%0\"; + } + if (rtx_equal_p (operands[1], operands[2])) + return \"clrw %0\"; + return \"subw3 %2,%1,%0\"; +}") + + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decb %0\"; + return \"subb2 %2,%0\"; + } + if (rtx_equal_p (operands[1], operands[2])) + return \"clrb %0\"; + return \"subb3 %2,%1,%0\"; +}") + + +; subsf3 can only subtract into the fpp accumulator due to the way +; the fpp reg is limited by the instruction set. This also doesn't +; bother setting up flags. + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"subf %2\"; +}") + + +; subdf3 is set up to subtract into the fpp reg due to limitations +; of the fpp instruction set. Doubles can not be immediate. This +; instruction does not set the flags. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"subd %2\"; +}") + + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mult:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mull2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mull2 %1,%0\"; + return \"mull3 %1,%2,%0\"; +}") + + +; mulsf3 can only multiply into the fpp accumulator due to limitations +; of the fpp. It also does not set the condition codes properly. + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"mulf %2\"; +}") + + +; muldf3 can only multiply into the fpp reg since the fpp is limited +; from the rest. Doubles may not be immediate mode. This does not set +; the flags like GCC would expect. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"muld %2\"; +}") + + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (div:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"movl $1,%0\"; + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == -1) + return \"mnegl %1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"divl2 %2,%0\"; + return \"divl3 %2,%1,%0\"; +}") + + +; divsf3 must divide into the fpp accumulator. Flags are not set by +; this instruction, so they are cleared. + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"divf %2\"; +}") + + +; divdf3 also must divide into the fpp reg so optimization isn't +; possible. Note that doubles cannot be immediate. The flags here +; are not set correctly so they must be ignored. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"divd %2\"; +}") + + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "andl3 %2,%1,%0") + + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "andw3 %1,%2,%0") + + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "andb3 %1,%2,%0") + + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "orl3 %2,%1,%0") + + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "orw3 %2,%1,%0") + + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "orb3 %2,%1,%0") + + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "xorl3 %1,%2,%0") + + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "xorw3 %1,%2,%0") + + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "xorb3 %1,%2,%0") + + +; Shifts on the tahoe are expensive, so try to do an add instead. + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + { + CC_STATUS_INIT; + return \"addl2 %0,%0\"; + } + return \"shal %2,%1,%0\"; +}") + + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "shar %2,%1,%0") + + +; Shifts are very expensive, so try to do an add if possible. + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + { + CC_STATUS_INIT; + return \"addl2 %0,%0\"; + } + return \"shll %2,%1,%0\"; +}") + + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "shrl %2,%1,%0") + + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + + +; negsf2 can only negate the value already in the fpp accumulator. +; The value remains in the fpp accumulator. No flags are set. + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=a,=a") + (neg:SF (match_operand:SF 1 "register_operand" "a,g")))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"negf\"; + case 1: + return \"lnf %1\"; + } +}") + + +; negdf2 can only negate the value already in the fpp accumulator. +; The value remains in the fpp accumulator. No flags are set. + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=a,=a") + (neg:DF (match_operand:DF 1 "register_operand" "a,g")))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"negd\"; + case 1: + return \"lnd %1\"; + } +}") + + +; sqrtsf2 tahoe can calculate the square root of a float in the +; fpp accumulator. The answer remains in the fpp accumulator. No +; flags are set by this function. + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=a") + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "" + "* +{ + CC_STATUS_INIT; + return \"sqrtf\"; +}") + + +; ffssi2 tahoe instruction gives one less than GCC desired result for +; any given input. So the increment is necessary here. + +(define_insn "ffssi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (ffs:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "ffs %1,%0\;incl %0") + + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + + +; cmpsi works fine, but due to microcode problems, the tahoe doesn't +; properly compare hi's and qi's. Leaving them out seems to be acceptable +; to the compiler, so they were left out. Compares of the stack are +; possible, though. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + + +; cmpsf similar to vax, but first operand is expected to be in the +; fpp accumulator. + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "a") + (match_operand:SF 1 "general_operand" "g")))] + "" + "cmpf %1") + + +; cmpdf similar to vax, but first operand is expected to be in the +; fpp accumulator. Immediate doubles not allowed. + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "a") + (match_operand:DF 1 "general_operand" "rm")))] + "" + "cmpd %1") + + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "g"))] + "" + "tstl %0") + + +; Small tests from memory are normal, but testing from registers don't +; expand the data properly. So test in this case does a convert and tests +; the new register data from the stack. + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "m,?r"))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"tstw %0\"; + case 1: + return \"pushl %0\;cvtwl 2(sp),(sp)\;tstl (sp)+\"; + } +}") + + +; Small tests from memory are normal, but testing from registers don't +; expand the data properly. So test in this case does a convert and tests +; the new register data from the stack. + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "m,?r"))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"tstb %0\"; + case 1: + return \"pushl %0\;cvtbl 3(sp),(sp)\;tstl (sp)+\"; + } +}") + + +; tstsf compares a given value to a value already in the fpp accumulator. +; No flags are set by this so ignore them. + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "a"))] + "" + "tstf") + + +; tstdf compares a given value to a value already in the fpp accumulator. +; immediate doubles not allowed. Flags are ignored after this. + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "a"))] + "" + "tstd") + + +; movstrhi tahoe instruction does not load registers by itself like +; the vax counterpart does. registers 0-2 must be primed by hand. +; we have loaded the registers in the order: dst, src, count. + +(define_insn "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "p") + (match_operand:BLK 1 "general_operand" "p")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2))] + "" + "movab %0,r1\;movab %1,r0\;movl %2,r2\;movblk") + + +; floatsisf2 on tahoe converts the long from reg/mem into the fpp +; accumulator. There are no hi and qi counterparts. Flags are not +; set correctly here. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=a") + (float:SF (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvlf %1\"; +}") + + +; floatsidf2 on tahoe converts the long from reg/mem into the fpp +; accumulator. There are no hi and qi counterparts. Flags are not +; set correctly here. + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=a") + (float:DF (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvld %1\"; +}") + + +; fix_truncsfsi2 to convert a float to long, tahoe must have the float +; in the fpp accumulator. Flags are not set here. + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "a"))))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvfl %0\"; +}") + + +; fix_truncsfsi2 to convert a double to long, tahoe must have the double +; in the fpp accumulator. Flags are not set here. + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a"))))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvdl %0\"; +}") + + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlw %1,%0") + + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlb %1,%0") + + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwb %1,%0") + + +; The fpp related instructions don't set flags, so ignore them +; after this instruction. + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=a") + (float_truncate:SF (match_operand:DF 1 "register_operand" "0")))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvdf\"; +}") + + +; This monster is to cover for the Tahoe's nasty habit of not extending +; a number if the source is in a register. (It just moves it!) Case 0 is +; a normal extend from memory. Case 1 does the extension from the top of +; the stack. Extension from the stack doesn't set the flags right since +; the moval changes them. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (sign_extend:SI (match_operand:HI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"cvtwl %1,%0\"; + case 1: + if (push_operand(operands[0], SImode)) + return \"pushl %1\;cvtwl 2(sp),(sp)\"; + else + { + CC_STATUS_INIT; + return \"pushl %1\;cvtwl 2(sp),%0\;moval 4(sp),sp\"; + } + } +}") + + +; This monster is to cover for the Tahoe's nasty habit of not extending +; a number if the source is in a register. (It just moves it!) Case 0 is +; a normal extend from memory. Case 1 does the extension from the top of +; the stack. Extension from the stack doesn't set the flags right since +; the moval changes them. + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (sign_extend:SI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"cvtbl %1,%0\"; + case 1: + if (push_operand(operands[0], SImode)) + return \"pushl %1\;cvtbl 3(sp),(sp)\"; + else + { + CC_STATUS_INIT; + return \"pushl %1\;cvtbl 3(sp),%0\;moval 4(sp),sp\"; + } + } +}") + + +; This monster is to cover for the Tahoe's nasty habit of not extending +; a number if the source is in a register. (It just moves it!) Case 0 is +; a normal extend from memory. Case 1 does the extension from the top of +; the stack. Extension from the stack doesn't set the flags right since +; the moval changes them. + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g,?=g") + (sign_extend:HI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"cvtbw %1,%0\"; + case 1: + if (push_operand(operands[0], SImode)) + return \"pushl %1\;cvtbw 3(sp),2(sp)\"; + else { + CC_STATUS_INIT; + return \"pushl %1\;cvtbw 3(sp),%0\;moval 4(sp),sp\"; + } + } +}") + + +; extendsfdf2 tahoe uses the fpp accumulator to do the extension. +; It takes a float and loads it up directly as a double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=a") + (float_extend:DF (match_operand:SF 1 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"ldfd %1\"; +}") + + +; movz works fine from memory but not from register for the same reasons +; the cvt instructions don't work right. So we use the normal instruction +; from memory and we use an and to simulate it from register. This is faster +; than pulling it off the stack. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (zero_extend:SI (match_operand:HI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"movzwl %1,%0\"; + case 1: + return \"andl3 $0xffff,%1,%0\"; + } +}") + + +; movz works fine from memory but not from register for the same reasons +; the cvt instructions don't work right. So we use the normal instruction +; from memory and we use an and to simulate it from register. This is faster +; than pulling it off the stack. + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g,?=g") + (zero_extend:HI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"movzbw %1,%0\"; + case 1: + return \"andw3 $0xff,%1,%0\"; + } +}") + + +; movz works fine from memory but not from register for the same reasons +; the cvt instructions don't work right. So we use the normal instruction +; from memory and we use an and to simulate it from register. This is faster +; than pulling it off the stack. + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (zero_extend:SI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"movzbl %1,%0\"; + case 1: + return \"andl3 $0xff,%1,%0\"; + } +}") + + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + + +; GCC does not account for register mask/argc longword. Thus the number +; for the call = number bytes for args + 4 + +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 4)); + return \"calls %1,%0\"; +}") + + +; GCC does not account for register mask/argc longword. Thus the number +; for the call = number bytes for args + 4 + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 4)); + return \"calls %2,%1\"; +}") + + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + + +(define_insn "return" + [(return)] + "" + "ret") + + +; casesi, extracted from the vax code. The instructions are +; very similar. Tahoe requires that the table be word aligned. GCC +; places the table immediately after, thus the alignment directive. + +(define_insn "casesi" + [(set (pc) + (if_then_else (le (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (match_dup 1))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2\;.align %@") + + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + + +;; This is the list of all the non-standard insn patterns + + +; This is used to access the address of a byte. This is similar to +; movqi, but the second operand had to be "address_operand" type, so +; it had to be an unnamed one. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; +}") + +; This is used to access the address of a word. This is similar to +; movhi, but the second operand had to be "address_operand" type, so +; it had to be an unnamed one. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + return \"movaw %a1,%0\"; +}") + +; This is used to access the address of a long. This is similar to +; movsi, but the second operand had to be "address_operand" type, so +; it had to be an unnamed one. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + return \"moval %a1,%0\"; +}") + +; The tahoe doesn't have an 8 byte indexed move address command +; and GCC needs it. To work around it, double the index (%2) and +; then use the 4 byte indexed move address command. +; +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (plus:SI (match_operand:SI 1 "general_operand" "g") +; (mult:SI (match_operand:SI 2 "register_operand" "r") +; (const_int 8))))] +; "" +; "* +;{ +; if (GET_CODE (operands[0]) == REG && +; REGNO (operands[0]) == REGNO (operands[2])) { +; return \"shll $3,%2,%2\;addl3 %1,%2,%0\"; +; } else { +; return \"shll $3,%2,%2\;addl3 %1,%2,%0\;shrl $3,%2,%2\"; } +;}") + + +; Bit test longword instruction, same as vax. + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + + +; Bit test word instructions, same as vax. + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + + +; Bit test instructions, same as vax. + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + + +; bne counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jneq %l0") + + +; beq counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jeql %l0") + + +; ble counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jleq %l0") + + +; bleu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlequ %l0") + + +; bge counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgeq %l0") + + +; bgeu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgequ %l0") + + +; blt counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlss %l0") + + +; bltu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlssu %l0") + + +; bgt counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtr %l0") + + +; bgtu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtru %l0") + + +; casesi alternate form as found in vax code. This form is to +; compensate for the table's offset being no distance (0 displacement) + +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (const_int 0))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1\;.align %@") + + +; casesi alternate form as found in vax code. Another form to +; compensate for the table's offset being no distance (0 displacement) + +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (match_dup 0)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1 \;.align %@") diff --git a/gcc-1.40/config/tm-3b1.h b/gcc-1.40/config/tm-3b1.h new file mode 100644 index 0000000..13b8f12 --- /dev/null +++ b/gcc-1.40/config/tm-3b1.h @@ -0,0 +1,482 @@ +/* Definitions of target machine for GNU compiler. + AT&T UNIX PC version (pc7300, 3b1) + + Written by Alex Crain + bug reports to alex@umbc3.umd.edu + + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define SGS_3B1 + +#include "tm-hp9k320.h" + +/* See tm-m68k.h. 0 means 680[01]0 with no 68881. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 0 + +/* -m68020 requires special flags to the assembler. */ + +#undef ASM_SPEC +#define ASM_SPEC "%{m68020:-68020}%{!m68020:-68010}" + +/* we use /lib/libp/lib* when profiling */ + +#undef LIB_SPEC +#define LIB_SPEC "%{!shlib:%{p:-L/lib/libp} %{pg:-L/lib/libp} -lc}" + +/* shared libraries need to use crt0s.o */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} " + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +/* Don't try to define `gcc_compiled.' since the assembler might not + accept symbols with periods and GDB doesn't run on this machine anyway. */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* ihnp4!lmayk!lgm@eddie.mit.edu says mc68000 and m68k should not be here. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68k -Dunix -Dunixpc" + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ + +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* Override parts of tm-m68k.h to fit the SGS-3b1 assembler. */ + +#undef TARGET_VERSION +#undef ASM_FORMAT_PRIVATE_NAME +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SOURCE_FILENAME +#undef ASM_OUTPUT_SOURCE_LINE +#undef PRINT_OPERAND_ADDRESS +#undef ASM_GENERATE_INTERNAL_LABEL +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_OPCODE +#undef ASM_OUTPUT_LOCAL +#undef ASM_OUTPUT_LABELREF +#undef ASM_OUTPUT_ASCII + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T unixpc syntax)"); + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \ + sprintf ((OUTPUT), "%s_%%%d", (NAME), (LABELNO))) + +/* The unixpc doesn't know about double's and float's */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long l[2]; } tem; \ + tem.d = (VALUE); \ + fprintf(FILE, "\tlong 0x%x,0x%x\n", tem.l[0], tem.l[1]); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\tlong 0x%x\n", tem.l); \ + } while (0) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +/* The `space' pseudo in the text segment outputs nop insns rather than 0s, + so we must output 0s explicitly in the text segment. */ +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + if (in_text_section ()) \ + { \ + int i; \ + for (i = 0; i < (SIZE) - 20; i += 20) \ + fprintf (FILE, "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); \ + if (i < (SIZE)) \ + { \ + fprintf (FILE, "\tbyte 0"); \ + i++; \ + for (; i < (SIZE); i++) \ + fprintf (FILE, ",0"); \ + fprintf (FILE, "\n"); \ + } \ + } \ + else \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +/* The beginnings of sdb support... */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + fprintf (FILE, "\tfile\t\"%s\"\n", FILENAME) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* Yet another null terminated string format. */ + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + { register int sp = 0, lp = 0; \ + fprintf (FILE, "\tbyte\t"); \ + loop: \ + if (PTR[sp] > ' ' && ! (PTR[sp] & 0x80) && PTR[sp] != '\\') \ + { lp += 3; \ + fprintf (FILE, "'%c", PTR[sp]); } \ + else \ + { lp += 5; \ + fprintf (FILE, "0x%x", PTR[sp]); } \ + if (++sp < LEN) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf (FILE, "\n%s ", ASCII_DATA_ASM_OP); } \ + else \ + putc (',', FILE); \ + goto loop; } \ + putc ('\n', FILE); } + +/* Note that in the case of the movhi which fetches an element of + an ADDR_DIFF_VEC the offset output is too large by 2. + This is because the 3b1 assembler refuses to subtract 2. + ASM_OUTPUT_CASE_LABEL, below, compensates for this. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "LD%%%d(%%pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "LD%%%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + fprintf (FILE, ")"); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "LD%%%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "LD%%%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%%%d:\n", PREFIX, NUM) + +/* Must put address in %a0 , not %d0 . -- LGM, 7/15/88 */ +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +/* ihnp4!lmayk!lgm says that `short 0' triggers assembler bug; + `short L%nn-L%nn' supposedly works. */ +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + if (! RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); \ + else \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n\tshort %s%%%d-%s%%%d\n", \ + XVECLEN (PATTERN (TABLE), 1) + 1, (PREFIX), (NUM), \ + (PREFIX), (NUM), (PREFIX), (NUM)) + +/* At end of a switch table, define LD%n iff the symbol LI%n was defined. */ +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ + if (RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tset LD%%%d,L%%%d-LI%%%d\n", (NUM), (NUM), (NUM)) + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' || \ + (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'm') (PTR)++; } \ +} + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +/* Define subroutines to call to handle multiply, divide, and remainder. + Use the subroutines that the 3b1's library provides. + The `*' prevents an underscore from being prepended by the compiler. */ + +#define DIVSI3_LIBCALL "*ldiv" +#define UDIVSI3_LIBCALL "*uldiv" +#define MODSI3_LIBCALL "*lrem" +#define UMODSI3_LIBCALL "*ulrem" +#define MULSI3_LIBCALL "*lmul" +#define UMULSI3_LIBCALL "*ulmul" diff --git a/gcc-1.40/config/tm-3b1g.h b/gcc-1.40/config/tm-3b1g.h new file mode 100644 index 0000000..783613e --- /dev/null +++ b/gcc-1.40/config/tm-3b1g.h @@ -0,0 +1,63 @@ +/* Definitions of target machine for GNU compiler, for a 3b1 using GAS. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-m68k.h" + +/* See tm-m68k.h. 0 means 68000 with no 68881. */ +#define TARGET_DEFAULT 0 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ +#define CPP_PREDEFINES "-Dmc68000 -Dmc68k -Dunix -Dunixpc" + +/* This is (not really) BSD, so (but) it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Brain damage. */ +#define SCCS_DIRECTIVE + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override part of the obstack macros. */ +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* Every structure or union's size must be a multiple of 2 bytes. */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + diff --git a/gcc-1.40/config/tm-aix386.h b/gcc-1.40/config/tm-aix386.h new file mode 100644 index 0000000..b9fd6ed --- /dev/null +++ b/gcc-1.40/config/tm-aix386.h @@ -0,0 +1,129 @@ +/* Definitions for IBM PS2 running AIX/386. + From: Minh Tran-Le <TRANLE@intellicorp.com> + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-i386.h" + +/* Use the ATT assembler syntax. */ + +#include "tm-att386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc crtn.o%s" + +/* Special flags for the linker. I don't know what they do. */ + +#define LINK_SPEC "%{K} %{!K:-K} %{T*} %{z:-lm}" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-D_I386 -Di386 -DAIX -D_AIX" + +/* special flags for the aix assembler to generate the short form for all + qualifying forward reference */ + +#define ASM_SPEC "-s2" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + char *p = (char *) strrchr (main_input_filename, '/'); \ + if (!p) \ + p = main_input_filename; \ + else p++; \ + fprintf ((FILE), "\t.file\t\"%s\"\n", p); \ + } while (0) + +/* This used to output .noopt if nonoptimizing and run ASM_FILE_START_1 + if optimizing, but that loses with the AIX assembler. */ + +/* This was suggested, but it shouldn't be right for DBX output. -- RMS + #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) */ + +/* We want to output SDB debugging information. */ + +#define SDB_DEBUGGING_INFO + +/* We don't want to output DBX debugging information. Becaus IBM AIX dbx + use COFF format */ + +#undef DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Don't write a `.optim' pseudo; this assembler + is said to have a bug when .optim is used. */ + +#if 0 +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.noopt\n"); +#endif + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tleal %sP%d,%%eax\n\tcall mcount\n", LPREFIX, (LABELNO)); + +/* Note that using bss_section here caused errors + in building shared libraries on system V.3. + but AIX 1.2 does not have yet shareable libraries on PS2 */ +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + (bss_section (), \ + ASM_OUTPUT_LABEL ((FILE), (NAME)), \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED))) diff --git a/gcc-1.40/config/tm-alliant.h b/gcc-1.40/config/tm-alliant.h new file mode 100644 index 0000000..c1926e6 --- /dev/null +++ b/gcc-1.40/config/tm-alliant.h @@ -0,0 +1,1440 @@ +/* Definitions of target machine for GNU compiler. Alliant FX version. + Copyright (C) 1989 Free Software Foundation, Inc. + Adapted from tm-m68k.h by Paul Petersen (petersen@uicsrd.csrd.uiuc.edu) + and Joe Weening (weening@gang-of-four.stanford.edu). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* This file is based on tm-m68k.h, simplified by removing support for + the Sun FPA and other things not applicable to the Alliant. Some + remnants of these features remain. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dalliant -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (Alliant)"); + +/* Run-time compilation parameters selecting different hardware + subsets. The Alliant IP is an mc68020. (Older mc68010-based IPs + are no longer supported.) The Alliant CE is 68020-compatible, and + also has floating point, vector and concurrency instructions. + + Although the IP doesn't have floating point, it emulates it in the + operating system. Using this generally is faster than running code + compiled with -msoft-float, because the soft-float code still uses + (simulated) FP registers and ends up emulating several fmove{s,d} + instructions per call. So I don't recommend using soft-float for + any Alliant code. -- JSW +*/ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile for a 68020 (not a 68000 or 68010). */ +#define TARGET_68020 (target_flags & 1) +/* Compile CE insns for floating point (not library calls). */ +#define TARGET_CE (target_flags & 2) +/* Compile using 68020 bitfield insns. */ +#define TARGET_BITFIELD (target_flags & 4) +/* Compile with 16-bit `int'. */ +#define TARGET_SHORT (target_flags & 040) + +/* Default 3 means compile 68020 and CE instructions. We don't use + bitfield instructions because there appears to be a bug in the + implementation of bfins on the CE. */ + +#define TARGET_DEFAULT 3 + +/* Define __HAVE_CE__ in preprocessor according to the -m flags. + This will control the use of inline FP insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -mce is the default */ +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_CE__ }\ +%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{mce:-D__HAVE_CE__ }\ +%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}" + +#endif + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "bitfield", 4}, \ + { "68000", -7}, \ + { "c68000", -7}, \ + { "soft-float", -2}, \ + { "nobitfield", -4}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "", TARGET_DEFAULT}} + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is true for 68020 insns such as bfins and bfexts. + We make it true always by avoiding using the single-bit insns + except in special cases with constant bit numbers. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 68000. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For 68000 we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY (TARGET_SHORT ? 16 : 32) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 16 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Define number of bits in most basic integer type. + (If undefined, default is BITS_PER_WORD). */ + +#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32) + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + For the Alliant, we give the data registers numbers 0-7, + the address registers numbers 010-017, + and the floating point registers numbers 020-027. */ +#define FIRST_PSEUDO_REGISTER 24 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the Alliant, these are a0 (argument pointer), + a6 (frame pointer) and a7 (stack pointer). */ +#define FIXED_REGISTERS \ + {0, 0, 0, 0, 0, 0, 0, 0, \ + 1, 0, 0, 0, 0, 0, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0 } + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + The Alliant calling sequence allows a function to use any register, + so we include them all here. */ + +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1 } + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the Alliant, ordinary registers hold 32 bits worth; + for the FP registers, a single register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 16 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the Alliant, the cpu registers can hold any mode but the FP registers + can hold only SFmode or DFmode. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 16 || (MODE) == SFmode || (MODE) == DFmode) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* m68000 pc isn't overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 15 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 14 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +/* Set for now on Alliant until we find a way to make this work with + their calling sequence. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 8 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The Alliant has three kinds of registers, so eight classes would be + a complete set. One of them is not needed. */ + +enum reg_class { NO_REGS, FP_REGS, DATA_REGS, DATA_OR_FP_REGS, + ADDR_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + { "NO_REGS", "FP_REGS", "DATA_REGS", "DATA_OR_FP_REGS", \ + "ADDR_REGS", "GENERAL_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ +{ \ + 0, /* NO_REGS */ \ + 0x00ff0000, /* FP_REGS */ \ + 0x000000ff, /* DATA_REGS */ \ + 0x00ff00ff, /* DATA_OR_FP_REGS */ \ + 0x0000ff00, /* ADDR_REGS */ \ + 0x0000ffff, /* GENERAL_REGS */ \ + 0x00ffffff /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +extern enum reg_class regno_reg_class[]; +#define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)>>3]) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS ADDR_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? ADDR_REGS : \ + ((C) == 'd' ? DATA_REGS : \ + ((C) == 'f' ? FP_REGS : \ + NO_REGS))) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For the 68000, `I' is used for the range 1 to 8 + allowed as immediate shift counts and in addq. + `J' is used for the range of signed numbers that fit in 16 bits. + `K' is for numbers that moveq can't handle. + `L' is for range -8 to -1, range of values that can be added with subq. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) > 0 && (VALUE) <= 8 : \ + (C) == 'J' ? (VALUE) >= -0x8000 && (VALUE) <= 0x7FFF : \ + (C) == 'K' ? (VALUE) < -0x80 || (VALUE) >= 0x80 : \ + (C) == 'L' ? (VALUE) < 0 && (VALUE) >= -8 : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. + On the 68000 series, use a data reg if possible when the + value is a constant in the range where moveq could be used + and we ensure that QImodes are reloaded into data regs. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x80) < 0x100 \ + && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : GET_MODE (X) == QImode \ + ? DATA_REGS \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 68000, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* The Alliant uses -fcaller-saves by default. */ +#define DEFAULT_CALLER_SAVES + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET -4 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 68000, sp@- in a byte insn really pushes a word. */ +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + On the Alliant we define this as 1 and make the calling sequence + (in alliant.md) pop the args. This wouldn't be necessary if we + could add to the pending stack adjustment the size of the argument + descriptors that are pushed after the arguments. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 1 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the Alliant the return value is in FP0 if real, else D0. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the Alliant the return value is in FP0 if real, else D0. The + Alliant library functions for floating-point emulation return their + values both in FP0 and in D0/D1. But since not all gnulib functions + return the results of these directly, we cannot assume that D0/D1 + contain the values we expect on return from a gnulib function. */ + +#define LIBCALL_VALUE(MODE) \ + (((MODE) == DFmode || (MODE) == SFmode) \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the Alliant, D0 and FP0 are the only registers thus used. + (No need to mention D1 when used as a pair with D0.) */ + +#define FUNCTION_VALUE_REGNO_P(N) (((N) & ~16) == 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for function argument passing. + On the Alliant, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the Alliant, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the Alliant, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the Alliant all args are pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. + The Alliant uses caller-saves, so this macro is very simple. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ int fsize = ((SIZE) - STARTING_FRAME_OFFSET + 3) & -4; \ + if (frame_pointer_needed) \ + { \ + if (fsize < 0x8000) \ + fprintf(FILE,"\tlinkw a6,#%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf(FILE,"\tlinkl a6,#%d\n", -fsize); \ + else \ + fprintf(FILE,"\tlinkw a6,#0\n\tsubl #%d,sp\n", fsize); \ + fprintf(FILE, "\tmovl a0,a6@(-4)\n" ); }} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tjbsr __mcount_\n") + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 1 + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk a6\n"); \ + fprintf (FILE, "\trts\n"); } + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } \ + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT +/* #define HAVE_POST_DECREMENT */ + +#define HAVE_PRE_DECREMENT +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +(((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8) +#define REGNO_OK_FOR_DATA_P(REGNO) \ +((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8) + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the 68000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is a data register. */ + +#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X))) + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* 1 if X is an address register */ + +#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +/* Alliant FP instructions don't take immediate operands, so this + forces them into memory. */ +#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) ((REGNO (X) ^ 020) >= 8) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) ((REGNO (X) & ~027) != 0) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + || (GET_CODE (X) == PLUS \ + && REG_P (XEXP (X, 0)) && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)) + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; } + +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ +{ if (GET_CODE (X) == LABEL_REF) goto ADDR; \ + if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR; } + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +#define GO_IF_INDEXED_ADDRESS(X, ADDR) \ +{ GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); } \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } } + +#define LEGITIMATE_INDEX_REG_P(X) \ + ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ + || (GET_CODE (X) == SIGN_EXTEND \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_MODE (XEXP (X, 0)) == HImode \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)))) + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || (TARGET_68020 && GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || INTVAL (XEXP (X, 1)) == 8))) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + GO_IF_INDEXED_ADDRESS (X, ADDR); } + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the 68000, we handle X+REG by loading X into a register R and + using R+REG. R will go in an address reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in an address reg. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == MULT) \ + ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + return X; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 1) = temp; \ + return X; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 0) = temp; \ + return X; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 68000, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE -1 + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Check a `double' value for validity for a particular machine mode. + This is defined to avoid crashes outputting certain constants. */ + +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 3.4028234663852890e+38) \ + { warning ("magnitude of value too large for `float'"); \ + (d) = 3.4028234663852890e+38; } \ + else if ((d) < -3.4028234663852890e+38) \ + { warning ("magnitude of value too large for `float'"); \ + (d) = -3.4028234663852890e+38; } \ + else if (((d) > 0) && ((d) < 1.1754943508222873e-38)) \ + (d) = 0.0; \ + else if (((d) < 0) && ((d) > -1.1754943508222873e-38)) \ + (d) = 0.0; \ + } + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* On the Alliant, floating-point instructions do not modify the + ordinary CC register. Only fcmp and ftest instructions modify the + floating-point CC register. We should actually keep track of what + both kinds of CC registers contain, but for now we only consider + the most recent instruction that has set either register. */ + +/* Set if the cc value came from a floating point test, so a floating + point conditional branch must be output. */ +#define CC_IN_FP 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the 68000, all the insns to store in an address register + fail to set the cc's. However, in some cases these instructions + can make it possibly invalid to use the saved cc's. In those + cases we clear out some or all of the saved cc's so they won't be used. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ \ + if (GET_CODE (EXP) == SET) \ + { if (ADDRESS_REG_P (SET_DEST (EXP)) || FP_REG_P (SET_DEST (EXP))) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2)) \ + cc_status.value2 = 0; } \ + else if (SET_DEST (EXP) != cc0_rtx \ + && (FP_REG_P (SET_SRC (EXP)) \ + || GET_CODE (SET_SRC (EXP)) == FIX \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_TRUNCATE \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_EXTEND)) \ + { CC_STATUS_INIT; } \ + /* A pair of move insns doesn't produce a useful overall cc. */ \ + else if (!FP_REG_P (SET_DEST (EXP)) \ + && !FP_REG_P (SET_SRC (EXP)) \ + && GET_MODE_SIZE (GET_MODE (SET_SRC (EXP))) > 4 \ + && (GET_CODE (SET_SRC (EXP)) == REG \ + || GET_CODE (SET_SRC (EXP)) == MEM \ + || GET_CODE (SET_SRC (EXP)) == CONST_DOUBLE))\ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (XEXP (EXP, 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (EXP, 0); \ + cc_status.value2 = XEXP (EXP, 1); } } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { \ + if (ADDRESS_REG_P (XEXP (XVECEXP (EXP, 0, 0), 0))) \ + CC_STATUS_INIT; \ + else if (XEXP (XVECEXP (EXP, 0, 0), 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (XVECEXP (EXP, 0, 0), 0); \ + cc_status.value2 = XEXP (XVECEXP (EXP, 0, 0), 1); } } \ + else CC_STATUS_INIT; \ + if (cc_status.value2 != 0 \ + && ADDRESS_REG_P (cc_status.value2) \ + && GET_MODE (cc_status.value2) == QImode) \ + CC_STATUS_INIT; \ + if (cc_status.value2 != 0) \ + switch (GET_CODE (cc_status.value2)) \ + { case PLUS: case MINUS: case MULT: case UMULT: \ + case DIV: case UDIV: case MOD: case UMOD: case NEG: \ + case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT: \ + case ROTATE: case ROTATERT: \ + if (GET_MODE (cc_status.value2) != VOIDmode) \ + cc_status.flags |= CC_NO_OVERFLOW; \ + break; \ + case ZERO_EXTEND: \ + /* (SET r1 (ZERO_EXTEND r2)) on this machine + ends with a move insn moving r2 in r2's mode. + Thus, the cc's are set for r2. + This can set N bit spuriously. */ \ + cc_status.flags |= CC_NOT_NEGATIVE; } \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + cc_status.value2 = 0; \ + if ((cc_status.value1 && FP_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FP_REG_P (cc_status.value2))) \ + cc_status.flags = CC_IN_FP; } + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ if (cc_prev_status.flags & CC_IN_FP) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\t.text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\t.data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7" } + +/* How to renumber registers for dbx and gdb. + On the Sun-3, the floating point registers have numbers + 18 to 25, not 16 to 23 as they do in the compiler. */ +/* (On the Alliant, dbx isn't working yet at all. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs ("\t.globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long v[2];} tem; \ + tem.d = (VALUE); \ + fprintf (FILE, "\t.long 0x%x,0x%x\n", tem.v[0], tem.v[1]); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\t.long 0x%x\n", tem.l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_ASCII(FILE,PTR,SIZE) \ +{ int i; unsigned char *pp = (unsigned char *) PTR; \ + fprintf(FILE, "\t.byte %d", (unsigned int)*pp++); \ + for (i = 1; i < SIZE; ++i, ++pp) { \ + if ((i % 8) == 0) \ + fprintf(FILE, "\n\t.byte %d", (unsigned int) *pp); \ + else \ + fprintf(FILE, ",%d", (unsigned int) *pp); } \ + fprintf (FILE, "\n"); } + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovl %s,sp@-\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovl sp@+,%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\t.even\n"); \ + else if ((LOG) != 0) \ + fprintf (FILE, "\t.align %dn", (LOG)); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t. = . + %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On the Alliant, we use several CODE characters: + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax). + '!' for the cc register (used in an `and to cc' insn). + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \ + || (CODE) == '+' || (CODE) == '@' || (CODE) == '!') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ int i; \ + if (CODE == '.') ; \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "sp@-"); \ + else if (CODE == '+') fprintf (FILE, "sp@+"); \ + else if (CODE == '@') fprintf (FILE, "sp@"); \ + else if (CODE == '!') fprintf (FILE, "cc"); \ + else if ((X) == 0 ) ; \ + else if (GET_CODE (X) == REG) \ + { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \ + fprintf (FILE, "%s,%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \ + else \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + } \ + else if (GET_CODE (X) == MEM) \ + { \ + output_address (XEXP (X, 0)); \ + if (CODE == 'd' && ! TARGET_68020 \ + && CONSTANT_ADDRESS_P (XEXP (X, 0)) \ + && !(GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) < 0x8000 \ + && INTVAL (XEXP (X, 0)) >= -0x8000)) \ + fprintf (FILE, ":l"); \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "#0r%.9g", u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#0r%.20g", u.d); } \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that m68k.md + generates a label LInnn: on such an insn. */ +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + static char *sz = ".BW.L...D"; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "%s@", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:W", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + fprintf (FILE, ":%c", sz[scale]); \ + putc (']', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L:B]", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "%s@", reg_names[REGNO (breg)]); \ + if (addr != 0) { \ + putc( '(', FILE ); \ + output_addr_const (FILE, addr); \ + if (ireg != 0) { \ + if (GET_CODE(addr) == CONST_INT) { \ + int size_of = 1, val = INTVAL(addr); \ + if (val < -0x8000 || val >= 0x8000) \ + size_of = 4; \ + else if (val < -0x80 || val >= 0x80) \ + size_of = 2; \ + fprintf(FILE, ":%c", sz[size_of]); \ + } \ + else \ + fprintf(FILE, ":L"); } \ + putc( ')', FILE ); } \ + if (ireg != 0) { \ + putc ('[', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s:W", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s:L", reg_names[REGNO (ireg)]); \ + fprintf (FILE, ":%c", sz[scale]); \ + putc (']', FILE); \ + } \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L:B]", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d:W", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +/* +Local variables: +version-control: t +End: +*/ + diff --git a/gcc-1.40/config/tm-altos3068.h b/gcc-1.40/config/tm-altos3068.h new file mode 100644 index 0000000..36c63c5 --- /dev/null +++ b/gcc-1.40/config/tm-altos3068.h @@ -0,0 +1,107 @@ +/* Definitions of target machine for GNU compiler. Altos 3068 68020 version. + Copyright (C) 1988,1989 Free Software Foundation, Inc. + +Written by Jyrki Kuoppala <jkp@cs.hut.fi> +Last modified: Mon Mar 6 22:47:58 1989 + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ +/* 5 is without 68881. Change to 7 if you have 68881 */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 5 +#endif + +/* Define __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#endif + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -DPORTAR -Dmc68k32 -Uvax -Dm68k -Dunix" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* We use gnu assembler, linker and gdb, so we want DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Tell some conditionals we will use GAS. Is this really used? */ + +#define USE_GAS + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0r%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.single 0r%.20e\n", (VALUE)) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.9g", (VALUE)) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.20g", (VALUE)) + +/* Return pointer values in both d0 and a0. */ + +#undef FUNCTION_EXTRA_EPILOGUE +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ +{ \ + extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode))\ + fprintf (FILE, "\tmovel d0,a0\n"); \ +} diff --git a/gcc-1.40/config/tm-apollo68.h b/gcc-1.40/config/tm-apollo68.h new file mode 100644 index 0000000..cddfd07 --- /dev/null +++ b/gcc-1.40/config/tm-apollo68.h @@ -0,0 +1,177 @@ +/* Definitions of target machine for GNU compiler. Apollo 680X0 version. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-m68k.h" + +/* This symbol may be tested in other files for special Apollo handling */ + +#define TM_APOLLO + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +/* Target switches for the Apollo is the same as in tm-m68k.h, except + there is no Sun FPA. */ + +#undef TARGET_SWITCHES +#define TARGET_SWITCHES \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "68881", 2}, \ + { "bitfield", 4}, \ + { "68000", -5}, \ + { "c68000", -5}, \ + { "soft-float", -0102}, \ + { "nobitfield", -4}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "", TARGET_DEFAULT}} + +/* Define __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}\ +%{!ansi:%{m68000:-Dmc68010 }%{mc68000:-Dmc68010 }%{!mc68000:%{!m68000:-Dmc68020 }}\ +%{!ansi:-D_APOLLO_SOURCE}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{!ansi:%{m68000:-Dmc68010 }%{mc68000:-Dmc68010 }%{!mc68000:%{!m68000:-Dmc68020 }}\ +%{!ansi:-D_APOLLO_SOURCE}}" + +#endif + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Apollo, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dapollo -Daegis -Dunix" + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Allow #ident but output nothing for it. */ + +#define IDENT_DIRECTIVE +#define ASM_OUTPUT_IDENT(FILE, NAME) + +/* Allow dollarsigns in identifiers */ + +#define DOLLARS_IN_IDENTIFIERS 1 + +/* -m68000 requires special flags to the assembler. + The -C flag is passed to a modified GNU assembler to cause COFF + modules to be produced. Remove it if you're not using this. + (See vasta@apollo.com.) */ + +#define ASM_SPEC \ + "-C %{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* STARTFILE_SPEC + Note that includes knowledge of the default specs for gcc, ie. no + args translates to the same effect as -m68881 */ + +/* To get ANSI-conformant behavior, a special version of crt0.o must be used. + We use the -ansi switch to pick up that version. */ + +#define STARTFILE_SPEC \ + "%{ansi:/usr/apollo/lib/%{pg:gcrt0.o}%{!pg:%{p:mcrt0.o}%{!p:crt0.o}}}\ +%{!ansi:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}" + +/* Make sure ld sets the entry point to _start. + This is in LIB_SPEC rather than LINK_SPEC because it needs to + come after _start is defined, and to eliminate the default LIB_SPEC. */ +#define LIB_SPEC "-e _start" + +/* Debugging is not supported yet */ + +#undef DBX_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Functions which return large structures get the address + to place the wanted value at offset 8 from the frame. */ + +#undef PCC_STATIC_STRUCT_RETURN +#undef STRUCT_VALUE_REGNUM + +/* Caller treats address of return area like a parm. */ +#define STRUCT_VALUE 0 + +#define STRUCT_VALUE_INCOMING \ + gen_rtx (MEM, Pmode, \ + gen_rtx (PLUS, SImode, frame_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, 8))) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 + +/* Specify how to pad function arguments. + Arguments are not padded at all; the stack is kept aligned on long + boundaries. */ + +#define FUNCTION_ARG_PADDING(mode, size) none + +/* Short integral argument prototype promotion is not done */ + +#undef PROMOTE_PROTOTYPES + +/* The definition of this macro imposes a limit on the size of + an aggregate object which can be treated as if it were a scalar + object. */ + +#define MAX_FIXED_MODE_SIZE BITS_PER_WORD + +/* The definition of this macro implies that there are cases where + a scalar value cannot be returned in registers. + For Apollo, anything larger than one integer register is returned + using the structure-value mechanism, i.e. objects of DFmode are + returned that way. */ + +#define RETURN_IN_MEMORY(type) \ + (GET_MODE_SIZE (TYPE_MODE (type)) > UNITS_PER_WORD) + +/* This is how to output a reference to a user-level label named NAME. + In order to link to Apollo libraries, no underscore is prepended to names. + `assemble_name' uses this. */ + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + + diff --git a/gcc-1.40/config/tm-att386.h b/gcc-1.40/config/tm-att386.h new file mode 100644 index 0000000..c359166 --- /dev/null +++ b/gcc-1.40/config/tm-att386.h @@ -0,0 +1,244 @@ +/* Definitions for AT&T assembler syntax for the Intel 80386. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#define TARGET_VERSION fprintf (stderr, " (80386, ATT syntax)"); + +/* Define the syntax of instructions and addresses. */ + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +#ifdef __STDC__ +#define AS2(a,b,c) #a " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is L then CH is `l'). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX ".L" + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs ("$", (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs ("$", (FILE)) + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE "\t.byte " +#define ASM_SHORT "\t.value " +#define ASM_LONG "\t.long " +#define ASM_DOUBLE "\t.double " + +/* String containing the assembler's comment-starter. */ + +#define COMMENT_BEGIN "/" + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { sdbout_filename ((FILE), main_input_filename); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) + +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.optim\n") + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "/APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "/NO_APP\n" + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +/* The `space' pseudo in the text segment outputs nop insns rather than 0s, + so we must output 0s explicitly in the text segment. */ +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + if (in_text_section ()) \ + { \ + int i; \ + for (i = 0; i < (SIZE) - 20; i += 20) \ + fprintf (FILE, "\t.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); \ + if (i < (SIZE)) \ + { \ + fprintf (FILE, "\t.byte 0"); \ + i++; \ + for (; i < (SIZE); i++) \ + fprintf (FILE, ",0"); \ + fprintf (FILE, "\n"); \ + } \ + } \ + else \ + fprintf ((FILE), "\t.set .,.+%u\n", (SIZE)) + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Output before uninitialized data. */ + +#define BSS_SECTION_ASM_OP ".bss" + +#define EXTRA_SECTIONS in_bss + +#define EXTRA_SECTION_FUNCTIONS \ +void \ +bss_section () \ +{ \ + if (in_section != in_bss) \ + { \ + fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); \ + in_section = in_bss; \ + } \ +} + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This says how to output an assembler line + to define a global common symbol. */ +/* We don't use ROUNDED because the standard compiler doesn't, + and the linker gives error messages if a common symbol + has more than one length value. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +/* Note that using bss_section here caused errors + in building shared libraries on system V.3. */ +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + do { \ + int align = exact_log2 (ROUNDED); \ + if (align > 2) align = 2; \ + data_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED)); \ + } while (0) + +/* This is how to store into the string BUF + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + (fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* How to output an ASCII string constant. */ + +#define ASM_OUTPUT_ASCII(FILE, p, size) \ +{ int i=0; \ + while (i < size) \ + { if (i%10 == 0) { if (i!=0) fprintf (FILE, "\n"); \ + fprintf (FILE, ASM_BYTE); } \ + else fprintf (FILE, ","); \ + fprintf (FILE, "0x%x",(p[i++] & 0377)) ;} \ + fprintf (FILE, "\n"); } diff --git a/gcc-1.40/config/tm-bsd386.h b/gcc-1.40/config/tm-bsd386.h new file mode 100644 index 0000000..2bfc61d --- /dev/null +++ b/gcc-1.40/config/tm-bsd386.h @@ -0,0 +1,202 @@ +/* Definitions for BSD assembler syntax for Intel 386 + (actually AT&T syntax for insns and operands, + adapted to BSD conventions for symbol names and debugging.) + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Use the Sequent Symmetry assembler syntax. */ + +#define TARGET_VERSION fprintf (stderr, " (80386, BSD syntax)"); + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +#ifdef __STDC__ +#define AS2(a,b,c) #a " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is L then CH is `l'). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX "L" + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs ("$", (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs ("$", (FILE)) + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE "\t.byte " +#define ASM_SHORT "\t.word " +#define ASM_LONG "\t.long " +#define ASM_DOUBLE "\t.double " + +/* String containing the assembler's comment-starter. */ + +#define COMMENT_BEGIN "/" + +/* Output at beginning of assembler file. + ??? I am skeptical of this -- RMS. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "\t.file\t\"%s\"\n", dump_base_name); + +/* This was suggested, but it shouldn't be right for DBX output. -- RMS + #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) */ + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "/APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "/NO_APP\n" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", (LOG)) + +/* This is how to store into the string BUF + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + (fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) diff --git a/gcc-1.40/config/tm-compaq.h b/gcc-1.40/config/tm-compaq.h new file mode 100644 index 0000000..6aa7d5f --- /dev/null +++ b/gcc-1.40/config/tm-compaq.h @@ -0,0 +1,39 @@ +/* Definitions for Compaq as target machine. NOT TESTED! + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-i386.h" + +/* Use the ATT assembler syntax. */ + +#include "tm-att386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +#define ASM_SPEC "" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Di386 -Di80386 -Dunix" + + +#include "tm-i386.h" +#include "tm-att386.h" diff --git a/gcc-1.40/config/tm-conv1os7.h b/gcc-1.40/config/tm-conv1os7.h new file mode 100644 index 0000000..ec522dd --- /dev/null +++ b/gcc-1.40/config/tm-conv1os7.h @@ -0,0 +1,6 @@ +#include "tm-convex1.h" + +#undef LINK_SPEC +#undef STARTFILE_SPEC +#undef CPP_SPEC +#undef LIB_SPEC diff --git a/gcc-1.40/config/tm-conv2os7.h b/gcc-1.40/config/tm-conv2os7.h new file mode 100644 index 0000000..9735905 --- /dev/null +++ b/gcc-1.40/config/tm-conv2os7.h @@ -0,0 +1,6 @@ +#include "tm-convex2.h" + +#undef LINK_SPEC +#undef STARTFILE_SPEC +#undef CPP_SPEC +#undef LIB_SPEC diff --git a/gcc-1.40/config/tm-convex.h b/gcc-1.40/config/tm-convex.h new file mode 100644 index 0000000..71be483 --- /dev/null +++ b/gcc-1.40/config/tm-convex.h @@ -0,0 +1,1034 @@ +/* Definitions of target machine for GNU compiler. Convex version. + Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Use the proper incantation to search Posix-compliant libraries. */ + +#define LINK_SPEC \ +"%{!traditional:-Eposix}%{traditional:-Enoposix}\ + -A__iob=___ap$iob\ + -A_use_libc_sema=___ap$use_libc_sema\ + -L /usr/lib" + +/* Use the matching startup files. */ + +#define STARTFILE_SPEC \ +"%{pg:/usr/lib/crt/gcrt0.o}\ +%{!pg:%{p:/usr/lib/crt/mcrt0.o}\ +%{!p:/usr/lib/crt/crt0.o}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dconvex -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (convex)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* + -mc1 avoid C2-only instructions; default on C1 host + -mc2 use C2-only instructions; default on C2 host + -margcount use standard calling sequence, with arg count word + -mnoargcount don't push arg count (it's in the symbol table) (usually) +*/ + +#define TARGET_C1 (target_flags & 1) +#define TARGET_C2 (target_flags & 2) +#define TARGET_ARGCOUNT (target_flags & 4) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { { "c1", 1 }, \ + { "c2", 2 }, \ + { "noc1", -1 }, \ + { "noc2", -2 }, \ + { "argcount", 4 }, \ + { "noargcount", -4 }, \ + { "", TARGET_DEFAULT }} + +/* Default target_flags if no switches specified. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* Allow $ in identifiers */ + +#define DOLLARS_IN_IDENTIFIERS 1 + +/* Definitions for g++. */ + +/* Do not put out GNU stabs for constructors and destructors. + ld does not like them. */ + +#define FASCIST_ASSEMBLER + +/* Convex has negative addresses, so use positive numbers + to mean `vtable index'. */ + +#define VTABLE_USES_MASK +#define VINDEX_MAX ((unsigned) 0x80000000) + +/* Target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* Lie, so that gcc will take the low part of double reg N in reg N. */ +/* #define WORDS_BIG_ENDIAN */ + +/* Number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* No data type wants to be aligned rounder than this. */ +/* beware of doubles in structs -- 64 is incompatible with pcc */ +#define BIGGEST_ALIGNMENT 32 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +/* #define STRICT_ALIGNMENT */ + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ +#define FIRST_PSEUDO_REGISTER 16 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + For Convex, these are AP, FP, and SP. */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + On Convex, all values fit in one register. */ +#define HARD_REGNO_NREGS(REGNO, MODE) 1 + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On Convex, S registers can hold any type, A registers can any nonfloat */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 8 || ((MODE) != SFmode && (MODE) != DFmode && (MODE) != DImode)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == SFmode || (MODE1) == DFmode || (MODE1) == DImode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode || (MODE2) == DImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 8 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 15 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 14 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 0 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* Convex has classes A (address) and S (scalar). Seems to work + better to put S first, here and in the md. */ + +enum reg_class { NO_REGS, S_REGS, A_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "S_REGS", "A_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {0, 0x00ff, 0xff00, 0xffff} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + (S_REGNO_P (REGNO) ? S_REGS : A_REGS) + +#define S_REGNO_P(REGNO) ((REGNO) < 8) +#define A_REGNO_P(REGNO) ((REGNO) >= 8) + +#define S_REG_P(X) (REG_P (X) && S_REGNO_P (REGNO (X))) +#define A_REG_P(X) (REG_P (X) && A_REGNO_P (REGNO (X))) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS A_REGS +#define BASE_REG_CLASS A_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ +/* S regs use the letter 'd' because 's' is taken. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? A_REGS : (C) == 'd' ? S_REGS : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. */ + +/* Convex uses only I: + 32-bit value with sign bit off, usable as immediate in DImode logical + instructions and, or, xor */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) ((VALUE) >= 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ +/* Convex uses only G: + value usable in ld.d (low word 0) or ld.l (high word all sign) */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + (LD_D_P (VALUE) || LD_L_P (VALUE)) + +#define LD_D_P(X) (const_double_low_int (X) == 0) + +#define LD_L_P(X) (const_double_low_int (X) >= 0 \ + ? const_double_high_int (X) == 0 \ + : const_double_high_int (X) == -1) + +extern int const_double_low_int (); +extern int const_double_high_int (); +extern int const_double_float_int (); + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +#define CLASS_MAX_NREGS(CLASS, MODE) 1 + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Define this if should default to -fcaller-saves. */ + +#define DEFAULT_CALLER_SAVES + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +#define PUSH_ROUNDING(BYTES) (((BYTES) + 3) & ~3) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ +/* The standard Convex call, with arg count word, includes popping the + args as part of the call template. We optionally omit the arg count + word and let gcc combine the arg pops. */ +#define RETURN_POPS_ARGS(FUNTYPE) TARGET_ARGCOUNT + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On Convex the return value is in S0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On Convex the return value is in S0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the Convex, S0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* 1 if N is a possible register number for function argument passing. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the vax, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On Convex, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On Convex, all args are pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ if ((SIZE) != 0) fprintf (FILE, "\tsub.w #%d,sp\n", ((SIZE) + 3) & -4);} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tldea LP%d,a1\n\tcallq mcount\n", (LABELNO)); + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 1 + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. */ + +/* #define FUNCTION_EPILOGUE(FILE, SIZE) */ + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(regno) \ + ((((regno) ^ 010) < 8 || ((reg_renumber[regno] ^ 010) & -8) == 0) \ + && regno != 8) + +#define REGNO_OK_FOR_BASE_P(regno) REGNO_OK_FOR_INDEX_P (regno) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 1 + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +/* For convex, any single-word constant is ok; the only contexts + allowing general_operand of mode DI or DF are movdi and movdf. */ + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) != CONST_DOUBLE ? 1 : (LD_D_P (X) || LD_L_P (X))) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) (REGNO (X) > 8) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (REGNO (X) > 8) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + For Convex, valid addresses are + indirectable or (MEM indirectable) + where indirectable is + const, reg, (PLUS reg const) */ + +/* 1 if X is an address that we could indirect through. */ +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 0)))) + +/* Go to ADDR if X is a valid address. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_ADDRESS_P (xfoob)) goto ADDR; \ + xfoob = XEXP (X, 0); \ + if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \ + goto ADDR; \ + if (GET_CODE (X) == PRE_DEC && REG_P (xfoob) \ + && REGNO (xfoob) == STACK_POINTER_REGNUM) \ + goto ADDR; } + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For Convex, nothing needs to be done. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) {} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the case instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Define this if the case instruction drops through after the table + when the index is out of range. Don't define it if the case insn + jumps to the default label instead. */ +/* #define CASE_DROPS_THROUGH */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +#define FIXUNS_TRUNC_LIKE_FIX_TRUNC + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 8 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* On Convex, it is as good to call a constant function address as to + call an address kept in a register. */ +#define NO_FUNCTION_CSE + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + case CONST_INT: \ + return 0; \ + case CONST_DOUBLE: \ + return 2; + +/* Check a `double' value for validity for a particular machine mode. */ + +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = 1.7014117331926443e+38; } \ + else if ((d) < -1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = -1.7014117331926443e+38; } \ + else if (((d) > 0) && ((d) < 2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + else if (((d) < 0) && ((d) > -2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + } + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for convex. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP,INSN) {CC_STATUS_INIT;} + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, ";NO_APP\n") + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON ";APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF ";NO_APP\n" + +/* Alignment with Convex's assembler goes like this: + .text can be .aligned up to a halfword. + .data and .bss can be .aligned up to a longword. + .lcomm is not supported, explicit declarations in .bss must be used instead. + We get alignment for word and longword .text data by conventionally + using .text 2 for word-aligned data and .text 3 for longword-aligned + data. This requires that this data's size be a multiple of its alignment, + which seems to be always true. */ + +/* Boolean to keep track of whether the current section is .text or not. */ + +extern int current_section_is_text; + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP (current_section_is_text = 1, ".text") + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP (current_section_is_text = 0, ".data") + +/* Output before uninitialized data. */ + +#define BSS_SECTION_ASM_OP (current_section_is_text = 0, ".bss") + +#define EXTRA_SECTIONS in_bss + +#define EXTRA_SECTION_FUNCTIONS \ +void \ +bss_section () \ +{ \ + if (in_section != in_bss) \ + { \ + fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); \ + in_section = in_bss; \ + } \ +} + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if (current_section_is_text && (LOG) > 1) \ + fprintf (FILE, ".text %d\n", LOG); \ + else if (current_section_is_text) \ + fprintf (FILE, ".text\n.align %d\n", 1 << (LOG)); \ + else \ + fprintf (FILE, ".align %d\n", 1 << (LOG)) + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ + "sp", "a1", "a2", "a3", "a4", "a5", "ap", "fp"} + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* Put case tables in .text 2, where they will be word-aligned */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM) + +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ + ASM_OUTPUT_ALIGN (FILE, 1) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\tds.d %.17e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\tds.s %.9e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tds.w "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tds.h "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tds.b "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tds.b %#x\n", (VALUE)) + +/* This is how to output a string */ + +#define ASM_OUTPUT_ASCII(FILE,STR,SIZE) do { \ + int i; \ + fprintf (FILE, "\tds.b \""); \ + for (i = 0; i < (SIZE); i++) { \ + register int c = (STR)[i] & 0377; \ + if (c >= ' ' && c < 0177 && c != '\\' && c != '"') \ + putc (c, FILE); \ + else \ + fprintf (FILE, "\\%03o", c);} \ + fprintf (FILE, "\"\n");} while (0) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpsh.%c %s\n", \ + S_REGNO_P (REGNO) ? 'l' : 'w', \ + reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tpop.%c %s\n", \ + S_REGNO_P (REGNO) ? 'l' : 'w', \ + reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tds.w L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (not used on Convex) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tds.w L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tds.b %u(0)\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( bss_section (), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ":\tbs.b %u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#%.9e", u.d); } \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +/* Print a memory operand whose address is X, on file FILE. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ \ + register rtx addr = ADDR; \ + register rtx index = 0; \ + register rtx offset = 0; \ + \ + if (GET_CODE (addr) == MEM) \ + { \ + fprintf (FILE, "@"); \ + addr = XEXP (addr, 0); \ + } \ + \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + index = addr; \ + break; \ + \ + case PLUS: \ + index = XEXP (addr, 0); \ + if (REG_P (index)) \ + offset = XEXP (addr, 1); \ + else \ + { \ + offset = XEXP (addr, 0); \ + index = XEXP (addr, 1); \ + if (! REG_P (index)) abort (); \ + } \ + break; \ + \ + default: \ + offset = addr; \ + break; \ + } \ + \ + if (offset) \ + output_addr_const (FILE, offset); \ + \ + if (index) \ + fprintf (FILE, "(%s)", reg_names[REGNO (index)]); \ +} + + diff --git a/gcc-1.40/config/tm-convex1.h b/gcc-1.40/config/tm-convex1.h new file mode 100644 index 0000000..573af46 --- /dev/null +++ b/gcc-1.40/config/tm-convex1.h @@ -0,0 +1,24 @@ +/* tm.h file for a Convex C1. */ + +#include "tm-convex.h" + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 1 + +#define CC1_SPEC "%{mc2:-mnoc1}" + +/* Include Posix prototypes unless -traditional. */ + +#define CPP_SPEC \ +"%{mc2:-D__convex_c2__}%{!mc2:-D__convex_c1__}\ + -D__NO_INLINE_MATH\ + %{!traditional:-D__stdc__ -D_POSIX_SOURCE -D_CONVEX_SOURCE}" + +/* Search Posix or else backward-compatible libraries depending + on -traditional. */ + +#define LIB_SPEC \ +"%{mc2:-lC2}%{!mc2:-lC1}\ + %{!p:%{!pg:%{traditional:-lc_old}%{!traditional:-lc}}}\ +%{p:%{traditional:-lc_old_p}%{!traditional:-lc_p}}\ +%{pg:%{traditional:-lc_old_p}%{!traditional:-lc_p}}" diff --git a/gcc-1.40/config/tm-convex2.h b/gcc-1.40/config/tm-convex2.h new file mode 100644 index 0000000..4e0307b --- /dev/null +++ b/gcc-1.40/config/tm-convex2.h @@ -0,0 +1,24 @@ +/* tm.h file for a Convex C2. */ + +#include "tm-convex.h" + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 2 + +#define CC1_SPEC "%{mc1:-mnoc2}" + +/* Include Posix prototypes unless -traditional. */ + +#define CPP_SPEC \ +"%{mc1:-D__convex_c1__}%{!mc1:-D__convex_c2__}\ + -D__NO_INLINE_MATH\ + %{!traditional:-D__stdc__ -D_POSIX_SOURCE -D_CONVEX_SOURCE}" + +/* Search Posix or else backward-compatible libraries depending + on -traditional. */ + +#define LIB_SPEC \ +"%{mc1:-lC1}%{!mc1:-lC2}\ + %{!p:%{!pg:%{traditional:-lc_old}%{!traditional:-lc}}}\ +%{p:%{traditional:-lc_old_p}%{!traditional:-lc_p}}\ +%{pg:%{traditional:-lc_old_p}%{!traditional:-lc_p}}" diff --git a/gcc-1.40/config/tm-decstatn.h b/gcc-1.40/config/tm-decstatn.h new file mode 100644 index 0000000..93fb270 --- /dev/null +++ b/gcc-1.40/config/tm-decstatn.h @@ -0,0 +1,27 @@ +/* Definitions of target machine for GNU compiler. DECstation (ultrix) version. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define DECSTATION + +#include "tm-mips.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__ANSI_COMPAT \ +-D__LANGUAGE_C -D__MIPSEL -D__R3000 -D__SYSTYPE_BSD -D__bsd4_2 -D__host_mips -D__mips -D__ultrix -D__unix \ +-DLANGUAGE_C -DMIPSEL -DR3000 -DSYSTYPE_BSD -Dbsd4_2 -Dhost_mips -Dmips -Dultrix -Dunix" diff --git a/gcc-1.40/config/tm-delta68k.h b/gcc-1.40/config/tm-delta68k.h new file mode 100644 index 0000000..71c45de --- /dev/null +++ b/gcc-1.40/config/tm-delta68k.h @@ -0,0 +1,486 @@ +/* Definitions of target machine for GNU compiler. + Motorola Delta version of 680x0 for x>1 + copied and modified from 3b1 version by + Daniel R. Bidwell (bidwell@andrews.edu). + + AT&T UNIX PC version (pc7300, 3b1) + + Written by Alex Crain + bug reports to alex@umbc3.umd.edu + + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define SGS_3B1 + +#include "tm-hp9k320.h" + +/* See tm-m68k.h. 0 means 680[01]0 with no 68881. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 7 + +/* -m68020 requires special flags to the assembler. */ + +#undef ASM_SPEC +#define ASM_SPEC "%{m68020:-68020}" + +/* we use /lib/libp/lib* when profiling */ + +#undef LIB_SPEC +#define LIB_SPEC "%{!shlib:%{p:-L/lib/libp} %{pg:-L/lib/libp} -lc}" + +/* shared libraries need to use crt0s.o */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} " + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +/* Don't try to define `gcc_compiled.' since the assembler might not + accept symbols with periods and GDB doesn't run on this machine anyway. */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* ihnp4!lmayk!lgm@eddie.mit.edu says mc68000 and m68k should not be here. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dm68k -Dmc68k -Dunix -Dunixpc" + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ + +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* Override parts of tm-m68k.h to fit the SGS-3b1 assembler. */ + +#undef TARGET_VERSION +#undef ASM_FORMAT_PRIVATE_NAME +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_FLOAT_OPERAND +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SOURCE_FILENAME +#undef ASM_OUTPUT_SOURCE_LINE +#undef PRINT_OPERAND_ADDRESS +#undef ASM_GENERATE_INTERNAL_LABEL +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_OPCODE +#undef ASM_OUTPUT_LOCAL +#undef ASM_OUTPUT_LABELREF +#undef ASM_OUTPUT_ASCII +#undef LEGITIMATE_CONSTANT_P +#undef ASM_RETURN_CASE_JUMP + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T unixpc syntax)"); + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \ + sprintf ((OUTPUT), "%s_%%%d", (NAME), (LABELNO))) + +/* The unixpc doesn't know about double's and float's */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long l[2]; } tem; \ + tem.d = (VALUE); \ + fprintf(FILE, "\tlong 0x%x,0x%x\n", tem.l[0], tem.l[1]); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\tlong 0x%x\n", tem.l); \ + } while (0) +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0x%.8x", (VALUE)) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +/* The `space' pseudo in the text segment outputs nop insns rather than 0s, + so we must output 0s explicitly in the text segment. */ +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + if (in_text_section ()) \ + { \ + int i; \ + for (i = 0; i < (SIZE) - 20; i += 20) \ + fprintf (FILE, "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); \ + if (i < (SIZE)) \ + { \ + fprintf (FILE, "\tbyte 0"); \ + i++; \ + for (; i < (SIZE); i++) \ + fprintf (FILE, ",0"); \ + fprintf (FILE, "\n"); \ + } \ + } \ + else \ + fprintf (FILE, "\tspace %d\n", (SIZE)) + +/* The beginnings of sdb support... */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + fprintf (FILE, "\tfile\t\"%s\"\n", FILENAME) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* Yet another null terminated string format. */ + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + { register int sp = 0, lp = 0; \ + fprintf (FILE, "\tbyte\t"); \ + loop: \ + if (PTR[sp] > ' ' && ! (PTR[sp] & 0x80) && PTR[sp] != '\\') \ + { lp += 3; \ + fprintf (FILE, "'%c", PTR[sp]); } \ + else \ + { lp += 5; \ + fprintf (FILE, "0x%x", PTR[sp]); } \ + if (++sp < LEN) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf (FILE, "\n%s ", ASCII_DATA_ASM_OP); } \ + else \ + putc (',', FILE); \ + goto loop; } \ + putc ('\n', FILE); } + +/* Note that in the case of the movhi which fetches an element of + an ADDR_DIFF_VEC the offset output is too large by 2. + This is because the 3b1 assembler refuses to subtract 2. + ASM_OUTPUT_CASE_LABEL, below, compensates for this. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(L%%%d,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(L%%%d,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + fprintf (FILE, ")"); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%%%d,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%%%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%%%d:\n", PREFIX, NUM) + +/* Must put address in %a0 , not %d0 . -- LGM, 7/15/88 */ +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +/* ihnp4!lmayk!lgm says that `short 0' triggers assembler bug; + `short L%nn-L%nn' supposedly works. */ +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); + +/* At end of a switch table, define LD%n iff the symbol LI%n was defined. */ +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ + if (RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tset LD%%%d,L%%%d-LI%%%d\n", (NUM), (NUM), (NUM)) + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbgl"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbeq", 4)) \ + { fprintf ((FILE), "fbngl"); (PTR) += 4; } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' || \ + (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'm') (PTR)++; } \ +} + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", (ROUNDED))) + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_DIM(a) fprintf(asm_out_file, "\tdim\t%d;", a) + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +#define LEGITIMATE_CONSTANT_P(X) (GET_CODE(X)==CONST_DOUBLE?0:1) + +#define ASM_RETURN_CASE_JUMP return "jmp (%0.w,%a1)" + diff --git a/gcc-1.40/config/tm-encore.h b/gcc-1.40/config/tm-encore.h new file mode 100644 index 0000000..cdf326c --- /dev/null +++ b/gcc-1.40/config/tm-encore.h @@ -0,0 +1,202 @@ +/* Definitions of target machine for GNU compiler. ENCORE NS32000 version. + Copyright (C) 1988 Free Software Foundation, Inc. + Adapted by Robert Brown (brown@harvard.harvard.edu) from the Sequent + version by Michael Tiemann (tiemann@mcc.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + * Looks like all multiprocessors have this bug! + */ + +#define SEQUENT_ADDRESS_BUG 1 + +#include "tm-ns32k.h" + +#define SDB_DEBUGGING_INFO +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Cause long-jump assembler to be used, + since otherwise some files fail to be assembled right. */ +#define ASM_SPEC "-j" + +#undef ASM_FILE_START +#undef ASM_GENERATE_INTERNAL_LABEL +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_ASCII +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_LOCAL +#undef CPP_PREDEFINES +#undef FUNCTION_BOUNDARY +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#undef TARGET_VERSION +#undef FUNCTION_PROFILER + + +#define TARGET_DEFAULT 1 +#define TARGET_VERSION fprintf (stderr, " (32000, Encore syntax)"); +/* Note Encore does not standardly do -Dencore. */ +/* budd: should have a -ns32332 (or -apc) switch! but no harm for now */ +#define CPP_PREDEFINES "-Dns32000 -Dn16 -Dns16000 -Dns32332 -Dunix" + +/* Ignore certain cpp directives used in header files on sysV. */ +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* The .file command should always begin the output. */ +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +#define FUNCTION_BOUNDARY 128 /* speed optimization */ + +/* + * The Encore assembler uses ".align 2" to align on 2-byte boundaries. + */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", 1 << (LOG)) + +/* + * Internal labels are prefixed with a period. + */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*.%s%d", PREFIX, NUM) +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word .L%d-.LI%d\n", VALUE, REL) + +/* + * Different syntax for integer constants, double constants, and + * uninitialized locals. + */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.double "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.long 0f%.20e\n", (VALUE)) + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.bss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,%u\n", (SIZE), (ROUNDED))) + + /* + * Encore assembler can't handle huge string constants like the one in + * gcc.c. If the default routine in varasm.c were more conservative, this + * code could be eliminated. It starts a new .ascii directive every 40 + * characters. + */ + +#define ASM_OUTPUT_ASCII(file, p, size) \ +{ \ + for (i = 0; i < size; i++) \ + { \ + register int c = p[i]; \ + if ((i / 40) * 40 == i) \ + if (i == 0) \ + fprintf (file, "\t.ascii \""); \ + else \ + fprintf (file, "\"\n\t.ascii \""); \ + if (c == '\"' || c == '\\') \ + putc ('\\', file); \ + if (c >= ' ' && c < 0177) \ + putc (c, file); \ + else \ + { \ + fprintf (file, "\\%o", c); \ + if (i < size - 1 \ + && p[i + 1] >= '0' && p[i + 1] <= '9') \ + fprintf (file, "\"\n\t.ascii \""); \ + } \ + } \ + fprintf (file, "\"\n"); \ +} + + /* + * Dollar signs are required before immediate operands, double + * floating point constants use $0f syntax, and external addresses + * should be prefixed with a question mark to avoid assembler warnings + * about undefined symbols. + */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') putc ('$', FILE); \ + else if (CODE == '?') fputc ('?', FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + fprintf (FILE, "0("); \ + output_address (xfoo); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else if (GET_CODE (X) == CONST) \ + output_addr_const (FILE, X); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\taddr .LP%d,r0\n\tjsr mcount\n", (LABELNO)) diff --git a/gcc-1.40/config/tm-genix.h b/gcc-1.40/config/tm-genix.h new file mode 100644 index 0000000..db4682e --- /dev/null +++ b/gcc-1.40/config/tm-genix.h @@ -0,0 +1,163 @@ +/* Definitions of target machine for GNU compiler. Genix ns32000 version. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-encore.h" + +/* We don't want the one Encore needs. */ +#undef ASM_SPEC + +/* The following defines override ones in tm-ns32k.h and prevent any attempts + to explicitly or implicitly make references to the SB register in the GCC + generated code. It is necessary to avoid such references under Genix V.3.1 + because this OS doesn't even save/restore the SB on context switches! */ + +#define IS_OK_REG_FOR_BASE_P(X) \ + ( (GET_CODE (X) == REG) && REG_OK_FOR_BASE_P (X) ) + +#undef INDIRECTABLE_1_ADDRESS_P +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_NO_LABEL_P (X) \ + || IS_OK_REG_FOR_BASE_P (X) \ + || (GET_CODE (X) == PLUS \ + && IS_OK_REG_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)) ) ) + +/* Note that for double indirects, only FP, SP, and SB are allowed + as the inner-most base register. But we are avoiding use of SB. */ + +#undef MEM_REG +#define MEM_REG(X) \ + ( (GET_CODE (X) == REG) \ + && ( (REGNO (X) == FRAME_POINTER_REGNUM) \ + || (REGNO (X) == STACK_POINTER_REGNUM) ) ) + +#undef INDIRECTABLE_2_ADDRESS_P +#define INDIRECTABLE_2_ADDRESS_P(X) \ + (GET_CODE (X) == MEM \ + && (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \ + || (GET_CODE (xfoo0) == PLUS \ + && MEM_REG (XEXP (xfoo0, 0)) \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \ + || CONSTANT_ADDRESS_NO_LABEL_P (xfoo0))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#undef GO_IF_NONINDEXED_ADDRESS +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_1_ADDRESS_P(X)) goto ADDR; \ + if (CONSTANT_P(X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \ + if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \ + goto ADDR; \ +} + +/* A bug in the GNX 3.X assembler causes references to external symbols to + be mishandled if the symbol is also used as the name of a function-local + variable or as the name of a struct or union field. The problem only + appears when you are also using the -g option so that SDB debugging + directives are also being produced by GCC. In such cases, the assembler + gets the external entity confused with the local entity and addressing + havoc ensues. The solution is to get GCC to produce .global directives + for all external entities which are actually referenced within the current + source file. The following macro does this. */ + +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + ASM_GLOBALIZE_LABEL(FILE,NAME); + +/* Genix wants 0l instead of 0f. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.long 0l%.20e\n", (VALUE)) + +/* A bug in the GNX 3.X linker prevents symbol-table entries with a storage- + class field of C_EFCN (-1) from being accepted. */ + +#ifdef PUT_SDB_EPILOGUE_END +#undef PUT_SDB_EPILOGUE_END +#endif +#define PUT_SDB_EPILOGUE_END(NAME) + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, National syntax)"); + +/* Same as the tm-encore definition except + * Different syntax for double constants. + * Don't output `?' before external regs. + * Output `(sb)' in certain indirect refs. */ + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') putc ('$', FILE); \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + extern int paren_base_reg_printed; \ + fprintf (FILE, "0("); \ + paren_base_reg_printed = 0; \ + output_address (xfoo); \ + if (!paren_base_reg_printed) \ + fprintf (FILE, "(sb)"); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0l%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else if (GET_CODE (X) == CONST) \ + output_addr_const (FILE, X); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} diff --git a/gcc-1.40/config/tm-harris.h b/gcc-1.40/config/tm-harris.h new file mode 100644 index 0000000..a06f001 --- /dev/null +++ b/gcc-1.40/config/tm-harris.h @@ -0,0 +1,96 @@ +/* Definitions of target machine for GNU compiler. Harris tahoe version. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-tahoe.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dtahoe -Dunix -Dhcx" + +#undef DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 1 + +/* urem and udiv don't exist on this system. */ +#undef UDIVSI3_LIBCALL +#undef UMODSI3_LIBCALL + +/* start the assembly by turning off APP. For the Harris (if not, + apparently, for the Tahoe) we want a .file directive as well. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + int len = strlen (dump_base_name); \ + char *na = dump_base_name + len; \ + /* NA gets DUMP_BASE_NAME sans directory names. */ \ + while (na > dump_base_name) \ + { \ + if (na[-1] == '/') \ + break; \ + na--; \ + } \ + fprintf (FILE, "#NO_APP\n\n"); \ + fprintf (FILE, "\t.file\t\"%s\"\n", na); \ + } while (0) + +/* Operand of .align is not logarithmic. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + LOG ? fprintf (FILE, "\t.align %d\n", 1 << (LOG)) : 0 + +/* For the same reason, we need .align 2 after casesi. */ +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '@') \ + putc ('2', FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".bss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,4\n", (ROUNDED))) + +#define ASM_OUTPUT_ASCII(FILE, PTR, SIZE) \ +{ \ + unsigned char *_p = (PTR); \ + int _thissize = (SIZE); \ + fprintf ((FILE), "\t.ascii \""); \ + for (i = 0; i < _thissize; i++) \ + { \ + register int c = _p[i]; \ + if (c >= ' ' && c < 0177 && c != '\"' && c != '\\') \ + putc (c, (FILE)); \ + else \ + { \ + fprintf ((FILE), "\\%o", c); \ + if (i < _thissize - 1 \ + && _p[i + 1] >= '0' && _p[i + 1] <= '9') \ + fprintf ((FILE), "\"\n\t.ascii \""); \ + } \ + } \ + fprintf ((FILE), "\"\n"); \ +} diff --git a/gcc-1.40/config/tm-hp9k2bsd.h b/gcc-1.40/config/tm-hp9k2bsd.h new file mode 100644 index 0000000..3793e52 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k2bsd.h @@ -0,0 +1,53 @@ +/* Definitions of target machine for GNU compiler. HP 9000/200 68000 version. + Copyright (C) 1987 - 1991 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-m68k.h" + +/* See tm-m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT -0102 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68010 -Dhp200 -Dunix" + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO diff --git a/gcc-1.40/config/tm-hp9k310.h b/gcc-1.40/config/tm-hp9k310.h new file mode 100644 index 0000000..806aed5 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k310.h @@ -0,0 +1,32 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68010 version. */ + +/* See tm-m68k.h. 0 means 68000 without 68881 and no bitfields. */ +#define TARGET_DEFAULT 0 + +#include "tm-hp9k320.h" + +#undef CPP_SPEC +#undef ASM_SPEC + +/* HP does not support a 68020 without a 68881 or a 68010 with a 68881. + However, -m68020 does not imply -m68881. You must specify both + if you want both. */ + +#ifdef HPUX_ASM + +#define CPP_SPEC "-D__HPUX_ASM__ %{m68881: -D__HAVE_68881__}\ +%{m68020: -Dmc68020}%{mc68020: -Dmc68020}\ +%{!traditional:-D_INCLUDE__STDC__}" + +#define ASM_SPEC "%{!m68020:%{!mc68020:+X}}" + +#else /* not HPUX_ASM */ + +#define CPP_SPEC "%{m68881: -D__HAVE_68881__}\ +%{m68020: -Dmc68020}%{mc68020: -Dmc68020}\ +%{!traditional:-D_INCLUDE__STDC__}" + +#define ASM_SPEC \ + "%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" + +#endif /* not HPUX_ASM */ diff --git a/gcc-1.40/config/tm-hp9k310g.h b/gcc-1.40/config/tm-hp9k310g.h new file mode 100644 index 0000000..d1e982b --- /dev/null +++ b/gcc-1.40/config/tm-hp9k310g.h @@ -0,0 +1,12 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Use this file if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) */ + +/* This wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#define USE_GAS + +#include "tm-hp9k310.h" diff --git a/gcc-1.40/config/tm-hp9k320.h b/gcc-1.40/config/tm-hp9k320.h new file mode 100644 index 0000000..4991007 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k320.h @@ -0,0 +1,598 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Define USE_GAS if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) + Undefine USE_GAS if you want GCC to feed the HP assembler. */ + +/* #define USE_GAS */ /* Use tm-hp9k320g.h if you want this. */ + +/* Control assembler-syntax conditionals in m68k.md. */ + +#ifndef USE_GAS +#define MOTOROLA +#define SGS +#define HPUX_ASM +#endif + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +/* For version 6.2 of HP-UX (or earlier), remove the "-V 3" from + ASM_SPEC below. */ + +#ifdef HPUX_ASM + +/* "-V 3" says that setjmp and longjmp need to save the fpu regs. */ + +#define ASM_SPEC "%{m68000:+X} -V 3" + +#if TARGET_DEFAULT & 02 /* -m68881 is the default */ + +/* These definitions differ from those used for GAS by defining __HPUX_ASM__. + This is needed because some programs, particularly GDB, need to + know which assembler is being used so that the correct `asm' + instructions can be used. */ + +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}} -D__HPUX_ASM__\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#else /* default is -msoft-float */ + +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}} -D__HPUX_ASM__\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#endif /* default is -msoft-float */ + +#else /* not HPUX_ASM */ + +#if TARGET_DEFAULT & 02 /* -m68881 is the default */ + +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}}\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#else /* default is -msoft-float */ + +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}}\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#endif /* default is -msoft-float */ + + +/* -m68000 requires special flags to the assembler. */ +#define ASM_SPEC \ + "%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" + +/* special directory for gnu libs on hp-ux system */ +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/local/lib/gnu/" + +#endif /* Not HPUX_ASM */ + +/* Names to predefine in the preprocessor for this target machine + (for non-strict-ANSI programs only). */ +/* These are the ones defined by HPUX cc, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dhp9000s200 -Dhp9000s300 -DPWB -Dhpux -Dunix" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* hpux doesn't use static area for struct returns. */ +#undef PCC_STATIC_STRUCT_RETURN + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* Function calls do save some fp registers on hpux version 7. */ + +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0} + +#ifdef HPUX_ASM + +/* Override parts of tm-m68k.h to fit the HPUX assembler. */ + +#undef TARGET_VERSION +#undef REGISTER_NAMES +#undef FUNCTION_PROLOGUE +#undef FUNCTION_EPILOGUE +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_FILE_START +#undef ASM_APP_ON +#undef ASM_APP_OFF +#undef TEXT_SECTION_ASM_OP +#undef DATA_SECTION_ASM_OP +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_SHORT +#undef ASM_OUTPUT_CHAR +#undef ASM_OUTPUT_BYTE +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SKIP +#undef ASM_OUTPUT_COMMON +#undef ASM_OUTPUT_LOCAL +#undef ASM_FORMAT_PRIVATE_NAME +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#undef FUNCTION_PROFILER +#undef ASM_GLOBALIZE_LABEL +#undef ASM_OUTPUT_INTERNAL_LABEL + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/hpux syntax)"); + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7"} + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = (SIZE); \ + if (frame_pointer_needed) \ + { if (fsize < 0x8000) \ + fprintf (FILE, "\tlink.w %%a6,&%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf (FILE, "\tlink.l %%a6,&%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink.w %%a6,&0\n\tsub.l &%d,%%sp\n", fsize); } \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if (mask != 0) \ + fprintf (FILE, "\tfmovem &0x%x,-(%%sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovm.l &0x%x,-(%%sp)\n", mask); } + +#define PROFILE_BEFORE_PROLOGUE + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%d,%%a0\n\tjsr mcount\n", (LABEL_NO)); + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + int fsize = (SIZE); \ + int big = 0; \ + nregs = 0; fmask = 0; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 && frame_pointer_needed) \ + { fprintf (FILE, "\tmov.l &%d,%%a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmov.l -%d(%%a6,%%a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmov.l -%d(%%a6),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovm.l -%d(%%a6,%%a0.l),&0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovm.l (%%sp)+,&0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovm.l -%d(%%a6),&0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem -%d(%%a6,%%a0.l),&0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem (%%sp)+,&0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem -%d(%%a6),&0x%x\n", \ + foffset + fsize, fmask); } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk %%a6\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd &%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +#define ASM_FILE_START(FILE) + +#define ASM_APP_ON "" + +#define ASM_APP_OFF "" + +#define TEXT_SECTION_ASM_OP "text" + +#define DATA_SECTION_ASM_OP "data" + +#define ASCII_DATA_ASM_OP "\tbyte" + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,2\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \ + sprintf ((OUTPUT), "%s___%d", (NAME), (LABELNO))) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs ("\tglobal ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ +do{ if (PREFIX[0] == 'L' && PREFIX[1] == 'I') \ + fprintf(FILE, "\tset %s%d,.+2\n", PREFIX, NUM); \ + else \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM); \ +} while(0) + +#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \ + fprintf (FILE, "\tdouble 0f%.20g\n", (VALUE)) + +#define ASM_OUTPUT_FLOAT(FILE, VALUE) \ + fprintf (FILE, "\tfloat 0f%.9g\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tlong "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tshort "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tbyte 0x%x\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%d\n", VALUE) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%d-L%d\n", VALUE, REL) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\tlalign 2\n"); \ + else if ((LOG) != 0) \ + abort (); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "&"); \ + else if (CODE == '-') fprintf (FILE, "-(%%sp)"); \ + else if (CODE == '+') fprintf (FILE, "(%%sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(%%sp)"); \ + else if (CODE == '!') fprintf (FILE, "%%cc"); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "&0f%.9g", u1.f); \ + else \ + fprintf (FILE, "&0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "&0f%.20g", u.d); } \ + else { putc ('&', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "L%d-LI%d(%%pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "L%d-LI%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%d-LI%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_OUTPUT_ASCII(f, p, size) \ +{ register int i; \ + int inside; \ + inside = FALSE; \ + for (i = 0; i < size; i++) { \ + if (i % 8 == 0) { \ + if (i != 0) { \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ + inside = FALSE; \ + } \ + fprintf(f, "%s ", ASCII_DATA_ASM_OP); \ + } \ + if (p[i] < 32 || p[i] == '\\' || p[i] == '"' || p[i] == 127) { \ + if (inside) { \ + putc('"', f); \ + inside = FALSE; \ + } \ + if (i % 8 != 0) \ + putc(',', f); \ + fprintf(f, "%d", p[i]); \ + } else { \ + if (!inside) { \ + if (i % 8 != 0) \ + putc(',', f); \ + putc('"', f); \ + inside = TRUE; \ + } \ + putc(p[i], f); \ + } \ + } \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ +} + +/* Translate Motorola opcodes such as `jbeq' + into SGS opcodes such as `beq.w'. + Delete the `e' in `move...' and `fmove'. + Change `ftst' to `ftest'. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + } \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; } \ +} + +/* Prevent output of `gcc_compiled.:'. */ + +#define ASM_IDENTIFY_GCC(FILE) + +#endif /* HPUX_ASM */ diff --git a/gcc-1.40/config/tm-hp9k320g.h b/gcc-1.40/config/tm-hp9k320g.h new file mode 100644 index 0000000..32ac30a --- /dev/null +++ b/gcc-1.40/config/tm-hp9k320g.h @@ -0,0 +1,12 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Use this file if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) */ + +/* This wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#define USE_GAS + +#include "tm-hp9k320.h" diff --git a/gcc-1.40/config/tm-hp9k3bsd.h b/gcc-1.40/config/tm-hp9k3bsd.h new file mode 100644 index 0000000..b4e5442 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k3bsd.h @@ -0,0 +1,36 @@ +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT 7 + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_FPU__ -D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68020 -Dhp300 -Dhp9000 -Dunix" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS diff --git a/gcc-1.40/config/tm-i386.h b/gcc-1.40/config/tm-i386.h new file mode 100644 index 0000000..34d6c2c --- /dev/null +++ b/gcc-1.40/config/tm-i386.h @@ -0,0 +1,1088 @@ +/* Definitions of target machine for GNU compiler for Intel 80386. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +/* the file tm-compaq.h includes this file */ + + +#define I386 1 + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile 80387 insns for floating point (not library calls). */ +#define TARGET_80387 (target_flags & 1) +/* Compile using ret insn that pops args. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 8) +/* Compile passing first two args in regs 0 and 1. + This exists only to test compiler features that will + be needed for RISC chips. It is not usable + and is not intended to be usable on this cpu. */ +#define TARGET_REGPARM (target_flags & 020) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { { "80387", 1}, \ + { "soft-float", -1}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "regparm", 020}, \ + { "noregparm", -020}, \ + { "", TARGET_DEFAULT}} + +/* TARGET_DEFAULT is defined in tm-compaq.h, etc. */ + +/* target machine storage layout */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 80386. */ + +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the 80386. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* Not true for 80386 */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 80386, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ + +#define EMPTY_FIELD_BOUNDARY 32 + +/* There is no point aligning anything to a rounder boundary than this. */ +/* Some structures in the ATT libraries are assumed to round up from 16 to 18 + bytes, for example the _io_buf */ +#define BIGGEST_ALIGNMENT 32 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +/* #define STRICT_ALIGNMENT */ + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + In the 80387 we give the 8 general purpose registers the numbers 0-7, + we assign 6 numbers for floating point registers 8-13, + Note that registers 0-7 can be accessed as a short or int, + while only 0-3 may be used with mov byte instructions. +*/ +#define FIRST_PSEUDO_REGISTER 10 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 80386, only the stack pointer is such. */ +#define FIXED_REGISTERS \ +/*ax,ad,ac,ab,si,di,bp,sp,fval,fp0*/ \ +{ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0} + +/* ;;change-wfs */ + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ + +#define CALL_USED_REGISTERS \ +/*ax,ad,ac,ab,si,di,bp,sp,*/ \ +{ 1, 1, 1, 0, 0, 0, 0, 1, \ + 1, 1} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + Actually there are no two word move instructions for consecutive + registers. And only registers 0-3 may have mov byte instructions + applied to them. + */ + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 8 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 80386, the first 4 cpu registers can hold any mode. + While the floating point registers may hold SFmode or DFmode only. + */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + hard_regno_mode_ok(REGNO,MODE) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ + +#define MODES_TIEABLE_P(MODE1, MODE2) ((MODE1) == (MODE2)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* on the 386 the pc register is %eip, and is not usable as a general + register. The ordinary mov instructions won't work */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 7 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 6 + +/* First floating point reg */ +#define FIRST_FLOAT_REG 8 +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 6 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 2 + +/* Register in which address to store a structure value + arrives in the function. On the 386, the prologue + copies this from the stack to register %eax. */ +#define STRUCT_VALUE_INCOMING \ + gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, frame_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, 8))) + +/* Place in which caller passes the structure value address. + Actually, all that matters about this value is it its rtx_code: + MEM means push the value on the stack like an argument. */ +#define STRUCT_VALUE \ + gen_rtx (MEM, Pmode, gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx)) + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + + +enum reg_class { + NO_REGS, AREG, DREG, ADREG, CREG, BREG, Q_REGS, SIREG, DIREG, + INDEX_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ +{ "NO_REGS", "AREG", "DREG", "ADREG", "CREG", "BREG","Q_REGS", \ + "SIREG", "DIREG", \ + "INDEX_REGS", "GENERAL_REGS", "FLOAT_REGS", "ALL_REGS"} +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + + + +#define REG_CLASS_CONTENTS {0, 0x1, 0x2, 0x3, 0x4, 0x8, 0xf,\ + 0x10, 0x20, 0x7f, 0xff, 0x300, 0x3ff} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == 0 ? AREG : \ + (REGNO) == 1 ? DREG : \ + (REGNO) == 2 ? CREG : \ + (REGNO) == 3 ? BREG : \ + (REGNO) == 4 ? SIREG : \ + (REGNO) == 5 ? DIREG : \ + (REGNO) == 7 ? GENERAL_REGS : \ + (REGNO) < 8 ? INDEX_REGS : \ + FLOAT_REGS) + +#define NON_QI_REG_P(X) \ + (REG_P (X) && REGNO (X) >= 4 && REGNO (X) < FIRST_PSEUDO_REGISTER) + +#define FP_REG_P(X) (REG_P (X) && FP_REGNO_P (REGNO (X))) +#define FP_REGNO_P(n) ((n) >= FIRST_FLOAT_REG && (n) < FIRST_PSEUDO_REGISTER) + +/* This definition indicates that some register classes are very small, + which requires extra care in certain optimizations. */ + +#define SMALL_REGISTER_CLASSES + +/* Try to maintain the accuracy of the death notes for regs satisfying the + following. Important for stack like regs, to know when to pop. */ + +#define PRESERVE_DEATH_INFO_REGNO_P(x) FP_REGNO_P(x) + +/* 1 if register REGNO can magically overlap other regs. + Note that nonzero values work only in very special circumstances. + We return 1 for an FP reg because "both" our FP regs + are really the same reg. */ + +#define OVERLAPPING_REGNO_P(REGNO) FP_REGNO_P (REGNO) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS INDEX_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'r' ? GENERAL_REGS : \ + (C) == 'q' ? Q_REGS : \ + (C) == 'f' ? FLOAT_REGS : \ + (C) == 'a' ? AREG : (C) == 'b' ? BREG : \ + (C) == 'c' ? CREG : (C) == 'd' ? DREG : \ + (C) == 'A' ? ADREG : \ + (C) == 'S' ? SIREG : \ + (C) == 'D' ? DIREG : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + I is for the maximum shifts. + */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 :0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? ! (TARGET_80387 && standard_80387_constant_p (VALUE)) : 1) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. + On the 80386 series, we prevent floating constants from being + reloaded into floating registers (since no move-insn can do that) + and we ensure that QImodes aren't reloaded into the esi or edi reg. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (GET_CODE (X) == CONST_DOUBLE \ + ? ((CLASS) == GENERAL_REGS || (CLASS) == ALL_REGS \ + ? GENERAL_REGS : NO_REGS) \ + : GET_MODE (X) == QImode \ + ? ((CLASS) == GENERAL_REGS || (CLASS) == ALL_REGS \ + ? Q_REGS \ + : (CLASS) == INDEX_REGS ? (abort (), INDEX_REGS) \ + : (CLASS)) \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 80386, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FLOAT_REGS ? 1 : \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On 386 pushw decrements by exactly 2 no matter what the position was. + On the 386 there is no pushb; we use pushw instead, and this + has the effect of rounding up to 2. */ + +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & (-2)) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + On the 80386, the RTD insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RTD can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RTD is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), \ + VALUE_REGNO(TYPE_MODE(VALTYPE))) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, MODE, VALUE_REGNO(MODE)) + +/* 1 if N is a possible register number for function argument passing. + On the 80386, no registers are used in this way. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the 80386, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the 80386, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + + +/* On the 80386 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in EAX, EDX. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 0) + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ + function_prologue (FILE, SIZE) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n\tcall _mcount\n", LPREFIX, (LABELNO)); + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ +/* Note on the 386 it might be more efficient not to define this since + we have to restore it ourselves from the frame pointer, in order to + use pop */ + +#define EXIT_IGNORE_STACK 1 + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ + function_epilogue (FILE, SIZE) + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = FIRST_FLOAT_REG; regno < FIRST_PSEUDO_REGISTER; regno++)\ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 8; \ + for (regno=0 ; regno <FIRST_FLOAT_REG ; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } \ + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < STACK_POINTER_REGNUM || (unsigned) reg_renumber[REGNO] < STACK_POINTER_REGNUM) +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) <= STACK_POINTER_REGNUM || (unsigned) reg_renumber[REGNO] <= STACK_POINTER_REGNUM) + +#define REGNO_OK_FOR_SIREG_P(REGNO) ((REGNO) == 4 || reg_renumber[REGNO] == 4) +#define REGNO_OK_FOR_DIREG_P(REGNO) ((REGNO) == 5 || reg_renumber[REGNO] == 5) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index or if + it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) (REGNO (X) < STACK_POINTER_REGNUM || REGNO (X) >= FIRST_PSEUDO_REGISTER) +/* Nonzero if X is a hard reg that can be used as a base reg + of if it is a pseudo reg. */ + /* ?wfs */ +#define REG_OK_FOR_BASE_P(X) (REGNO (X) <= STACK_POINTER_REGNUM || REGNO(X) >= FIRST_PSEUDO_REGISTER) +#define REG_OK_FOR_STRREG_P(X) \ + (REGNO (X) == 4 || REGNO (X) == 5 || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_STRREG_P(X) \ + (REGNO_OK_FOR_DIREG_P (REGNO (X)) || REGNO_OK_FOR_SIREG_P (REGNO (X))) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is usually machine-independent. */ + +#define MAX_REGS_PER_ADDRESS 2 + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ + if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR + +#define LEGITIMATE_INDEX_REG_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* Return 1 if X is an index or an index times a scale. */ + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || (GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || INTVAL (XEXP (X, 1)) == 8))) + +/* Go to ADDR if X is an index term, a base reg, or a sum of those. */ + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (LEGITIMATE_INDEX_P (X)) goto ADDR; \ + GO_IF_INDEXABLE_BASE (X, ADDR); \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +/* We used to allow this, but it isn't ever used. + || ((GET_CODE (X) == POST_DEC || GET_CODE (X) == POST_INC) \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_STRREG_P (XEXP (X, 0))) \ +*/ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (CONSTANT_ADDRESS_P (X)) goto ADDR; \ + GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + GO_IF_INDEXING (XEXP (X, 0), ADDR); \ + if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + GO_IF_INDEXING (XEXP (X, 1), ADDR); } } + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the 80386, we handle X+REG by loading X into a register R and + using R+REG. R will go in a general reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in a general reg. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == MULT) \ + ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + return X; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), temp); \ + if (val != temp) emit_move_insn (temp, val, 0); \ + XEXP (X, 1) = temp; \ + return X; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), temp); \ + if (val != temp) emit_move_insn (temp, val, 0); \ + XEXP (X, 0) = temp; \ + return X; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 80386, only postdecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == POST_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE Pmode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Specify the tree operation to be used to convert reals to integers. + This should be changed to take advantage of fist --wfs ?? + */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* When a prototype says `char' or `short', really pass an `int'. + (The 386 can't easily push less than an int.) */ + +#define PROMOTE_PROTOTYPES + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Define this if addresses of constant functions + shouldn't be put through pseudo regs where they can be cse'd. + Desirable on the 386 because a CALL with a constant address is + not much slower than one with a register address. */ +#define NO_FUNCTION_CSE + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; \ + case PLUS: \ + if (GET_CODE (XEXP (RTX, 0)) == REG \ + && GET_CODE (XEXP (RTX, 1)) == CONST_INT) \ + return 2; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* ??? Find a better place to put this. */ +#if 0 +#define FINAL_PRESCAN_INSN(INSN, OPERANDS, NOPERANDS) \ + fp_hook (INSN, OPERANDS, NOPERANDS) +#endif + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* Set if the cc value is actually in the 80387, so a floating point + conditional branch must be output. */ +#define CC_IN_80387 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + notice_update_cc((EXP)) + +/* Output a signed jump insn. Use template NORMAL ordinarily, or + FLOAT following a floating point comparison. + Use NO_OV following an arithmetic insn that set the cc's + before a test insn that was deleted. + NO_OV may be zero, meaning final should reinsert the test insn + because the jump cannot be handled properly without it. */ + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ \ + if (cc_status.flags & CC_IN_80387) \ + return FLOAT; \ + if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; \ +} + +/* Control the assembler format that we output. */ + +#ifdef ATT +#include <syms.h> +#else +#define FILNMLEN 14 +#endif + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +/* In order to refer to the first 8 regs as 32 bit regs prefix an "e" + For non floating point regs, the following are the HImode names. + */ + + +#define HI_REGISTER_NAMES \ +{"ax","dx","cx","bx","si","di","bp","sp", \ + "st","st(1)"} +/* ,"st(2)","st(3)","st(4)","st(5)" } */ +#define REGISTER_NAMES HI_REGISTER_NAMES + +/* Note we are omitting these since currently I don't know how +to get gcc to use these, since they want the same but different +number as al, and ax. +*/ + +/* note the last four are not really qi_registsers, but + the md will have to never output movb into one of them + only a movw . There is no movb into the hardware reg + esi that I can find */ + +#define QI_REGISTER_NAMES \ +{"al", "dl", "cl", "bl", "si", "di", "bp", "sp",} + +/* + Don't know how to use these, yet. They overlap with ax,dx,cx,bx + and so would clobber al,dl,cl,bl +#define QI_REGISTER_NAMES_TOP \ +{"ah", \ + "dh", \ + "ch", \ + "bh", } +*/ + +/* How to renumber registers for dbxand gdb. */ + +/* {0,2,1,3,6,7,4,5,12,13,14,15,16,17} */ +#define DBX_REGISTER_NUMBER(n) \ +((n)==0?0 :(n)==1?2 :(n)==2?1 :(n)==3?3 :(n)==4?6 :(n)==5?7 :(n)==6?4 :(n)==7?5 :(n)==8?12 :(n)==9?12 :(n)) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + (assemble_name (FILE, NAME), fputs (":\n", FILE)) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "%s%.22e\n",ASM_DOUBLE, (VALUE)) + + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fputs(ASM_LONG,FILE); \ + fprintf((FILE), "0x%x\n", tem.l); \ + } while (0) + + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + + + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE,ASM_LONG), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* Likewise for `char' and `short' constants. */ +/* is this supposed to do align too?? */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE,ASM_SHORT), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fputs (ASM_BYTE,FILE), \ + output_addr_const (FILE,(VALUE)), \ + fputs ( ",",FILE), \ + output_addr_const (FILE,(VALUE)), \ + fputs (" >> 8\n",FILE)) +*/ + + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, ASM_BYTE), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf ((FILE), "%s0x%x\n", ASM_BYTE, (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpushl e%s\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tpopl e%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "%s%s%d\n",ASM_LONG,LPREFIX, VALUE) + +/* This is how to output an element of a case-vector that is relative. + We don't use these on the 386 yet, because the ATT assembler can't do + forward reference the differences. + */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) abort(); \ + fprintf (FILE, "\t.word %s%d-%s%d\n",LPREFIX, VALUE,LPREFIX, REL) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "" +#define ASM_CLOSE_PAREN "" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + The CODE z takes the size of operand from the following digit, and + outputs b,w,or l respectively. + + On the 80386, we use several such letters: + f -- float insn (print a CONST_DOUBLE as a float rather than in hex). + L,W,B,Q,S -- print the opcode suffix for specified size of operand. + R -- print the prefix for register names. + z -- print the opcode suffix for the size of the current operand. + * -- print a star (in certain assembler syntax) + w -- print the operand as if it's a "word" (HImode) even if it isn't. + w -- print the operand as if it's a byte (QImode) even if it isn't. + c -- don't print special prefixes before constant operands. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '*') + +#define PRINT_OPERAND(FILE, X, CODE) \ + print_operand (FILE, X, CODE) + + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) + +/* Routines in gnulib that return floats must return them in an fp reg, + just as other functions do which return such values. + These macros make that happen. */ + +#define SFVALUE float +#define INTIFY(FLOATVAL) FLOATVAL + +/* Nonzero if INSN magically clobbers register REGNO. */ + +#define INSN_CLOBBERS_REGNO_P(INSN, REGNO) \ + (FP_REGNO_P (REGNO) \ + && (GET_CODE (INSN) == JUMP_INSN || GET_CODE (INSN) == BARRIER)) + +/* a letter which is not needed by the normal asm syntax, which + we can use for operand syntax in the extended asm */ + +#define ASM_OPERAND_LETTER '#' + + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc-1.40/config/tm-i386esix.h b/gcc-1.40/config/tm-i386esix.h new file mode 100644 index 0000000..33b349f --- /dev/null +++ b/gcc-1.40/config/tm-i386esix.h @@ -0,0 +1,36 @@ +/* Definitions for Intel 386 running ESIX Unix System V. */ +/* Just like SCO support except don't use their special library and + predefined symbol. */ + +/* Mostly it's like AT&T Unix System V. */ + +#include "tm-i386v.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define ENDFILE_SPEC "crtn.o%s" + +/* Library spec. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Di386 -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP" + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}" + +/* SCO's assember doesn't grok '$' in labels (for g++) */ + +#define NO_DOLLAR_IN_LABEL + +/* Unlike SCO, ESIX expects the called function to pop the structure + value address. So don't define STRUCT_RETURN_CALLER_POP. */ diff --git a/gcc-1.40/config/tm-i386gas.h b/gcc-1.40/config/tm-i386gas.h new file mode 100644 index 0000000..fdb3c59 --- /dev/null +++ b/gcc-1.40/config/tm-i386gas.h @@ -0,0 +1,106 @@ +/* Definitions for Intel 386 running system V with gnu tools + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-i386.h" +/* Use the bsd assembler syntax. */ +/* we need to do this because gas is really a bsd style assembler, + * and so doesn't work well this these att-isms: + * + * ASM_OUTPUT_SKIP is .set .,.+N, which isn't implemented in gas + * ASM_OUTPUT_LOCAL is done with .set .,.+N, but that can't be + * used to define bss static space + * + * Next is the question of whether to uses underscores. RMS didn't + * like this idea at first, but since it is now obvious that we + * need this separate tm file for use with gas, at least to get + * dbx debugging info, I think we should also switch to underscores. + * We can keep tm-i386v for real att style output, and the few + * people who want both form will have to compile twice. + */ + +#include "tm-bsd386.h" + +/* these come from tm-bsd386.h, but are specific to sequent */ +#undef DBX_NO_XREFS +#undef DBX_CONTIN_LENGTH + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +#if 0 /* People say gas uses the log as the arg to .align. */ +/* When using gas, .align N aligns to an N-byte boundary. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) +#endif + +/* Align labels, etc. at 4-byte boundaries. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 2\n"); /* Use log of 4 as arg. */ + +#if 0 +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 4\n"); +#endif + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "\t.file\t\"%s\"\n", dump_base_name); diff --git a/gcc-1.40/config/tm-i386isc.h b/gcc-1.40/config/tm-i386isc.h new file mode 100644 index 0000000..6204193 --- /dev/null +++ b/gcc-1.40/config/tm-i386isc.h @@ -0,0 +1,24 @@ +/* Definitions for Intel 386 running Interactive Unix System V. */ + +/* Mostly it's like AT&T Unix System V. */ + +#include "tm-i386v.h" + +/* Use crt0.o or crt1.o as a startup file and crtn.o as a closing file. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{posix:%{pg:mcrtp1.o%s}%{!pg:%{p:mcrtp1.o%s}%{!p:crtp0.o%s}}}\ + %{!posix:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}\ + %{p:-L/lib/libp} %{pg:-L/lib/libp}}}\ + %{shlib:%{posix:crtp1.o%s}%{!posix:crt1.o%s}} " + +#define ENDFILE_SPEC "crtn.o%s" + +/* Library spec */ +#undef LIB_SPEC +#define LIB_SPEC "%{posix:-lcposix} %{shlib:-lc_s} -lc" + +/* caller has to pop the extra argument passed to functions that return + structures. */ + +#define STRUCT_RETURN_CALLER_POP diff --git a/gcc-1.40/config/tm-i386sco.h b/gcc-1.40/config/tm-i386sco.h new file mode 100644 index 0000000..f9ca635 --- /dev/null +++ b/gcc-1.40/config/tm-i386sco.h @@ -0,0 +1,39 @@ +/* Definitions for Intel 386 running SCO Unix System V. */ + + +/* Mostly it's like AT&T Unix System V. */ + +#include "tm-i386v.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define ENDFILE_SPEC "crtn.o%s" + +/* Library spec, including SCO international language support. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} libintl.a%s -lc" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Di386 -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP" + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} -DM_INTERNAT" + +/* SCO's assember doesn't grok '$' in labels (for g++) */ + +#define NO_DOLLAR_IN_LABEL + +/* SCO's libraries are compiled with Microsoft C, which requires the + caller to pop the extra argument passed to functions that return + structures. */ + +#define STRUCT_RETURN_CALLER_POP + diff --git a/gcc-1.40/config/tm-i386v.h b/gcc-1.40/config/tm-i386v.h new file mode 100644 index 0000000..573804b --- /dev/null +++ b/gcc-1.40/config/tm-i386v.h @@ -0,0 +1,86 @@ +/* Definitions for Intel 386 running system V. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-i386.h" + +/* Use the ATT assembler syntax. */ + +#include "tm-att386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{posix:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}%{!posix:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}\ + %{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp}" + +#define LIB_SPEC "%{posix:-lcposix} %{shlib:-lc_s} -lc crtn.o%s" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386" + +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We want to output SDB debugging information. */ + +#define SDB_DEBUGGING_INFO + +/* We don't want to output DBX debugging information. */ + +#undef DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Don't write a `.optim' pseudo; this assembler doesn't handle them. */ + +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) diff --git a/gcc-1.40/config/tm-i386v4.h b/gcc-1.40/config/tm-i386v4.h new file mode 100644 index 0000000..e128b66 --- /dev/null +++ b/gcc-1.40/config/tm-i386v4.h @@ -0,0 +1,62 @@ +/* Definitions for Intel 386 running system Vr4. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by James Van Artsdalen, Dell Computer Corporation. + james@bigtex.cactus.org */ + +#include "tm-i386v.h" + +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/ccs/lib/" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}} %{pg:gcrti.o%s}%{!pg:%{p:mcrti.o%s}%{!p:crti.o%s}} values-Xt.o%s" + +#undef LIB_SPEC +#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -Y P,/usr/ccs/lib:/usr/lib -Qy -lc crtn.o%s" + +/* Brain-damaged v4 include files won't work right if __STDC__ != 0 */ + +#define STDC_VALUE 0 + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + char *p = (char *) strrchr(main_input_filename, '/'); \ + if (!p++) \ + p = main_input_filename; \ + fprintf ((FILE), "\t.file\t\"%s\"\n", p); \ + } while (0) + +/* SysVr4 has a third "alignment" argument to .comm. It matters when + linking with PCC generated code when the object is less than word + length. */ + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,%u\n", (SIZE), (SIZE) < 3 ? (SIZE) : 4)) diff --git a/gcc-1.40/config/tm-i386vgas.h b/gcc-1.40/config/tm-i386vgas.h new file mode 100644 index 0000000..d8e69ff --- /dev/null +++ b/gcc-1.40/config/tm-i386vgas.h @@ -0,0 +1,121 @@ +/* Definitions for Intel 386 running system V with gnu tools + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-i386.h" +/* Use the bsd assembler syntax. */ +/* we need to do this because gas is really a bsd style assembler, + * and so doesn't work well this these att-isms: + * + * ASM_OUTPUT_SKIP is .set .,.+N, which isn't implemented in gas + * ASM_OUTPUT_LOCAL is done with .set .,.+N, but that can't be + * used to define bss static space + * + * Next is the question of whether to uses underscores. RMS didn't + * like this idea at first, but since it is now obvious that we + * need this separate tm file for use with gas, at least to get + * dbx debugging info. */ + +#include "tm-bsd386.h" + +/* these come from tm-bsd386.h, but are specific to sequent */ +#undef DBX_NO_XREFS +#undef DBX_CONTIN_LENGTH + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +#if 0 /* These aren't right for GNU ld. */ +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc crtn.o%s" +#endif + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "\t.file\t\"%s\"\n", dump_base_name); + +/* This is how to output a reference to a user-level label named NAME. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +#if 0 /* People say gas uses the log as the arg to .align. */ +/* When using gas, .align N aligns to an N-byte boundary. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) +#endif + +/* Align labels, etc. at 4-byte boundaries. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 2\n"); /* Use log of 4 as arg. */ + +#if 0 +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 4\n"); +#endif + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) diff --git a/gcc-1.40/config/tm-i860.h b/gcc-1.40/config/tm-i860.h new file mode 100644 index 0000000..ee0bacb --- /dev/null +++ b/gcc-1.40/config/tm-i860.h @@ -0,0 +1,1228 @@ +/* Definitions of target machine for GNU compiler, for Intel 860. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Di860 -Dunix" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (i860)"); + +/* Run-time compilation parameters selecting different hardware subsets. + + On the i860, we have one: TARGET_FPU. */ + +extern int target_flags; + +/* Nonzero if we should generate code to use the fpu. */ +#define TARGET_FPU (target_flags & 1) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { {"fpu", 1}, \ + {"soft-float", -1}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 1 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is a moot question on the i860 due to the lack of bit-field insns. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on i860 in the mode we will use. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* For the i860 this goes with BYTES_BIG_ENDIAN. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 128 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* If bit field type is int, dont let it cross an int, + and give entire struct the alignment of an int. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + + i860 has 32 fullword registers and 32 floating point registers. */ + +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the i860, this includes the always-0 registers + and fp, sp, and the return address. + Also r31, used for special purposes for constant addresses. */ +#define FIXED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + On the i860, these are r0-r3, r16-r31, f0, f1, and f16-f31. */ +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1} + +#define REG_ALLOC_ORDER \ + {16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26, 27, 28, 29, 30, 31, \ + 0, 1, 2, 3, 4, 5, 6, 7, \ + 8, 9, 10, 11, 12, 13, 14, 15, \ + 40, 41, 42, 43, 44, 45, 46, 47, \ + 48, 49, 50, 51, 52, 53, 54, 55, \ + 56, 57, 58, 59, 60, 61, 62, 63, \ + 32, 33, 34, 35, 36, 37, 38, 39} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the i860, all registers hold 32 bits worth. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the i860, any register can hold anything, provided it is properly + aligned. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((GET_MODE_SIZE ((MODE)) <= 4) || ((REGNO) & 1) == 0) \ + && ((REGNO) < 32 || TARGET_FPU)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +/* I think that is not always true; alignment restrictions for doubles + should not prevent tying them with singles. So try allowing that. + On the other hand, don't let fixed and floating be tied; + this restriction is not necessary, but may make better code. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((GET_MODE_CLASS ((MODE1)) == MODE_FLOAT) \ + == (GET_MODE_CLASS ((MODE2)) == MODE_FLOAT)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* i860 pc isn't overloaded on a register that the compiler knows about. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 2 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 3 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 28 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 29 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 16 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The i860 has two kinds of registers, hence four classes. */ + +enum reg_class { NO_REGS, GENERAL_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "GENERAL_REGS", "FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ + {{0, 0}, {0xffffffff, 0}, \ + {0, 0xffffffff}, {0xffffffff, 0xffffffff}} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) >= 32 ? FP_REGS : GENERAL_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_REGS : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For the i860, `I' is used for the range of constants + an add/subtract insn can actually contain. + But not including -0x8000, since we need + to negate the constant sometimes. + `J' is used for the range which is just zero (since that is R0). + `K' is used for the range allowed in bte. + `L' is used for the range allowed in logical insns. */ + +#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x7fff) < 0xffff) + +#define LOGIC_INT(X) ((unsigned) INTVAL (X) < 0x10000) + +#define SMALL_INTVAL(X) ((unsigned) ((X) + 0x7fff) < 0xffff) + +#define LOGIC_INTVAL(X) ((unsigned) (X) < 0x10000) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? ((unsigned) (VALUE) + 0x7fff) < 0xffff \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : (C) == 'L' ? (unsigned) (VALUE) < 0x10000 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the i860, this is the size of MODE in words. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the i860, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the i860, the value register depends on the mode. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT \ + ? 40 : 16)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, MODE, \ + (GET_MODE_CLASS ((MODE)) == MODE_FLOAT \ + ? 40 : 16)) + +/* 1 if N is a possible register number for a function value + as seen by the caller. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 40 || (N) == 16) + +/* 1 if N is a possible register number for function argument passing. + On the i860, these are r16-r27 and f8-f15. */ + +#define FUNCTION_ARG_REGNO_P(N) \ + (((N) < 28 && (N) > 15) || ((N) < 48 && (N) >= 40)) + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the i860, we must count separately the number of general registers used + and the number of float registers used. */ + +#define CUMULATIVE_ARGS struct { int ints, floats; } + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the i860, the general-reg offset normally starts at 0, + but starts at 4 bytes + when the function gets a structure-value-address as an + invisible first argument. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM).ints = ((FNTYPE) != 0 && aggregate_value_p ((FNTYPE)) \ + ? 4 : 0), \ + (CUM).floats = 0) + +/* Machine-specific subroutines of the following macros. */ +#define CEILING(X,Y) (((X) + (Y) - 1) / (Y)) +#define ROUNDUP(X,Y) (CEILING ((X), (Y)) * (Y)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) + Floats, and doubleword ints, are returned in f regs; + other ints, in r regs. + Aggregates, even short ones, are passed in memory. */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((TYPE) != 0 && (TREE_CODE ((TYPE)) == RECORD_TYPE \ + || TREE_CODE ((TYPE)) == UNION_TYPE) \ + ? 0 \ + : GET_MODE_CLASS ((MODE)) == MODE_FLOAT || (MODE) == DImode \ + ? ((CUM).floats = (ROUNDUP ((CUM).floats, GET_MODE_SIZE ((MODE))) \ + + ROUNDUP (GET_MODE_SIZE (MODE), 4))) \ + : GET_MODE_CLASS ((MODE)) == MODE_INT \ + ? ((CUM).ints = (ROUNDUP ((CUM).ints, GET_MODE_SIZE ((MODE))) \ + + ROUNDUP (GET_MODE_SIZE (MODE), 4))) \ + : 0) + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the i860, the first 12 words of integer arguments go in r16-r27, + and the first 8 words of floating arguments go in f8-f15. + DImode values are treated as floats. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((TYPE) != 0 && (TREE_CODE ((TYPE)) == RECORD_TYPE \ + || TREE_CODE ((TYPE)) == UNION_TYPE) \ + ? 0 \ + : GET_MODE_CLASS ((MODE)) == MODE_FLOAT || (MODE) == DImode \ + ? (ROUNDUP ((CUM).floats, GET_MODE_SIZE ((MODE))) < 32 \ + ? gen_rtx (REG, (MODE), \ + 40+(ROUNDUP ((CUM).floats, \ + GET_MODE_SIZE ((MODE))) \ + / 4)) \ + : 0) \ + : GET_MODE_CLASS ((MODE)) == MODE_INT \ + ? (ROUNDUP ((CUM).ints, GET_MODE_SIZE ((MODE))) < 48 \ + ? gen_rtx (REG, (MODE), \ + 16+(ROUNDUP ((CUM).ints, \ + GET_MODE_SIZE ((MODE))) \ + / 4)) \ + : 0) \ + : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + int fsize = (SIZE); \ + int nregs, i; \ + for (i = 0, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + } \ + fsize += nregs * 4 + 8; \ + fsize = (fsize + 15) & -16; \ + if (fsize > 0x7fff) \ + { \ + fprintf (FILE, "\tadds -16,sp,sp\n"); \ + fprintf (FILE, "\tst.l fp,8(sp)\n"); \ + fprintf (FILE, "\tst.l r1,12(sp)\n"); \ + fprintf (FILE, "\tadds 8,sp,fp\n"); \ + fprintf (FILE, "\torh %d,r0,r31\n", (fsize - 16) >> 16); \ + fprintf (FILE, "\tor %d,r31,r31\n", (fsize - 16) & 0xffff); \ + fprintf (FILE, "\tsubs sp,r31,sp\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tadds -%d,sp,sp\n", fsize); \ + fprintf (FILE, "\tst.l fp,%d(sp)\n", fsize - 8); \ + fprintf (FILE, "\tst.l r1,%d(sp)\n", fsize - 4); \ + fprintf (FILE, "\tadds %d,sp,fp\n", fsize - 8); \ + } \ + for (i = 0, nregs = 0; i < 32; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tst.l %s,%d(sp)\n", \ + reg_names[i], 4 * nregs++); \ + for (i = 32; i < 64; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tfst.l %s,%d(sp)\n", \ + reg_names[i], 4 * nregs++); \ +} +/* ??? maybe save pairs or quads of fp registers. */ + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + abort (); + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +/* #define EXIT_IGNORE_STACK 0 */ + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + int fsize = (SIZE); \ + int nregs, i; \ + for (i = 0, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + } \ + fsize += nregs * 4 + 8; \ + fsize = (fsize + 15) & -16; \ + if (fsize < 0x7fff) \ + { \ + for (i = 0, nregs = 0; i < 32; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tld.l %d(fp),%s\n", \ + 4 * nregs++ - (fsize - 8), reg_names[i]); \ + for (i = 32; i < 64; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tfld.l %d(fp),%s\n", \ + 4 * nregs++ - (fsize - 8), reg_names[i]); \ + } \ + else \ + { \ + fprintf (FILE, "\torh %d,r0,r31\n", (fsize - 8) >> 16); \ + fprintf (FILE, "\tor %d,r31,r31\n", (fsize - 8) & 0xffff); \ + fprintf (FILE, "\tsubs fp,r31,sp\n"); \ + for (i = 0, nregs = 0; i < 32; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tld.l %d(sp),%s\n", \ + 4 * nregs++, reg_names[i]); \ + for (i = 32; i < 64; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tfld.l %d(sp),%s\n", \ + 4 * nregs++, reg_names[i]); \ + } \ + if (fsize < 0x7fff) \ + { \ + fprintf (FILE, "\tld.l 4(fp),r1\n"); \ + fprintf (FILE, "\tld.l 0(fp),fp\n"); \ + fprintf (FILE, "\tbri r1\n\taddu %d,sp,sp\n", fsize); \ + } \ + else \ + { \ + fprintf (FILE, "\tld.l 4(fp),r1\n"); \ + fprintf (FILE, "\tadds 8,fp,r31\n"); \ + fprintf (FILE, "\tld.l 0(fp),fp\n"); \ + fprintf (FILE, "\tbri r1\n\tmov r31,sp\n"); \ + } \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 0x20) < 32 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 32) + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the i860, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the Sparc, this is anything but a CONST_DOUBLE. + Let's try permitting CONST_DOUBLEs and see what happens. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) (((unsigned) REGNO (X)) - 32 >= 14) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (((unsigned) REGNO (X)) - 32 >= 14) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + On the i860, the actual addresses must be REG+REG or REG+SMALLINT. + But we can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. + + The displacement in an address must be a multiple of the alignment. + + Try making SYMBOL_REF (and other things which are CONSTANT_ADDRESS_P) + a legitimate address, regardless. Because the only insns which can use + memory are load or store insns, the added hair in the machine description + is not that bad. It should also speed up the compiler by halving the number + of insns it must manage for each (MEM (SYMBOL_REF ...)) involved. */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (GET_CODE (X) == REG) \ + { if (REG_OK_FOR_BASE_P (X)) goto ADDR; } \ + else if (GET_CODE (X) == PLUS) \ + { \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && INTVAL (XEXP (X, 1)) >= -0x8000 \ + && INTVAL (XEXP (X, 1)) < 0x8000 \ + && INTVAL (XEXP (X, 1)) & (GET_MODE_SIZE (MODE) - 1) == 0) \ + goto ADDR; \ + } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + { \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) >= -0x8000 \ + && INTVAL (XEXP (X, 0)) < 0x8000 \ + && INTVAL (XEXP (X, 0)) & (GET_MODE_SIZE (MODE) - 1) == 0) \ + goto ADDR; \ + } \ + } \ + else if (CONSTANT_ADDRESS_P (X)) \ + goto ADDR; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. */ + +/* On the i860, change COMPLICATED + CONSTANT to REG+CONSTANT. + Also change a symbolic constant to a REG, + though that may not be necessary. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == PLUS) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == PLUS) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) != REG \ + && GET_CODE (XEXP (X, 0)) != CONST_INT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) != REG \ + && GET_CODE (XEXP (X, 1)) != CONST_INT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (x) == SYMBOL_REF) \ + (X) = copy_to_reg (X); \ + if (GET_CODE (x) == CONST) \ + (X) = copy_to_reg (X); \ + if (memory_address_p (MODE, X)) \ + goto WIN; } + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the i860 this is never true. + There are some addresses that are invalid in wide modes + but valid for narrower modes, but they shouldn't cause trouble. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* On the 860, every legit address is offsettable, + but GCC would have trouble figuring this out. */ + +#define OFFSETTABLE_ADDRESS_P(MODE, ADDR) (memory_address_p ((MODE), (ADDR))) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Must pass floats to gnulib functions as doubles. */ +#define GNULIB_NEEDS_DOUBLE 1 + +#define DIVSI3_LIBCALL "*.div" +#define UDIVSI3_LIBCALL "*.udiv" +#define REMSI3_LIBCALL "*.rem" +#define UREMSI3_LIBCALL "*.urem" + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 16 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* This is System V, so it wants sdb format. */ +#define DBX_DEBUGGING_INFO + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE SImode + +/* Define this if addresses of constant functions + shouldn't be put through pseudo regs where they can be cse'd. + Desirable on machines where ordinary constants are expensive + but a CALL with constant address is cheap. */ +#define NO_FUNCTION_CSE + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (INTVAL (RTX) == 0) \ + return 0; \ + if (INTVAL (RTX) < 0x2000 && INTVAL (RTX) >= -0x2000) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 2 * GET_MODE_SIZE (GET_MODE (RTX)) / UNITS_PER_WORD; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This holds the value sourcing h%r31. We keep this info + around so that mem/mem ops, such as increment and decrement, + etc, can be performed reasonably. */ +#define CC_STATUS_MDEP rtx + +#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0) + +/* On the i860, each comparison tests just one condition, + so only that condition can be remembered. + We don't need GT, GE, GTU and GEU because CC_REVERSED can handle them. */ +#define CC_ONLY_EQ 0100 +#define CC_ONLY_LE 0200 +#define CC_ONLY_LT 0400 +#define CC_ONLY_LEU 02000 +#define CC_ONLY_LTU 04000 +#define CC_CONDITION_MASK 07700 + +/* Non-zero to invert the sense of the condition code. */ +#define CC_NEGATED 010000 + +/* Nonzero if we know the value of h%r31. */ +#define CC_KNOW_HI_R31 0100000 + +/* Nonzero if h%r31 is actually ha%something, rather than h%something. */ +#define CC_HI_R31_ADJ 0200000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the i860, only compare insns set a useful condition code. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ cc_status.flags &= (CC_KNOW_HI_R31 | CC_HI_R31_ADJ); \ + cc_status.value1 = 0; cc_status.value2 = 0; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#define ASM_FILE_START(FILE) +#if 0 +#define ASM_FILE_START(FILE) \ + do { sdbout_filename ((FILE), main_input_filename); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) +#endif + +#define ASM_FILE_START_1(FILE) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "sp", "fp", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r30", "r31", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", \ + "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", \ + "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", \ + "f30", "f31" } + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* Likewise, for function names. The difference is that we output a no-op + just before the beginning of the function, to ensure that there does not + appear to be a delayed branch there. + Such a thing would confuse interrupt recovery. */ +#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \ + do { fprintf (FILE, "\tnop\n"); ASM_OUTPUT_LABEL (FILE,NAME); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* This is how to output an internal numbered label which + labels a jump table. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + fprintf (FILE, ".data\n\t.align 4\n.%s%d:\n", PREFIX, NUM) + +/* Output at the end of a jump table. */ + +#define ASM_OUTPUT_CASE_END(FILE,NUM,INSN) \ + fprintf (FILE, ".text\n") + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*.%s%d", PREFIX, NUM) + +#define ASCII_DATA_ASM_OP ".byte" +#define ASM_OUTPUT_ASCII(f, p, size) \ +{ register int i; \ + int inside; \ + inside = FALSE; \ + for (i = 0; i < size; i++) { \ + if (i % 64 == 0) { \ + if (i != 0) { \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ + inside = FALSE; \ + } \ + fprintf(f, "%s ", ASCII_DATA_ASM_OP); \ + } \ + if (p[i] < 32 || p[i] == '\\' || p[i] == '"' || p[i] == 127) { \ + if (inside) { \ + putc('"', f); \ + inside = FALSE; \ + } \ + if (i % 64 != 0) \ + putc(',', f); \ + fprintf(f, "%d", p[i]); \ + } else { \ + if (!inside) { \ + if (i % 64 != 0) \ + putc(',', f); \ + putc('"', f); \ + inside = TRUE; \ + } \ + putc(p[i], f); \ + } \ + } \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ +} + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double %.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float %.12e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.short "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output code to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\taddu -16,r3,r3\n\t%sst.l %s,0(r3)\n", \ + ((REGNO) < 32 ? "" : "f"), reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\t%sld.l 0(r3),%s\n\taddu 16,r3,r3\n", \ + ((REGNO) < 32 ? "" : "f"), reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long .L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (The i860 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word .L%d-.L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) != 0) \ + fprintf (FILE, "\t.align %d\n", 1 << (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.blkb %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* This assumes the compiler is running on a little-endian machine. + The support for the other case is left for version 2, + since there is nothing in version 1 to indicate the sex of the host. */ + +#define PRINT_OPERAND_EXTRACT_FLOAT(X) \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On the i860, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. + It can also be `m', meaning this is a memory ref, + but print its address as a constant. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if ((CODE) == 'm') \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "r0"); \ + else if ((CODE) == 'r' && (X) == CONST0_RTX (GET_MODE (X))) \ + fprintf (FILE, "f0"); \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + { \ + if (GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + PRINT_OPERAND_EXTRACT_FLOAT (X); \ + u1.f = u.d; \ + fprintf (FILE, "0x%x", u1.i); } \ + else \ + abort (); \ + } \ + else \ + output_addr_const (FILE, X); } + +/* Print a memory address as an operand to reference that memory location. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx base, index = 0; \ + int offset = 0; \ + register rtx addr = ADDR; \ + if (GET_CODE (addr) == REG) \ + { \ + fprintf (FILE, "0(%s)", reg_names[REGNO (addr)]); \ + } \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == CONST_INT) \ + offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);\ + else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);\ + else \ + base = XEXP (addr, 0), index = XEXP (addr, 1); \ + if (index != 0) \ + fprintf (FILE, "%s", reg_names[REGNO (index)]); \ + else \ + fprintf (FILE, "%d", offset); \ + fprintf (FILE, "(%s)", reg_names[REGNO (base)]); \ + } \ + else \ + { \ +/* ??? this may be wrong. */ \ + output_addr_const (FILE, addr); \ + } \ +} diff --git a/gcc-1.40/config/tm-i860bsdg.h b/gcc-1.40/config/tm-i860bsdg.h new file mode 100644 index 0000000..84c5ce5 --- /dev/null +++ b/gcc-1.40/config/tm-i860bsdg.h @@ -0,0 +1,4 @@ +#include "tm-i860bsd.h" + +#undef ASCII_DATA_ASM_OP +#define ASCII_DATA_ASM_OP ".ascii" diff --git a/gcc-1.40/config/tm-i860g.h b/gcc-1.40/config/tm-i860g.h new file mode 100644 index 0000000..9bf8295 --- /dev/null +++ b/gcc-1.40/config/tm-i860g.h @@ -0,0 +1,4 @@ +#include "tm-i860.h" + +#undef ASCII_DATA_ASM_OP +#define ASCII_DATA_ASM_OP ".ascii" diff --git a/gcc-1.40/config/tm-iris.h b/gcc-1.40/config/tm-iris.h new file mode 100644 index 0000000..66c7606 --- /dev/null +++ b/gcc-1.40/config/tm-iris.h @@ -0,0 +1,48 @@ +/* Definitions of target machine for GNU compiler. Iris version. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dmips -Dsgi -DSVR3 -Dhost_mips -DMIPSEB -DSYSTYPE_SYSV -DLANGUAGE_C" + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} crtn.o%s" + +#define SGI_TARGET 1 /* inform other mips files this is SGI */ + +/* Always use 1 for .file number. I [meissner@osf.org] wonder why + IRIS needs this. */ + +#define SET_FILE_NUMBER() num_source_filenames = 1 + +/* Put out a label after a .loc. I [meissner@osf.org] wonder why + IRIS needs this. */ + +#define LABEL_AFTER_LOC(STREAM) fprintf (STREAM, "LM%d:\n", ++sym_lineno) + +#define STACK_ARGS_ADJUST(SIZE) \ +{ \ + SIZE.constant += 4; \ + if (SIZE.constant < 32) \ + SIZE.constant = 32; \ +} + +#include "tm-mips.h" diff --git a/gcc-1.40/config/tm-isi68-nfp.h b/gcc-1.40/config/tm-isi68-nfp.h new file mode 100644 index 0000000..c51d5a8 --- /dev/null +++ b/gcc-1.40/config/tm-isi68-nfp.h @@ -0,0 +1,5 @@ +/* Define target machine as an ISI 68000/68020 with no 68881. */ + +#define TARGET_DEFAULT 5 + +#include "tm-isi68.h" diff --git a/gcc-1.40/config/tm-isi68.h b/gcc-1.40/config/tm-isi68.h new file mode 100644 index 0000000..5900e2b --- /dev/null +++ b/gcc-1.40/config/tm-isi68.h @@ -0,0 +1,79 @@ +/* Definitions of target machine for GNU compiler. ISI 68000/68020 version. + Intended only for use with GAS, and not ISI's assembler, which is buggy + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +#if TARGET_DEFAULT & 2 +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* If the 68881 is used, link must load libmc.a instead of libc.a */ + +#define LIB_SPEC "%{msoft-float:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}%{!msoft-float:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}}" + +#else +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* If the 68881 is used, link must load libmc.a instead of libc.a */ + +#define LIB_SPEC "%{!m68881:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}%{m68881:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}}" +#endif + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dmc68000 -Dis68k" + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Override parts of tm-m68000.h to fit the ISI 68k machine. */ + +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_VALUE_REGNO_P +#undef ASM_FILE_START + +/* If TARGET_68881, return SF and DF values in f0 instead of d0. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + +/* 1 if N is a possible register number for a function value. + D0 may be used, and F0 as well if -m68881 is specified. */ + +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (TARGET_68881 && (N) == 16)) + +/* Also output something to cause the correct _doprnt to be loaded. */ +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n%s\n", TARGET_68881 ? ".globl fltused" : "") diff --git a/gcc-1.40/config/tm-m68k.h b/gcc-1.40/config/tm-m68k.h new file mode 100644 index 0000000..256b06e --- /dev/null +++ b/gcc-1.40/config/tm-m68k.h @@ -0,0 +1,1643 @@ +/* Definitions of target machine for GNU compiler. Sun 68000/68020 version. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +/* See tm-sun3.h, tm-sun2.h, tm-isi68.h for different CPP_PREDEFINES. */ + +/* Print subsidiary information on the compiler version in use. */ +#ifdef MOTOROLA +#define TARGET_VERSION fprintf (stderr, " (68k, Motorola syntax)"); +#else +#define TARGET_VERSION fprintf (stderr, " (68k, MIT syntax)"); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile for a 68020 (not a 68000 or 68010). */ +#define TARGET_68020 (target_flags & 1) +/* Compile 68881 insns for floating point (not library calls). */ +#define TARGET_68881 (target_flags & 2) +/* Compile using 68020 bitfield insns. */ +#define TARGET_BITFIELD (target_flags & 4) +/* Compile using rtd insn calling sequence. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 8) +/* Compile passing first two args in regs 0 and 1. + This exists only to test compiler features that will + be needed for RISC chips. It is not usable + and is not intended to be usable on this cpu. */ +#define TARGET_REGPARM (target_flags & 020) +/* Compile with 16-bit `int'. */ +#define TARGET_SHORT (target_flags & 040) + +/* Compile with special insns for Sun FPA. */ +#define TARGET_FPA (target_flags & 0100) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "68881", 2}, \ + { "bitfield", 4}, \ + { "68000", -5}, \ + { "c68000", -5}, \ + { "soft-float", -0102}, \ + { "nobitfield", -4}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "fpa", 0100}, \ + { "nofpa", -0100}, \ + { "", TARGET_DEFAULT}} +/* TARGET_DEFAULT is defined in tm-sun*.h and tm-isi68.h, etc. */ + +/* Blow away 68881 flag silently on TARGET_FPA (since we can't clear + any bits in TARGET_SWITCHES above) */ +#define OVERRIDE_OPTIONS \ +{ \ + if (TARGET_FPA) target_flags &= ~2; \ +} + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is true for 68020 insns such as bfins and bfexts. + We make it true always by avoiding using the single-bit insns + except in special cases with constant bit numbers. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 68000. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For 68000 we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY (TARGET_SHORT ? 16 : 32) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 16 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Define number of bits in most basic integer type. + (If undefined, default is BITS_PER_WORD). */ + +#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32) + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + For the 68000, we give the data registers numbers 0-7, + the address registers numbers 010-017, + and the 68881 floating point registers numbers 020-027. */ +#define FIRST_PSEUDO_REGISTER 56 /* 24 */ + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 68000, only the stack pointer is such. */ +/* fpa0 is also reserved so that it can be used to move shit back and + forth between high fpa regs and everything else. */ +#define FIXED_REGISTERS \ + {0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + /* FPA registers. */ \ + 1, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, } + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, \ + /* FPA registers. */ \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, } + +/* Make sure everything's fine if we *don't* have a given processor. + This assumes that putting a register in fixed_regs will keep the + compilers mitt's completely off it. We don't bother to zero it out + of register classes. If neither TARGET_FPA or TARGET_68881 is set, + the compiler won't touch since no instructions that use these + registers will be valid. */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + int i; \ + HARD_REG_SET x; \ + if (!TARGET_FPA) \ + { \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FPA_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ + if (TARGET_FPA) \ + { \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FP_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ +} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the 68000, ordinary registers hold 32 bits worth; + for the 68881 registers, a single register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 16 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 68000, the cpu registers can hold any mode but the 68881 registers + can hold only SFmode or DFmode. And the 68881 registers can't hold anything + if 68881 use is disabled. However, the Sun FPA register can + (apparently) hold whatever you feel like putting in them. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((REGNO) < 16 && \ + (!TARGET_FPA || (MODE) != DFmode || (REGNO) != 7)) \ + || ((REGNO) < 24 \ + ? TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode) \ + : ((REGNO) < 56 \ + ? TARGET_FPA : 0))) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (! TARGET_68881 \ + || (((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode))) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* m68000 pc isn't overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 15 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 14 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 14 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The 68000 has three kinds of registers, so eight classes would be + a complete set. One of them is not needed. */ + +/* + * Notes on final choices: + * + * 1) Didn't feel any need to union-ize LOW_FPA_REGS with anything + * else. + * 2) Removed all unions that involve address registers with + * floating point registers (left in unions of address and data with + * floating point). + * 3) Defined GENERAL_REGS as ADDR_OR_DATA_REGS. + * 4) Defined ALL_REGS as FPA_OR_FP_OR_GENERAL_REGS. + * 4) Left in everything else. + */ +enum reg_class { NO_REGS, LO_FPA_REGS, FPA_REGS, FP_REGS, + FP_OR_FPA_REGS, DATA_REGS, DATA_OR_FPA_REGS, DATA_OR_FP_REGS, + DATA_OR_FP_OR_FPA_REGS, ADDR_REGS, GENERAL_REGS, + GENERAL_OR_FPA_REGS, GENERAL_OR_FP_REGS, ALL_REGS, + LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + { "NO_REGS", "LO_FPA_REGS", "FPA_REGS", "FP_REGS", \ + "FP_OR_FPA_REGS", "DATA_REGS", "DATA_OR_FPA_REGS", "DATA_OR_FP_REGS", \ + "DATA_OR_FP_OR_FPA_REGS", "ADDR_REGS", "GENERAL_REGS", \ + "GENERAL_OR_FPA_REGS", "GENERAL_OR_FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ +{ \ + {0, 0}, /* NO_REGS */ \ + {0xff000000, 0x000000ff}, /* LO_FPA_REGS */ \ + {0xff000000, 0x00ffffff}, /* FPA_REGS */ \ + {0x00ff0000, 0x00000000}, /* FP_REGS */ \ + {0xffff0000, 0x00ffffff}, /* FP_OR_FPA_REGS */ \ + {0x000000ff, 0x00000000}, /* DATA_REGS */ \ + {0xff0000ff, 0x00ffffff}, /* DATA_OR_FPA_REGS */ \ + {0x00ff00ff, 0x00000000}, /* DATA_OR_FP_REGS */ \ + {0xffff00ff, 0x00ffffff}, /* DATA_OR_FP_OR_FPA_REGS */\ + {0x0000ff00, 0x00000000}, /* ADDR_REGS */ \ + {0x0000ffff, 0x00000000}, /* GENERAL_REGS */ \ + {0xff00ffff, 0x00ffffff}, /* GENERAL_OR_FPA_REGS */\ + {0x00ffffff, 0x00000000}, /* GENERAL_OR_FP_REGS */\ + {0xffffffff, 0x00ffffff}, /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +extern enum reg_class regno_reg_class[]; +#define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)>>3]) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS ADDR_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We do a trick here to modify the effective constraints on the + machine description; we zorch the constraint letters that aren't + appropriate for a specific target. This allows us to guarantee + that a specific kind of register will not be used for a given target + without fiddling with the register classes above. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? ADDR_REGS : \ + ((C) == 'd' ? DATA_REGS : \ + ((C) == 'f' ? (TARGET_68881 ? FP_REGS : \ + NO_REGS) : \ + ((C) == 'x' ? (TARGET_FPA ? FPA_REGS : \ + NO_REGS) : \ + ((C) == 'y' ? (TARGET_FPA ? LO_FPA_REGS : \ + NO_REGS) : \ + NO_REGS))))) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For the 68000, `I' is used for the range 1 to 8 + allowed as immediate shift counts and in addq. + `J' is used for the range of signed numbers that fit in 16 bits. + `K' is for numbers that moveq can't handle. + `L' is for range -8 to -1, range of values that can be added with subq. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) > 0 && (VALUE) <= 8 : \ + (C) == 'J' ? (VALUE) >= -0x8000 && (VALUE) <= 0x7FFF : \ + (C) == 'K' ? (VALUE) < -0x80 || (VALUE) >= 0x80 : \ + (C) == 'L' ? (VALUE) < 0 && (VALUE) >= -8 : 0) + +/* + * A small bit of explanation: + * "G" defines all of the floating constants that are *NOT* 68881 + * constants. this is so 68881 constants get reloaded and the + * fpmovecr is used. "H" defines *only* the class of constants that + * the fpa can use, because these can be gotten at in any fpa + * instruction and there is no need to force reloads. + */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? ! (TARGET_68881 && standard_68881_constant_p (VALUE)) : \ + (C) == 'H' ? (TARGET_FPA && standard_sun_fpa_constant_p (VALUE)) : 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. + On the 68000 series, use a data reg if possible when the + value is a constant in the range where moveq could be used + and we ensure that QImodes are reloaded into data regs. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x80) < 0x100 \ + && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : GET_MODE (X) == QImode \ + ? DATA_REGS \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 68000, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS || (CLASS) == FPA_REGS || (CLASS) == LO_FPA_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 68000, sp@- in a byte insn really pushes a word. */ +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + On the 68000, the RTS insn cannot pop anything. + On the 68010, the RTD insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RTD can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RTD is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the 68000 the return value is in D0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the 68000 the return value is in D0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* 1 if N is a possible register number for a function value. + On the 68000, d0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for function argument passing. + On the 68000, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the m68k, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the m68k, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the 68000 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in d0, d1. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 0) + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +/* Note that the order of the bit mask for fmovem is the opposite + of the order for movem! */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (TARGET_68020 || fsize < 0x8000) \ + fprintf (FILE, "\tlink a6,#%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink a6,#0\n\tsubl #%d,sp\n", fsize); } \ + for (regno = 24; regno < 56; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + fprintf(FILE, "\tfpmoved %s, sp@-\n", \ + reg_names[regno]); \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if ((mask & 0xff) != 0) \ + fprintf (FILE, "\tfmovem #0x%x,sp@-\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmovel %s,sp@-\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmoveml #0x%x,sp@-\n", mask); } + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tlea LP%d,a0\n\tjsr mcount\n", (LABELNO)) + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\ttstl LPBX0\n\tbne LPI%d\n\tpea LPBX0\n\tjsr ___bb_init_func\n\taddql #4,sp\nLPI%d:\n", \ + LABELNO, LABELNO); + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. */ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, "\taddql #1,LPBX2+%d\n", 4 * BLOCKNO) + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 1 + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset, fpoffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + FUNCTION_EXTRA_EPILOGUE (FILE, SIZE); \ + nregs = 0; fmask = 0; fpoffset = 0; \ + for (regno = 24 ; regno < 56 ; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + fpoffset = nregs*8; \ + nregs = 0; \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = fpoffset + nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask || fpoffset)) \ + { fprintf (FILE, "\tmovel #%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmovel a6@(-%d,a0:l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovel sp@+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmovel a6@(-%d),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmoveml a6@(-%d,a0:l),#0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmoveml sp@+,#0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmoveml a6@(-%d),#0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem a6@(-%d,a0:l),#0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem sp@+,#0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem a6@(-%d),#0x%x\n", \ + foffset + fsize, fmask); } \ + if (fpoffset != 0) \ + for (regno = 55; regno >= 24; regno--) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) { \ + if (big) \ + fprintf(FILE, "\tfpmoved a6@(-%d,a0:l), %s\n", \ + fpoffset + fsize, reg_names[regno]); \ + else if (! frame_pointer_needed) \ + fprintf(FILE, "\tfpmoved sp@+, %s\n", \ + reg_names[regno]); \ + else \ + fprintf(FILE, "\tfpmoved a6@(-%d), %s\n", \ + fpoffset + fsize, reg_names[regno]); \ + fpoffset -= 8; \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk a6\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd #%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* This is a hook for other tm files to change. */ +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } \ + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT +/* #define HAVE_POST_DECREMENT */ + +#define HAVE_PRE_DECREMENT +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +(((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8) +#define REGNO_OK_FOR_DATA_P(REGNO) \ +((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8) +#define REGNO_OK_FOR_FPA_P(REGNO) \ +(((REGNO) >= 24 && (REGNO) < 56) || (reg_renumber[REGNO] >= 24 && reg_renumber[REGNO] < 56)) + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the 68000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is a data register. */ + +#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X))) + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* 1 if X is an address register */ + +#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) + +/* 1 if X is a register in the Sun FPA. */ +#define FPA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FPA_P (REGNO (X))) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) ((REGNO (X) ^ 020) >= 8) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) ((REGNO (X) & ~027) != 0) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + || (GET_CODE (X) == PLUS \ + && REG_P (XEXP (X, 0)) && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)) + +#if 0 +/* This should replace the last two lines + except that Sun's assembler does not seem to handle such operands. */ + && (TARGET_68020 ? CONSTANT_ADDRESS_P (XEXP (X, 1)) \ + : (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)))) +#endif + + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; } + +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ +{ if (GET_CODE (X) == LABEL_REF) goto ADDR; \ + if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR; } + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +#define GO_IF_INDEXED_ADDRESS(X, ADDR) \ +{ GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); } \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } } + +#define LEGITIMATE_INDEX_REG_P(X) \ + ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ + || (GET_CODE (X) == SIGN_EXTEND \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_MODE (XEXP (X, 0)) == HImode \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)))) + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || (TARGET_68020 && GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || INTVAL (XEXP (X, 1)) == 8))) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + GO_IF_INDEXED_ADDRESS (X, ADDR); } + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the 68000, we handle X+REG by loading X into a register R and + using R+REG. R will go in an address reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in an address reg. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == MULT) \ + ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + return X; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 1) = temp; \ + return X; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 0) = temp; \ + return X; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 68000, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE -1 + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* Set if the cc value is actually in the 68881, so a floating point + conditional branch must be output. */ +#define CC_IN_68881 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the 68000, all the insns to store in an address register + fail to set the cc's. However, in some cases these instructions + can make it possibly invalid to use the saved cc's. In those + cases we clear out some or all of the saved cc's so they won't be used. */ + +/* It was claimed recently that addq, subq to an address register + do update the cc's, but the 68000 and 68020 manuals say otherwise. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ \ + /* If the cc is being set from the fpa and the + expression is not an explicit floating point + test instruction (which has code to deal with + this), reinit the CC */ \ + if (((cc_status.value1 && FPA_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FPA_REG_P (cc_status.value2))) \ + && !(GET_CODE(EXP) == PARALLEL \ + && GET_CODE (XVECEXP(EXP, 0, 0)) == SET \ + && XEXP (XVECEXP (EXP, 0, 0), 0) == cc0_rtx)) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (EXP) == SET) \ + { if (ADDRESS_REG_P (SET_DEST (EXP))) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2)) \ + cc_status.value2 = 0; } \ + else if (!FP_REG_P (SET_DEST (EXP)) \ + && SET_DEST (EXP) != cc0_rtx \ + && (FP_REG_P (SET_SRC (EXP)) \ + || GET_CODE (SET_SRC (EXP)) == FIX \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_TRUNCATE \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_EXTEND)) \ + { CC_STATUS_INIT; } \ + /* A pair of move insns doesn't produce a useful overall cc. */ \ + else if (!FP_REG_P (SET_DEST (EXP)) \ + && !FP_REG_P (SET_SRC (EXP)) \ + && GET_MODE_SIZE (GET_MODE (SET_SRC (EXP))) > 4 \ + && (GET_CODE (SET_SRC (EXP)) == REG \ + || GET_CODE (SET_SRC (EXP)) == MEM \ + || GET_CODE (SET_SRC (EXP)) == CONST_DOUBLE))\ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (XEXP (EXP, 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (EXP, 0); \ + cc_status.value2 = XEXP (EXP, 1); } } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { \ + if (ADDRESS_REG_P (XEXP (XVECEXP (EXP, 0, 0), 0))) \ + CC_STATUS_INIT; \ + else if (XEXP (XVECEXP (EXP, 0, 0), 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (XVECEXP (EXP, 0, 0), 0); \ + cc_status.value2 = XEXP (XVECEXP (EXP, 0, 0), 1); } } \ + else CC_STATUS_INIT; \ + if (cc_status.value2 != 0 \ + && ADDRESS_REG_P (cc_status.value2) \ + && GET_MODE (cc_status.value2) == QImode) \ + CC_STATUS_INIT; \ + if (cc_status.value2 != 0 \ + && !(cc_status.value1 && FPA_REG_P (cc_status.value1))) \ + switch (GET_CODE (cc_status.value2)) \ + { case PLUS: case MINUS: case MULT: case UMULT: \ + case DIV: case UDIV: case MOD: case UMOD: case NEG: \ + case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT: \ + case ROTATE: case ROTATERT: \ + if (GET_MODE (cc_status.value2) != VOIDmode) \ + cc_status.flags |= CC_NO_OVERFLOW; \ + break; \ + case ZERO_EXTEND: \ + case ZERO_EXTRACT: \ + /* (SET r1 (ZERO_EXTEND r2)) on this machine + ends with a move insn moving r2 in r2's mode. + Thus, the cc's are set for r2. + This can set N bit spuriously. */ \ + cc_status.flags |= CC_NOT_NEGATIVE; } \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + cc_status.value2 = 0; \ + if (((cc_status.value1 && FP_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FP_REG_P (cc_status.value2))) \ + && !((cc_status.value1 && FPA_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FPA_REG_P (cc_status.value2)))) \ + cc_status.flags = CC_IN_68881; } + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +do { if (cc_prev_status.flags & CC_IN_68881) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } while (0) + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpa0", "fpa1", "fpa2", "fpa3", "fpa4", "fpa5", "fpa6", "fpa7", \ + "fpa8", "fpa9", "fpa10", "fpa11", "fpa12", "fpa13", "fpa14", "fpa15", \ + "fpa16", "fpa17", "fpa18", "fpa19", "fpa20", "fpa21", "fpa22", "fpa23", \ + "fpa24", "fpa25", "fpa26", "fpa27", "fpa28", "fpa29", "fpa30", "fpa31", } + +/* How to renumber registers for dbx and gdb. + On the Sun-3, the floating point registers have numbers + 18 to 25, not 16 to 23 as they do in the compiler. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0r%.20g\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +/* Sun's assembler can't handle floating constants written as floating. + However, when cross-compiling, always use that in case format differs. */ + +#ifdef CROSS_COMPILER + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0r%.10g\n", (VALUE)) + +#else + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\t.long 0x%x\n", tem.l); \ + } while (0) + +#endif /* not CROSS_COMPILER */ + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovel %s,sp@-\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovel sp@+,%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\t.even\n"); \ + else if ((LOG) != 0) \ + abort (); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.skip %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.9g", (VALUE)) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.20g", (VALUE)) + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On the 68000, we use several CODE characters: + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax). + '!' for the cc register (used in an `and to cc' insn). + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather + than directly). Second part of 'y' below. + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. + 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs + CONST_DOUBLE's as SunFPA constant RAM registers if + possible, so it should not be used except for the SunFPA. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \ + || (CODE) == '+' || (CODE) == '@' || (CODE) == '!') + +/* This assumes the compiler is running on a big-endian machine. + The support for the other case is left for version 2. */ +#define PRINT_OPERAND_EXTRACT_FLOAT(X) \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); + +#ifdef CROSS_COMPILER +#define PRINT_OPERAND_PRINT_FLOAT(CODE, FILE) \ + ASM_OUTPUT_FLOAT_OPERAND (FILE, u1.f); +#else +#define PRINT_OPERAND_PRINT_FLOAT(CODE, FILE) \ +{ if (CODE == 'f') \ + ASM_OUTPUT_FLOAT_OPERAND (FILE, u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } +#endif + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ int i; \ + if (CODE == '.') ; \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "sp@-"); \ + else if (CODE == '+') fprintf (FILE, "sp@+"); \ + else if (CODE == '@') fprintf (FILE, "sp@"); \ + else if (CODE == '!') fprintf (FILE, "cc"); \ + else if (GET_CODE (X) == REG) \ + { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \ + fprintf (FILE, "%s:%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \ + else \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + } \ + else if (GET_CODE (X) == MEM) \ + { \ + output_address (XEXP (X, 0)); \ + if (CODE == 'd' && ! TARGET_68020 \ + && CONSTANT_ADDRESS_P (XEXP (X, 0)) \ + && !(GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) < 0x8000 \ + && INTVAL (XEXP (X, 0)) >= -0x8000)) \ + fprintf (FILE, ":l"); \ + } \ + else if ((CODE == 'y' || CODE == 'w') \ + && GET_CODE(X) == CONST_DOUBLE \ + && (i = standard_sun_fpa_constant_p (X))) \ + fprintf (FILE, "%%%d", i & 0x1ff); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + PRINT_OPERAND_EXTRACT_FLOAT (X); \ + u1.f = u.d; \ + PRINT_OPERAND_PRINT_FLOAT (CODE, FILE); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + PRINT_OPERAND_EXTRACT_FLOAT (X); \ + ASM_OUTPUT_DOUBLE_OPERAND (FILE, u.d); } \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that m68k.md + generates a label LInnn: on such an insn. */ +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "%s@", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "%s@(", reg_names[REGNO (breg)]); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + if (addr != 0 && ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s:l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d:w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc-1.40/config/tm-m88k.h b/gcc-1.40/config/tm-m88k.h new file mode 100644 index 0000000..1725c68 --- /dev/null +++ b/gcc-1.40/config/tm-m88k.h @@ -0,0 +1,1128 @@ +/* Definitions of target machine for GNU compiler, for the Motorola 88000 chip. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dm88000 -Dm88k" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (88k)"); + +/* Run-time compilation parameters selecting different hardware subsets. + + On the the m88000, we don't yet need any. */ + +extern int target_flags; + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + {{ "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 1 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the m88000. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For the m88000 we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + + the m88000 has 32 fullword registers. */ + +#define FIRST_PSEUDO_REGISTER 32 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + + On the 88000, these are: + Reg 0 = 0 (hardware). + Reg 1 = Subroutine return pointer (hardware). + [Reg 2-9 = Parameter registers (Motorola convention).] + Reg 25 = condition code register (Gnu). + Reg 26-29 = reserved by Motorola. + Reg 30 = frame pointer (software). + Reg 31 = stack pointer (software). */ +#define FIXED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 1, 1, 1, 1, 1, 0, 1} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 1, 1, 1, 1, 1, 0, 1} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the m88000, ordinary registers hold 32 bits worth; + a single floating point register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the m88000, the cpu registers can hold any mode, but doubles + (and larger) must start and an even register number boundary. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (GET_MODE_SIZE (MODE) <= 4 || ((REGNO) & 1) == 0) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == DFmode || (MODE1) == DImode) \ + == ((MODE2) == DFmode || (MODE2) == DImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* the m88000 pc isn't overloaded on a register that the compiler knows about. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 31 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 30 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 30 + +/* Register in which static-chain is passed to a function. */ +/* ??? */ +#define STATIC_CHAIN_REGNUM 10 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 2 +#define STRUCT_VALUE_STACK_PROTECT_REGNUM 3 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The 88000 has one kind of registers, hence two classes. */ + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {0, -1} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) ALL_REGS + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS ALL_REGS +#define BASE_REG_CLASS ALL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) NO_REGS + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For the m88000, `I' is used for the range of constants an insn + can actually contain. + `J' is used for the range which is just zero (since that is R0). + `K' is used for the 5-bit operand of a compare insns. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) (VALUE) < 0x10000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' && XINT (VALUE, 0) == 0 && XINT (VALUE, 1) == 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. + + Do not define this for the Motorola 88000. There are no + negative literals! */ +/* #define FRAME_GROWS_DOWNWARD */ + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the m88000, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* If BYTES is the size of arguments for a function call, + return the size of the argument block (which is BYTES suitably rounded). + Define this only on machines where the entire call block is allocated + before the args are stored into it. */ + +#define ROUND_CALL_BLOCK_SIZE(BYTES) \ + (((BYTES) + 7) & ~7) + +/* Offset of first parameter from the argument pointer register value. */ +/* For the 88000, this must be non-zero so that addresses of the parms + can always be distinguished. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* ?? On the m88000 the value is found in the second "output" register. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 2) + +/* ?? But the called function leaves it in the second "input" register. */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 2) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 2) + +/* 1 if N is a possible register number for a function value + as seen by the caller. + On the m88000, the first "output" reg is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2) + +/* 1 if N is a possible register number for function argument passing. + On the m88000, these are the "output" registers. */ + +#define FUNCTION_ARG_REGNO_P(N) ((N) <= 9 && (N) >= 2) + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the m88000, this is a single integer, which is a number of words + of arguments scanned so far (including the invisible argument, + if any, which holds the structure-value-address). + Thus 8 or more means all following args should go on the stack. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the m88000, the offset normally starts at 0, but starts at 4 bytes + when the function gets a structure-value-address as an + invisible first argument. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = ((FNTYPE) != 0 && aggregate_value_p ((FNTYPE)))) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4)) + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the m88000 the first eight words of args are normally in registers + and the rest are pushed. But any arg that won't entirely fit in regs + is pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(8 >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + ? gen_rtx (REG, (MODE), 2 + (CUM)) \ + : 0) + +/* Define where a function finds its arguments. + This would be different from FUNCTION_ARG if we had register windows. */ + +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ + FUNCTION_ARG (CUM, MODE, TYPE, NAMED) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int current_function_pretend_args_size; \ + extern int frame_pointer_needed; \ + int fsize = ((SIZE) + current_function_pretend_args_size + 7) & ~7; \ + int regno, nregs, i; \ + int offset = 0; \ + for (regno = 2, nregs = 0; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + nregs = (nregs + 1) & ~1; \ + if (regs_ever_live[1] + frame_pointer_needed + nregs) \ + { \ + if (fsize + 8 + nregs*4 < 0x10000) \ + offset = fsize; \ + fprintf (FILE, "\tsub r31,r31,%d\n", 8 + nregs*4 + offset); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tst r30,r31,%d\n", offset); \ + if (regs_ever_live[1]) \ + fprintf (FILE, "\tst r1,r31,%d\n", 4 + offset); \ + if (nregs) \ + for (regno = 2, nregs = 2; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + if (regno & 1 || !regs_ever_live[regno+1] || call_used_regs[regno+1])\ + fprintf (FILE, "\tst r%d,r31,%d\n", regno, offset + nregs++ * 4);\ + else \ + { \ + fprintf (FILE, "\tst.d r%d,r31,%d\n", regno, offset + nregs * 4);\ + regno += 1; nregs += 2; \ + } \ + if (offset || fsize == 0) /* do nothing. */ ; \ + else if ((unsigned) fsize < 0x10000) \ + fprintf (FILE, "\tsub r31,r31,%d\n", fsize); \ + else fprintf (FILE, "\tor.u r25,r0,hi16(%d)\n\tor r25,r0,lo16(%d)\n\tsub r31,r31,r25\n", fsize, fsize); \ + if (frame_pointer_needed) fprintf (FILE, "\tor r30,r0,r31\n"); \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + abort (); + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +extern int may_call_alloca; +extern int current_function_pretend_args_size; + +#define EXIT_IGNORE_STACK \ + (get_frame_size () != 0 \ + || may_call_alloca || current_function_pretend_args_size) + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int may_call_alloca; \ + int fsize = ((SIZE) + current_function_pretend_args_size + 7) & ~7; \ + int nregs, regno, i; \ + for (regno = 2, nregs = 0; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + if (frame_pointer_needed) \ + { \ + if ((unsigned) fsize < 0x10000) \ + fprintf (FILE, "\tadd r31,r30,%d\n", fsize); \ + else fprintf (FILE, "\tor.u r25,r0,hi16(%d)\n\tor r25,r0,lo16(%d)\n\tadd r31,r30,r25\n", fsize, fsize); \ + } \ + else if (fsize) fprintf (FILE, "\tadd r31,r31,%d\n", fsize); \ + if (nregs) \ + for (regno = 2, nregs = 2; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + if (regno & 1 || !regs_ever_live[regno+1] || call_used_regs[regno+1])\ + fprintf (FILE, "\tld r%d,r31,%d\n", regno, nregs++ * 4);\ + else \ + { \ + fprintf (FILE, "\tld.d r%d,r31,%d\n", regno, nregs * 4);\ + regno += 1; nregs += 2; \ + } \ + if (regs_ever_live[1]) \ + fprintf (FILE, "\tld r1,r31,4\n"); \ + else \ + fprintf (FILE, ";; r1 is set to go!\n"); \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tld r30,r31,0\n"); \ + nregs = (nregs + 1) & ~1; \ + if (regs_ever_live[1] + frame_pointer_needed + (nregs > 2)) \ + fprintf (FILE, "\tjmp.n r1\n\taddu r31,r31,%d\n", nregs * 4); \ + else fprintf (FILE, "\tjmp r1\n"); \ + /* let insn reorganizer know that we are at the end of a function. */ \ + fprintf (FILE, "\tdata\n"); \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } + + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the the m88000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) (1) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) (1) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (1) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + On the m88000, the actual legitimate addresses must be REG+REG or REG+SMALLINT. + But we can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. */ + +#define INT_FITS_16_BITS(I) ((unsigned) (I) < 0x10000) + +#define FITS_16_BITS(X) \ + (GET_CODE (X) == CONST_INT && INT_FITS_16_BITS (INTVAL (X))) + +#define LEGITIMATE_INDEX_P(X, MODE) \ + (FITS_16_BITS (X) \ + || (REG_P (X) \ + && REG_OK_FOR_INDEX_P (X)) \ + || (GET_CODE (X) == MULT \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == GET_MODE_SIZE (MODE))) \ + || (GET_CODE (X) == MULT \ + && REG_P (XEXP (X, 1)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1)) \ + && GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (INTVAL (XEXP (X, 0)) == GET_MODE_SIZE (MODE)) \ + && (warning ("MULT backwards"), 1))) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + if (GET_CODE (X) == CONST_INT) \ + { \ + if (FITS_16_BITS (X)) \ + goto ADDR; \ + } \ + else if (CONSTANT_ADDRESS_P (X)) \ + goto ADDR; \ + else if (REG_P (X)) \ + { \ + if (REG_OK_FOR_BASE_P (X)) \ + goto ADDR; \ + } \ + else if (GET_CODE (X) == PLUS) \ + if (REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (LEGITIMATE_INDEX_P (XEXP (X, 1), MODE)) \ + goto ADDR; \ + } \ + else if (REG_P (XEXP (X, 1)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + { \ + if (LEGITIMATE_INDEX_P (XEXP (X, 0), MODE)) \ + goto ADDR; \ + } \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. */ + +/* On the m88000, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (memory_address_p (MODE, X)) \ + goto WIN; } + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the the m88000 this is never true. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if a raw index is all that is needed for a + `tablejump' insn. */ +#define CASE_TAKES_INDEX_RAW + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Do not break .stabs pseudos into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE SImode + +/* Define this if addresses of constant functions + shouldn't be put through pseudo regs where they can be cse'd. + Desirable on machines where ordinary constants are expensive + but a CALL with constant address is cheap. */ +#define NO_FUNCTION_CSE + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if ((unsigned) INTVAL (RTX) < 0x10000) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* Tell emit-rtl.c how to initialize special values on a per-function bass. */ +extern int optimize; +extern struct rtx_def *cc0_reg_rtx; + +typedef struct { struct rtx_def *ccr; } cc_status_mdep; +#define CC_STATUS_MDEP cc_status_mdep + +#define INIT_EMIT_MDEP \ +{ \ + cc0_reg_rtx = gen_rtx (REG, SImode, 25); \ +} + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +#define CC_IN_FCCR 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_DEST (EXP)) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { if ((cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1))) \ + cc_status.value1 = 0; \ + if ((cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2))) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if ((cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1))) \ + cc_status.value1 = 0; \ + if ((cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2))) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + printf ("here!\n", cc_status.value2 = 0); \ +} + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\ttext" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\tdata" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r30", "r31"} + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs ("\tglobal\t", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "@%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*@%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\tdouble %.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\tfloat %.12e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tword "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `short' and `char' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\thalf "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tbyte 0x%x\n", (VALUE)) + +#define ASM_OUTPUT_ASCII(FILE, P, SIZE) \ + output_ascii (FILE, P, SIZE) + +#define ASM_OUTPUT_ADDR_VEC_PROLOGUE(FILE, MODE, LEN) \ + fprintf (FILE, "\tjmp r1\n"); + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t@L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (the m88000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tword @L%d-@L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) != 0) \ + fprintf (FILE, "\talign %d\n", 1<<(LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tzero %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fprintf ((FILE), "\talign %d\n", (SIZE) <= 4 ? 4 : 8), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ":\n\tzero %u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On the m88000, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "0r%.9g", u1.f); \ + else \ + fprintf (FILE, "0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "0r%.20g", u.d); } \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "r0"); \ + else { output_addr_const (FILE, X); }} + +/* Print a memory address as an operand to reference that memory location. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx base, index = 0; \ + register rtx addr = ADDR; \ + register rtx reg0, reg1; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "r0,%s", reg_names[REGNO (addr)]); \ + break; \ + case PLUS: \ + reg0 = XEXP (addr, 0); \ + reg1 = XEXP (addr, 1); \ + if (GET_CODE (reg0) == MULT) \ + { rtx tmp = reg0; reg0 = reg1; reg1 = tmp; } \ + if (REG_P (reg0)) \ + if (REG_P (reg1)) \ + fprintf (FILE, "%s,%s", \ + reg_names[REGNO (reg0)], \ + reg_names[REGNO (reg1)]); \ + else if (GET_CODE (reg1) == CONST_INT) \ + { \ + int offset = INTVAL (reg1); \ + fprintf (FILE, "%s,%d", reg_names[REGNO (reg0)], offset); \ + } \ + else if (GET_CODE (reg1) == MULT) \ + fprintf (FILE, "%s[%s]", \ + reg_names[REGNO (reg0)], \ + reg_names[REGNO (XEXP (reg1, 0))]); \ + else fatal ("bad XEXP (1) to PRINT_OPERAND_ADDRESS"); \ + else fatal ("unknown PLUS case in PRINT_OPERAND_ADDRESS"); \ + break; \ + case MULT: \ + fprintf (FILE, "r0[%s]", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + default: \ + fprintf (FILE, "r0,"); \ + output_addr_const (FILE, addr); \ + }} + diff --git a/gcc-1.40/config/tm-mips-bsd.h b/gcc-1.40/config/tm-mips-bsd.h new file mode 100644 index 0000000..0659703 --- /dev/null +++ b/gcc-1.40/config/tm-mips-bsd.h @@ -0,0 +1,3 @@ +#define MIPS_BSD43 + +#include "tm-mips.h" diff --git a/gcc-1.40/config/tm-mips-news.h b/gcc-1.40/config/tm-mips-news.h new file mode 100644 index 0000000..c42e055 --- /dev/null +++ b/gcc-1.40/config/tm-mips-news.h @@ -0,0 +1,19 @@ +/* like pmax except BIG ENDIAN instead of LITTLE ENDIAN */ + +#define MIPS_NEWS +#include "tm-mips.h" + +#undef CPP_SPEC + /* default RISC NEWS environment */ +#define CPP_SPEC "-Dr3000 -DLANGUAGE_C -DMIPSEB -DSYSTYPE_BSD -Dsony_news -Dunix -I/usr/include2.11" + +#undef MACHINE_TYPE +#define MACHINE_TYPE "Sony NEWS (RISC NEWS)" + +/* Define this if most significant byte of a word is the lowest numbered. +*/ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. +*/ +#define WORDS_BIG_ENDIAN diff --git a/gcc-1.40/config/tm-mips-sysv.h b/gcc-1.40/config/tm-mips-sysv.h new file mode 100644 index 0000000..d3fa7d1 --- /dev/null +++ b/gcc-1.40/config/tm-mips-sysv.h @@ -0,0 +1,5 @@ +#define MIPS_SYSV + +#include "tm-mips.h" + +#define TARGET_MEM_FUNCTIONS diff --git a/gcc-1.40/config/tm-mips.h b/gcc-1.40/config/tm-mips.h new file mode 100644 index 0000000..8a044a4 --- /dev/null +++ b/gcc-1.40/config/tm-mips.h @@ -0,0 +1,2309 @@ +/* Definitions of target machine for GNU compiler. MIPS version. + Contributed by A. Lichnewsky, lich@inria.inria.fr + Changes by Michael Meissner, meissner@osf.org + Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* ??? This file needs to be reformatted so that it looks like the + rest of GCC. ??? */ + +/*---------------------------------------------------------------------- + +SWITCHES: + + -O optimization. Implies -mgpOPT + -O1 Same as -O, mips compatibility + -O2 Implies -O -fomit-frame-pointer -fstrength-reduce + -O3 Implies -O2 + -finline-functions + + -mG0 -mG1 -mG2 + Construct a size to be passed to GCC for Data / Sdata selection. + + Value is ( (i=G0 + 2 G1 + 4 G2) , (i < 6) ? ( 1<<i) :(1 <<(i+3))) + Same value should be passed to as + ld using -G. Use -G instead + since it is now supported. + + Default = -mG1 -mG0 (Value = 8). + + -G32 Implies -G 32 -mG2 -mnG1 -mG0. + + + -bestGnum + Pass -bestGnum flag to ld. This helps setting best value for + the -G parameter. + + -ZSYSV for RISC-OS: use the System V environment + -ZBSD43 for RISC-OS: use the BSD 4.3 environment +----------------------------------------------------------------------*/ + + + +/* Suppression of libg.a when debugging */ +#define NO_LIBG + + +/* Switch Recognition by gcc.c */ + +#ifdef SWITCH_TAKES_ARG +#undef SWITCH_TAKES_ARG +#endif + +#define SWITCH_TAKES_ARG(CHAR) \ + ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \ + || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \ + || (CHAR) == 'I' || (CHAR) == 'Y' || (CHAR) == 'm' \ + || (CHAR) == 'L' || (CHAR) == 'i' || (CHAR) == 'A' \ + || (CHAR) == 'G') + +/* Process -mGxx switches */ + +extern void overide_options (); + +#define OVERRIDE_OPTIONS overide_options () + + +/* Names to predefine in the preprocessor for this target machine. */ + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmips -Dunix -Dhost_mips -DMIPSEB -DR3000 -DLANGUAGE_C" +#endif + +/* Extra switches sometimes passed to the assembler. */ + +#ifndef ASM_SPEC +#ifndef OSF_OS /* normal MIPS system */ +#ifndef DECSTATION /* big endian MIPS (MIPS, SGI) */ +#ifndef SGI_TARGET /* not Silicon Graphics (ie, MIPSco) */ + +#define ASM_SPEC "%{!mrnames:-nocpp} \ + %{!mgas: \ + %{pipe: %e-pipe is not supported.} \ + %{EB} %{!EB:-EB} \ + %{EL: %e-EL not supported} \ + %{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3} \ + %{g} %{g1} %{g2} %{g3} %{g0}} \ + %{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32: -G 32}} \ + %{v} %{K}" + +#else /* Silicon Graphics */ +#define ASM_SPEC "%{!mrnames:-nocpp} \ + %{!mgas: \ + %{pipe: %e-pipe is not supported.} \ + %{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3} \ + %{g} %{g1} %{g2} %{g3} %{g0}} \ + %{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32: -G 32}} \ + %{v} %{K}" + +#endif /* Silicon Graphics */ +#else /* Ultrix Decstation (little endian) */ +#define ASM_SPEC "%{!mrnames:-nocpp} \ + %{!mgas: \ + %{pipe:%e:-pipe not supported} \ + %{EL} %{!EL:-EL} \ + %{EB: %e-EB not supported} \ + %{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3} \ + %{g} %{g1} %{g2} %{g3} %{g0}} \ + %{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32: -G 32}} \ + %{v} %{K}" +#endif /* DECstation running Ultrix */ +#else /* OSF/1 of some sort */ +#ifndef DECSTATION + /* Big endian MIPS running OSF/1 */ +#define ASM_SPEC "%{mmips-as: \ + %{pipe:%e:-pipe not supported} \ + %{EB} %{!EB:-EB} \ + %{EL: %e-EL not supported} \ + %{!mrnames:-nocpp} \ + %{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3} \ + %{g} %{g1} %{g2} %{g3} %{g0} \ + %{v} %{K}} \ + %{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{!mmips-as:-G 0} \ + %{!pic:%{!mpic:%{mmips-as:-G 8}}}} \ + %{G32: -G 32}}" +#else + /* Little endian OSF/1 Decstation */ +#define ASM_SPEC "%{mmips-as: \ + %{pipe:%e:-pipe not supported} \ + %{EL} %{!EL:-EL} \ + %{EB: %e-EB not supported} \ + %{!mrnames:-nocpp} \ + %{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3} \ + %{g} %{g1} %{g2} %{g3} %{g0} \ + %{v} %{K}} \ + %{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{!mmips-as:-G 0} \ + %{!pic:%{!mpic:%{mmips-as:-G 8}}}} \ + %{G32: -G 32}}" + +#endif /* little endian OSF/1 DECstation */ +#endif /* OSF/1 */ +#endif /* ASM_SPEC */ + +/* Redefinition of libraries used. Mips doesn't support normal + UNIX style profiling via calling _mcount. It does offer + profiling that samples the PC, so do what we can... */ + +#ifndef LIB_SPEC +#define LIB_SPEC "%{pg:%e-pg is not supported on the MIPS}%{p:-lprof1} -lc" +#endif + +/* Inhibit use of -lg. */ +#define LIBG_SPEC "" + +/* Extra switches sometimes passed to the loader. */ + + +#ifndef LINK_SPEC +#ifdef MIPS_SYSV /* RISC-OS SYSTEM V */ + +#ifndef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt1.o%s crtn.o%s}}" +#endif + +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{bestGnum} \ + %{!ZBSD43:-systype /sysv/}%{ZBSD43:-systype /bsd43/} \ + %{EB} %{!EB:-EB} %{EL:%e-EL not supported}" + +#else /* RISC-OS SYSTEM V */ +#ifdef MIPS_BSD43 /* RISC-OS BSD */ + +#ifndef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt1.o%s crtn.o%s}}" +#endif + +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{bestGnum} \ + %{!ZSYSV:-systype /bsd43/}%{ZSYSV:-systype /sysv/} \ + %{EB} %{!EB:-EB} %{EL:%e-EL not supported}" + +#else + +#ifndef DECSTATION /* Big endian BSD or OSF/1 system */ +#ifndef OSF_OS /* Big endian BSD system */ +#ifndef SGI_TARGET /* Big endian non Silicon Graphics system */ + +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{!mgas: %{EB} %{!EB:-EB} %{EL:%e-EL not supported} \ + %{bestGnum}}" + +#else /* Silicon graphics system */ +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{!mgas: %{bestGnum}}" + +#endif /* Silicon Graphics system */ +#else /* Big endian OSF/1 system */ +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{!mmips-as:-G 0} \ + %{!pic:%{!mpic:%{mmips-as:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{mmips-as: %{EB} %{!EB:-EB} %{EL:%e-EL not supported} \ + %{bestGnum}} \ + %{nostdlib}" +#endif /* Big endian BSD or OSF/1 system */ + +#else /* Little endian Ultrix or OSF/1 */ +#ifndef OSF_OS /* Little endian Ultrix system */ +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{mgas:-G 0} \ + %{!pic:%{!mpic:%{!mgas:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{!mgas: %{EL} %{!EL:-EL} %{EB:%e-EB not supported} \ + %{bestGnum}}" + +#else /* Little endian OSF/1 system */ +#define LINK_SPEC "%{G*} \ + %{!G:%{!G32: %{mpic:-G 0} %{pic:-G 0} \ + %{!mmips-as:-G 0} \ + %{!pic:%{!mpic:%{mmips-as:-G 8}}}} \ + %{G32:-G 32}} \ + %{!G:%{!G32: \ + %{mG0:%eYou should include ld/as option -G} \ + %{mG1:%eYou should include ld/as option -G} \ + %{mG2:%eYou should include ld/as option -G}}} \ + %{mmips-as: %{EL} %{!EL:-EL} %{EB:%e-EB not supported} \ + %{bestGnum}} \ + %{nostdlib}" + +#endif /* Little endian OSF/1 system */ +#endif /* Little endian BSD or OSF/1 system */ +#endif /* RISC-OS BSD */ +#endif /* RISC-OS SYSTEM V */ +#endif /* LINK_SPEC defined */ + +/* CC1 SPECS */ + +#define CC1_SPEC "%{O: %{!mngpOPT:-mgpOPT}} \ + %{O1:-O %{!mngpOPT:-mgpOPT}} \ + %{O2:-O %{!fnostrength-reduce:-fstrength-reduce} \ + %{!fnoomit-frame-pointer:-fomit-frame-pointer} \ + %{!mngpOPT:-mgpOPT}} \ + %{O3:-O %{!fnostrength-reduce:-fstrength-reduce} \ + %{!fnoomit-frame-pointer:-fomit-frame-pointer} \ + %{!fnoinline-functions:-finline-functions} \ + %{!mngpOPT:-mgpOPT}} \ + %{O4:%eGCC does not support -O4} \ + %{!g: %{g1:-g} %{g2:-g} %{g3:-g}} \ + %{G32: -mG2 -mnG1 }" + +/* CPP SPECS */ + +#ifndef DECSTATION + +#ifdef SGI_TARGET /* Silicon Graphics */ +#define CPP_SPEC " %{!ansi:-D__EXTENSIONS__} \ + -D_MIPSEB -D_SYSTYPE_SYSV -D_LANGUAGE_C \ + %{O1:-D__OPTIMIZE__} \ + %{O2:-D__OPTIMIZE__} \ + %{O3:-D__OPTIMIZE__}" + +#else +#if defined(MIPS_SYSV) || defined(MIPS_BSD43) + /* MIPS RISC-OS environments */ + +#ifdef MIPS_SYSV +#define CPP_SPEC " %{!ansi:%{!ZBSD43:-DSYSTYPE_SYSV}%{ZBSD43:-DSYSTYPE_BSD43}}\ + %{!ZBSD43:-D__SYSTYPE_SYSV__}%{ZBSD43:-D__SYSTYPE_BSD43__} \ + %{O1:-D__OPTIMIZE__} \ + %{O2:-D__OPTIMIZE__} \ + %{O3:-D__OPTIMIZE__}" +#else /* not MIPS_SYSV */ + +/* Use this instead of a conditional -I in CPP_SPEC + because -I adds the dir in the wrongplace in the search path. */ +#define CC_INCLUDE_DIR "/bsd43/usr/include" + +#define CPP_SPEC " %{!ansi:%{!ZSYSV:-DSYSTYPE_BSD43}%{ZSYSV:-DSYSTYPE_SYSV}}\ + %{!ZSYSV:-D__SYSTYPE_BSD43__}%{ZSYSV:-D__SYSTYPE_SYSV__}\ + %{O1:-D__OPTIMIZE__} \ + %{O2:-D__OPTIMIZE__} \ + %{O3:-D__OPTIMIZE__}" + +#endif /* not MIPS_SYSV */ + +#else /* not MIPS_SYSV and not MIPS_BSD43 */ + /* default MIPS Bsd environment */ +#define CPP_SPEC "%{!ansi:-DSYSTYPE_BSD} -D__SYSTYPE_BSD__ \ + %{O1:-D__OPTIMIZE__} \ + %{O2:-D__OPTIMIZE__} \ + %{O3:-D__OPTIMIZE__}" + +#endif /* not MIPS_SYSV and not MIPS_BSD43 */ +#endif /* not Silicon Graphics */ + +#else /* DECSTATION */ +#define CPP_SPEC "%{O1:-D__OPTIMIZE__} \ + %{O2:-D__OPTIMIZE__} \ + %{O3:-D__OPTIMIZE__}" + +#endif /* not DECSTATION */ + +/* Print subsidiary information on the compiler version in use. */ + +#ifndef __DATE__ +#define __DATE__ "[unknown date]" +#endif + +#define MIPS_VERSION "AL-MIPS 1.1" + +#ifdef DECSTATION +#ifdef OSF_OS +#define MACHINE_TYPE "OSF/1 Dec Mips" +#else +#define MACHINE_TYPE "Ultrix Dec Mips" +#endif + +#else +#ifdef SGI_TARGET +#define MACHINE_TYPE "Sgi Mips" + +#else +#if defined(MIPS_SYSV) || defined(MIPS_BSD43) + /* MIPS RISC-OS environments */ +#ifdef MIPS_SYSV +#define MACHINE_TYPE "RISC-OS System V Mips" + +#else /* not MIPS_SYSV */ +#define MACHINE_TYPE "RISC-OS BSD Mips" + +#endif /* not MIPS_SYSV */ +#else /* not MIPS_SYSV and not MIPS_BSD43 */ + /* default MIPS Bsd environment */ +#define MACHINE_TYPE "BSD Mips" +#endif /* not SGI iris */ +#endif /* not MIPS_SYSV and not MIPS_BSD43 */ +#endif /* not DECSTATION */ + +#define TARGET_VERSION \ +{ \ + fprintf (stderr, " %s %s %s", MIPS_VERSION, MACHINE_TYPE, __DATE__); \ +} + + +#define SDB_DEBUGGING_INFO /* generate debug info inside of comments */ +#define MIPS_DEBUGGING_INFO /* MIPS specific debugging info */ + +/* On Sun 4, this limit is 2048. We use 1500 to be safe, + since the length can run past this up to a continuation point. */ +#define DBX_CONTIN_LENGTH 1500 + + +/* How to renumber registers for dbx and gdb. + MIPS needs no change in the numeration. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + + +/* Overides for the COFF debug format. */ +#define PUT_SDB_SCL(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.scl\t%d;", (a)); \ +} while (0) + +#define PUT_SDB_INT_VAL(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.val\t%d;", (a)); \ +} while (0) + +#define PUT_SDB_VAL(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fputs ("\t.val\t", asm_out_text_file); \ + output_addr_const (asm_out_text_file, (a)); \ + fputc (';', asm_out_text_file); \ +} while (0) + +#define PUT_SDB_DEF(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t#.def\t"); \ + ASM_OUTPUT_LABELREF (asm_out_text_file, a); \ + fputc (';', asm_out_text_file); \ +} while (0) + +#define PUT_SDB_PLAIN_DEF(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t#.def\t.%s;", (a)); \ +} while (0) + +#define PUT_SDB_ENDEF \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.endef\n"); \ +} while (0) + +#define PUT_SDB_TYPE(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.type\t0x%x;", (a)); \ +} while (0) + +#define PUT_SDB_SIZE(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.size\t%d;", (a)); \ +} while (0) + +#define PUT_SDB_DIM(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.dim\t%d;", (a)); \ +} while (0) + +#ifndef PUT_SDB_START_DIM +#define PUT_SDB_START_DIM \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.dim\t"); \ +} while (0) +#endif + +#ifndef PUT_SDB_NEXT_DIM +#define PUT_SDB_NEXT_DIM(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "%d,", a); \ +} while (0) +#endif + +#ifndef PUT_SDB_LAST_DIM +#define PUT_SDB_LAST_DIM(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "%d;", a); \ +} while (0) +#endif + +#define PUT_SDB_TAG(a) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, "\t.tag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_text_file, a); \ + fputc (';', asm_out_text_file); \ +} while (0) + +/* For block start and end, we create labels, so that + later we can figure out where the correct offset is. + The normal .ent/.end serve well enough for functions, + so those are just commented out. */ + +#define PUT_SDB_BLOCK_START(LINE) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, \ + "$Lb%d:\n\t#.begin\t$Lb%d\t%d\n", \ + sdb_label_count, \ + sdb_label_count, \ + (LINE)); \ + sdb_label_count++; \ +} while (0) + +#define PUT_SDB_BLOCK_END(LINE) \ +do { \ + extern FILE *asm_out_text_file; \ + fprintf (asm_out_text_file, \ + "$Le%d:\n\t#.bend\t$Le%d\t%d\n", \ + sdb_label_count, \ + sdb_label_count, \ + (LINE)); \ + sdb_label_count++; \ +} while (0) + +#define PUT_SDB_FUNCTION_START(LINE) + +#define PUT_SDB_FUNCTION_END(LINE) + +#define PUT_SDB_EPILOGUE_END(NAME) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), ".%dfake", (NUMBER)); + + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + + /* Mips vs. GNU assembler */ +#define TARGET_UNIX_ASM (target_flags & 0x00000001) +#define TARGET_MIPS_AS TARGET_UNIX_ASM +#define TARGET_GAS (TARGET_UNIX_ASM == 0) + + /* Debug Mode */ +#define TARGET_DEBUG_MODE (target_flags & 0x00000002) +#define TARGET_DEBUGA_MODE (target_flags & 0x00000004) +#define TARGET_DEBUGB_MODE (target_flags & 0x00000010) +#define TARGET_DEBUGC_MODE (target_flags & 0x00000020) +#define TARGET_DEBUGD_MODE (target_flags & 0x00000040) +#define TARGET_DEBUGE_MODE (target_flags & 0x00008000) + + /* Reg. Naming in .s ($21 vs. $a0) */ +#define TARGET_NAME_REGS (target_flags & 0x00000008) + + /* addu/subbu vs. add/sub */ +#define TARGET_NOFIXED_OVFL (target_flags & 0x00000080) + + /* Optimize for Sdata/Sbss */ +#define TARGET_GP_OPT (target_flags & 0x00001000) +#define TARGET_GVALUE_MASK (target_flags & 0x00000f00) +#define TARGET_GVALUE (TARGET_GVALUE_MASK >> 8) + + /* Position independent code */ +#define TARGET_PIC (target_flags & 0x00002000) +#define TARGET_PIC_LARGE_OBJECT (target_flags & 0x00004000) + + + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ +{ {"mips-as", 0x00000001}, /* MIPS assembler */ \ + {"gas", -0x00000001}, /* GNU assembler */ \ + {"debug", 0x00000002}, /* Eliminate version in output*/ \ + {"nodebug", -0x00000002}, \ + {"debuga", 0x00000004}, /* don't fold SP pushes into frame */ \ + {"nodebuga", -0x00000004}, \ + {"debugb", 0x00000010}, /* GO_IF_LEGITIMATE_ADDRESS debug */ \ + {"nodebugb", -0x00000010}, \ + {"debugc", 0x00000020}, /* fix frame ptr debug */ \ + {"nodebugc", -0x00000020}, \ + {"debugd", 0x00000040}, /* branch/cc0 debug */ \ + {"nodebugd", -0x00000040}, \ + {"rnames", 0x00000008}, /* Register names like $a0 */ \ + {"nornames", -0x00000008}, /* Register names like $21 */ \ + {"nofixed-ovfl", 0x00000080}, /* Use addu and subu */ \ + {"fixed-ovfl", -0x00000080}, /* Use add and sub */ \ + {"G0", 0x00000100}, /* Bit 1 of sdata size */ \ + {"nG0", -0x00000100}, \ + {"noG0", -0x00000100}, \ + {"G1", 0x00000200}, /* Bit 2 of sdata size */ \ + {"nG1", -0x00000200}, \ + {"noG1", -0x00000200}, \ + {"G2", 0x00000400}, /* Bit 3 of sdata size */ \ + {"nG2", -0x00000400}, \ + {"noG2", -0x00000400}, \ + {"gpOPT", 0x00001000}, /* Optimize for global ptr */ \ + {"ngpOPT", -0x00001000}, \ + {"nogpOPT", -0x00001000}, \ + {"pic", 0x00002000}, /* Position independent code */ \ + {"npic", -0x00002000}, \ + {"nopic", -0x00002000}, \ + {"pic-large-object", 0x00004000}, /* Don't opt pic local funcs */ \ + {"nopic-large-object", -0x00004000}, \ + {"debuge", 0x00008000}, /* FUNCTION_ARG debug */ \ + {"nodebuge", -0x00008000}, \ + {"", TARGET_DEFAULT}} + +/* Default target_flags if no switches specified (-mmips-as, -mnofixed-ovfl, + -G0, -G1 [same as -G 8]). OSF/1 does not set -mmips-as, and sets -G 0. */ + +#ifndef OSF_OS +#define TARGET_DEFAULT 0x00000381 +#else +#define TARGET_DEFAULT 0x00000080 +#endif + +/* Default GVALUE (data item size threshold for selection of Sdata/data) + is computed : GVALUE == ( ((i=G0+2*G1+4*G2) < 6) + ? 1<<i + : 1<< (i+3)) +*/ + +/* Target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. +*/ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +#ifndef DECSTATION +#define BYTES_BIG_ENDIAN +#endif + +/* Define this if most significant word of a multiword number is numbered. */ +#ifndef DECSTATION +#define WORDS_BIG_ENDIAN +#endif + +/* Define macros to easily access the most and least significant words + without a lot of #ifdef's. */ + +#ifdef WORDS_BIG_ENDIAN +#define MOST_SIGNIFICANT_WORD 0 +#define LEAST_SIGNIFICANT_WORD 1 + +#else +#define MOST_SIGNIFICANT_WORD 1 +#define LEAST_SIGNIFICANT_WORD 0 +#endif + +/* Number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Give parms extra alignment, up to this much, if their types want it. */ +#define MAX_PARM_BOUNDARY 64 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* There is no point aligning anything to a rounder boundary than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Define this macro if an argument declared as `char' or `short' in a + prototype should actually be passed as an `int'. In addition to + avoiding errors in certain cases of mismatch, it also makes for + better code on certain machines. */ +#define PROMOTE_PROTOTYPES + + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + + On the MIPS, see conventions, page D-2 + + I have chosen not to take Multiply/Divide HI,LO or PC into + account. */ + +#define FIXED_REGISTERS {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ +} + + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ + +#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,\ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\ +} + + +/* Internal macros to classify a register number as to whether it's a + general purpose register or a floating point register. The macro + FP_CALL_REG_P also allows registers $4 and $6 as floating point + registers to pass floating point as per MIPS spec. */ + +#define GP_REG_FIRST 0 +#define GP_REG_LAST 31 +#define GP_REG_NUM (GP_REG_LAST - GP_REG_FIRST + 1) + +#define FP_REG_FIRST 32 +#define FP_REG_LAST 63 +#define FP_REG_NUM (FP_REG_LAST - FP_REG_FIRST + 1) + +#define GP_REG_P(REGNO) ((unsigned) ((REGNO) - GP_REG_FIRST) < GP_REG_NUM) +#define FP_REG_P(REGNO) ((unsigned) ((REGNO) - FP_REG_FIRST) < FP_REG_NUM) + +#define FP_CALL_REG_P(REGNO) \ + (FP_REG_P (REGNO) \ + || (REGNO) == (4 + GP_REG_FIRST) \ + || (REGNO) == (6 + GP_REG_FIRST)) + + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the MIPS, all general registers are one word long. I have chosen to + use Floating point register pairs. */ + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((MODE == SFmode) ? 2 : \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the MIPS, all general registers can hold all modes, except + FLOATING POINT. */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_INT || MODE == VOIDmode) \ + ? (GP_REG_P (REGNO)) \ + : (GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + ? (((REGNO) & 1) == 0 && FP_CALL_REG_P (REGNO)) \ + : 0) \ + + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ( ((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* MIPS pc is apparently not overloaded on a register. */ +/* #define PC_REGNUM 15 */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 29 + +/* Offset from the stack pointer to the first available location. */ +#define STACK_POINTER_OFFSET 0 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 30 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. + + At present this is required if we are not a leaf procedure. This + is because the .frame directive requires a register that does not + change throughout the procedure call, and until stack pushes are + folded into the initial stack allocation, we need an unvarying fp. */ +#define FRAME_POINTER_REQUIRED (stack_args_pushed > 0) + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 2 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 4 + +/* Mips registers used in prologue/epilogue code when the stack frame + is larger than 32K bytes. These registers must come from the + scratch register set, and not used for passing and returning + arguments and any other information used in the calling sequence + (such as pic). */ +#define MIPS_TEMP1_REGNUM 8 +#define MIPS_TEMP2_REGNUM 9 + +/* Define NO_FUNCTION_CSE if it is as good or better to call a constant + function address than to call an address kept in a register. */ +#define NO_FUNCTION_CSE + + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The MIPS has general and floating point registers. */ + + +enum reg_class { NO_REGS, GR_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES } ; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define GENERAL_REGS GR_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "GR_REGS", "FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {{0x00000000, 0x00000000}, \ + {0xffffffff, 0x00000000}, \ + {0x00000000, 0xffffffff}, \ + {0xffffffff, 0xffffffff}} + + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) ((FP_REG_P (REGNO)) ? FP_REGS : GR_REGS) + +/* Define a table that lets us find quickly all the reg classes + containing a given one. This is the initializer for an + N_REG_CLASSES x N_REG_CLASSES array of reg class codes. + Row N is a sequence containing all the class codes for + classes that contain all the regs in class N. Each row + contains no duplicates, and is terminated by LIM_REG_CLASSES. */ + +/* We give just a dummy for the first element, which is for NO_REGS. */ +/* #define REG_CLASS_SUPERCLASSES {{LIM_REG_CLASSES}, \ + {GR_REGS,ALL_REGS,LIM_REG_CLASSES}, \ + {FP_REGS,ALL_REGS,LIM_REG_CLASSES}, \ + {ALL_REGS,LIM_REG_CLASSES} \ +} +*/ +/* We give just a dummy for the first element, which is for NO_REGS. */ +#define REG_CLASS_SUPERCLASSES {{LIM_REG_CLASSES}, \ + {ALL_REGS,LIM_REG_CLASSES}, \ + {ALL_REGS,LIM_REG_CLASSES}, \ + {LIM_REG_CLASSES} \ +} + +/* The inverse relationship: + for each class, a list of all reg classes contained in it. */ +#define REG_CLASS_SUBCLASSES \ +{{LIM_REG_CLASSES}, \ + {GR_REGS,LIM_REG_CLASSES}, \ + {FP_REGS,LIM_REG_CLASSES},\ + {GR_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES}\ +} + +/* Define a table that lets us find quickly the class + for the subunion of any two classes. + + We say "subunion" because the result need not be exactly + the union; it may instead be a subclass of the union + (though the closer to the union, the better). + But if it contains anything beyond union of the two classes, + you will lose! + + This is an initializer for an N_REG_CLASSES x N_REG_CLASSES + array of reg class codes. The subunion of classes C1 and C2 + is just element [C1, C2]. */ + +#define REG_CLASS_SUBUNION \ +{{NO_REGS, GR_REGS, FP_REGS, ALL_REGS}, \ + {GR_REGS, GR_REGS, ALL_REGS, ALL_REGS}, \ + {FP_REGS, ALL_REGS, FP_REGS, ALL_REGS}, \ + {ALL_REGS, ALL_REGS, ALL_REGS, ALL_REGS}} + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GR_REGS +#define BASE_REG_CLASS GR_REGS + + + /* REGISTER AND CONSTANT CLASSES + */ + +/* Get reg_class from a letter such as appears in the machine +description. */ + /* DEFINED REGISTER CLASSES: + ** + ** 'f' : Floating point registers + ** 'y' : General register when used to + ** transfer chunks of Floating point + ** with mfc1 mtc1 insn + */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_REGS: \ + (C) == 'y' ? GR_REGS:NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. */ + +/* For MIPS, `I' is used for the range of constants an arithmetic insn + can actually contain (16 bits signed integers). + `J' is used for the range which is just zero (since that is + available as $R0). + `K' is used for the range of constants a logical insn + can actually contain (16 bit zero-extended integers). +*/ + +#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x8000) < 0x10000) +#define SMALL_INT_UNSIGNED(X) ((unsigned) (INTVAL (X)) < 0x10000) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) ((VALUE) + 0x8000) < 0x10000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x10000 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + + /* DEFINED FLOATING CONSTANT CLASSES: + ** + ** 'G' : Floating point 0 + */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (((GET_MODE(X) == SFmode) || (GET_MODE(X) == DFmode))? FP_REGS : \ + ((GET_MODE(X) == VOIDmode) ? GR_REGS :(CLASS))) + +/* Same but Mode has been extracted already +*/ + +#define PREFERRED_RELOAD_CLASS_FM(X,CLASS) \ + ((((X) == SFmode) || ((X) == DFmode))? FP_REGS : \ + (((X) == VOIDmode) ? GR_REGS :(CLASS))) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((((MODE) == DFmode) || ((MODE) == SFmode)) ? 2 \ + : ((MODE) == VOIDmode)? ((CLASS) == FP_REGS ? 2 :1) \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET -8 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the vax, sp@- in a byte insn really pushes a word. */ + +/* #define PUSH_ROUNDING(BYTES) 0 */ + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Offset from top-of-stack address to location to store the + function parameter if it can't go in a register. + Addresses for following parameters are computed relative to this one. + + It also has the effect of counting register arguments in the total + argument size. */ +#define FIRST_PARM_CALLER_OFFSET(FNDECL) 0 + +/* When a parameter is passed in a register, stack space is still + allocated for it. For the MIPS, stack space must be allocated, cf + Asm Lang Prog Guide page 7-8. + + BEWARE that some space is also allocated for non existing arguments + in register. In case an argument list is of form GF used registers + are a0 (a2,a3), but we should push over a1... */ +#define REG_PARM_STACK_SPACE + +/* Align stack frames on 64 bits (Double Word ). */ +#define STACK_BOUNDARY 64 + + +/* Standard GCC stack related variables that we reference. */ + +extern int optimize; +extern int may_call_alloca; +extern int current_function_calls_alloca; +extern int frame_pointer_needed; +extern int flag_omit_frame_pointer; + +/* MIPS external variables defined in out-mips.c. */ + +extern char *reg_numchar[]; /* register names as $r2, etc. */ +extern char *current_function_name; /* current function being compiled */ +extern int num_source_filenames; /* current .file # */ +extern int inside_function; /* != 0 if inside of a function */ +extern int stack_args_pushed; /* max bytes pushed for calls */ +extern int stack_args_preallocated; /* # bytes for args preallocated */ +extern int sdb_label_count; /* block start/end next label # */ +extern int mips_section_threshold; /* # bytes of data/sdata cutoff */ +extern int sym_lineno; /* sgi next label # for each stmt */ + + +/* Make sure 16 bytes are always allocated on the stack. */ +#ifndef STACK_ARGS_ADJUST +#define STACK_ARGS_ADJUST(SIZE) \ +{ \ + if (SIZE.constant < 16) \ + SIZE.constant = 16; \ +} +#endif + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + + +/* Symbolic macros for the registers used to return integer and floating + point values. */ + +#define GP_RETURN 2 +#define FP_RETURN 32 + +/* Symbolic macros for the first/last argument registers. */ + +#define GP_ARG_FIRST 4 +#define GP_ARG_LAST 7 +#define FP_ARG_FIRST 44 +#define FP_ARG_LAST 47 + +#define MAX_ARGS_IN_REGISTERS 4 + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, MODE, \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + ? FP_RETURN \ + : GP_RETURN) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + + +/* 1 if N is a possible register number for a function value. + On the MIPS, R2 R3 and F0 F2 are the only register thus used. + Currently, R2 and F0 are only implemented here (C has no complex type) */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN) + +/* 1 if N is a possible register number for function argument passing. */ + +#define FUNCTION_ARG_REGNO_P(N) (((N) >= GP_ARG_FIRST && (N) <= GP_ARG_LAST) \ + || ((N) >= FP_ARG_FIRST && (N) <= FP_ARG_LAST \ + && (0 == (N) % 2))) + +/* A C expression which can inhibit the returning of certain function + values in registers, based on the type of value. A nonzero value says + to return the function value in memory, just as large structures are + always returned. Here TYPE will be a C expression of type + `tree', representing the data type of the value. + + Note that values of mode `BLKmode' are returned in memory + regardless of this macro. Also, the option `-fpcc-struct-return' + takes effect regardless of this macro. On most systems, it is + possible to leave the macro undefined; this causes a default + definition to be used, whose value is the constant 0. + + GCC normally converts 1 byte structures into chars, 2 byte + structs into shorts, and 4 byte structs into ints, and returns + them this way. Defining the following macro overides this, + to give us MIPS cc compatibility. */ + +#define RETURN_IN_MEMORY(TYPE) \ + ((TREE_CODE (TYPE) == RECORD_TYPE) || (TREE_CODE (TYPE) == UNION_TYPE)) + + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. +*/ + +typedef struct mips_args { + int gp_reg_found; + int arg_number; + int arg_words; +} *CUMULATIVE_ARGS; + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + +*/ + +extern void init_cumulative_args (); + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ +do { \ + CUM = (CUMULATIVE_ARGS) alloca (sizeof (*CUM)); \ + init_cumulative_args (CUM, FNTYPE); \ +} while (0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (function_arg_advance(CUM, MODE, TYPE, NAMED)) + +extern void function_arg_advance(); + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +extern struct rtx_def *function_arg (); + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + (function_arg(CUM, MODE, TYPE, NAMED)) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. +*/ + +extern int function_arg_partial_nregs (); + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ + (function_arg_partial_nregs (CUM, MODE, TYPE, NAMED)) + + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +extern void function_prologue (); + +#define FUNCTION_PROLOGUE(FILE, SIZE) function_prologue(FILE, SIZE) + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. */ + +extern void function_epilogue (); + +#define FUNCTION_EPILOGUE(FILE, SIZE) function_epilogue(FILE, SIZE) + +/* Tell prologue and epilogue if Register containing return + address should be saved / restored. */ + +#define MUST_SAVE_REGISTER(regno) \ + ((regs_ever_live[regno] && !call_used_regs[regno]) || \ + (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) || \ + (regno == 31 && regs_ever_live[31])) + +/* ALIGN FRAMES on double word boundaries */ + +#define AL_ADJUST_ALIGN(LOC) (((LOC)+7) & 0xfffffff8) + + +/* If the memory Address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer. This is for + when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ ADDR = mips_fix_frame_pointer(ADDR, DEPTH); } + +extern struct rtx_def *mips_fix_frame_pointer (); + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + register char **reg_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + \ + fprintf (FILE, "\t.set\tnoreorder\n"); \ + fprintf (FILE, "\t.set\tnoat\n"); \ + fprintf (FILE, "\tmove\t%s,%s\t\t# save current return address\n", \ + reg_ptr[1], reg_ptr[31]); \ + fprintf (FILE, "\tjal\t_mcount\n"); \ + fprintf (FILE, "\tsubu\t%s,%s,8\t\t# _mcount pops 2 words from stack\n", \ + reg_ptr[STACK_POINTER_REGNUM], reg_ptr[STACK_POINTER_REGNUM]); \ + fprintf (FILE, "\t.set\treorder\n"); \ + fprintf (FILE, "\t.set\tat\n"); \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 1 + + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + These definitions are NOT overridden anywhere. */ + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) + +#define REGNO_OK_FOR_BASE_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects them all. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Some source files that are used after register allocation + need to be strict. */ + +#ifndef REG_OK_STRICT + +#define REG_OK_FOR_INDEX_P(X) 1 /* ok if index or pseudo reg */ +#define REG_OK_FOR_BASE_P(X) 1 /* ok if base reg. of pseudo reg */ + +#else + +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 1 + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is actually machine-independent. */ + +/* 1 if X is an address that we could indirect through. */ +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && ((xplus0 = XEXP (X, 0)), \ + (xplus1 = XEXP (X, 1)), \ + ((GET_CODE (xplus0) != REG && GET_CODE (xplus1) == REG) \ + ? ((xplus0 = XEXP (X, 1)), (xplus1 = XEXP (X, 0))) \ + : 0), \ + GET_CODE (xplus0) == REG) \ + && REG_OK_FOR_BASE_P (xplus0) \ + && ((GET_CODE (xplus1) == CONST_INT && SMALL_INT (xplus1)) \ + || (GET_CODE (xplus1) == LABEL_REF) \ + || (GET_CODE (xplus1) == SYMBOL_REF) \ + || (GET_CODE (xplus1) == CONST) \ + || (xplus0 == stack_pointer_rtx \ + && (GET_CODE (xplus1) == CONST || (GET_CODE (xplus1) == SYMBOL_REF)))))) + + +#if 1 +extern void trace (); +#define GO_PRINTF(x) trace(x) +#define GO_DEBUG_RTX(x) debug_rtx(x) + +#else +#define GO_PRINTF(x) +#define GO_DEBUG_RTX(x) +#endif + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + register rtx xinsn = (X); \ + register rtx xplus0, xplus1; \ + \ + if (TARGET_DEBUGB_MODE) \ + { \ + GO_PRINTF ("\n==================== GO_IF_LEGITIMATE_ADDRESS\n"); \ + GO_DEBUG_RTX (xinsn); \ + } \ + \ + if (GET_CODE (xinsn) == REG) goto ADDR; \ + if (INDIRECTABLE_ADDRESS_P (xinsn)) goto ADDR; \ + \ + if (TARGET_DEBUGB_MODE) \ + GO_PRINTF ("Not a legitimate address\n"); \ +} + + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + At present, GAS doesn't understand li.[sd], so don't allow it + to be generated at present. Also, the MIPS assembler does not + grok li.d Infinity. */ + +#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE) + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the MIPS (so far ..), nothing needs to be done. + + ACHTUNG this is actually used by the FLOW analysis to get rid + of statements.... + +*/ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) {} + + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* Declarations for condition code stuff. */ +extern void compare_collect (); +extern void compare_restore (); + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. + + Only 5 bits are used in SLLV and SRLV +*/ +#define SHIFT_COUNT_TRUNCATED + + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a word address (for indexing purposes) + so give the MEM rtx a words's mode. */ + +#define FUNCTION_MODE SImode + +/* Define TARGET_MEM_FUNCTIONS if we want to use calls to memcpy and + memset, instead of the BSD functions bcopy and bzero. */ + +#if defined(MIPS_SYSV) || defined(OSF_OS) +#define TARGET_MEM_FUNCTIONS +#endif + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + /* Constant zero is super cheap due to register 0. */ \ + if (RTX == const0_rtx) return 0; \ + if ((INTVAL (RTX) < 0x7fff) && (- INTVAL(RTX) < 0x7fff)) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Used in by the peephole code. */ +#define additive_op(op,mode) (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS) + + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the vax. */ +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the vax. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + CC_STATUS_INIT; + + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. + If we are optimizing to use the global pointer, create a temporary + file to hold all of the text stuff, and write it out to the end. + This is needed because the MIPS assembler is evidently one pass, + and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata + declaration when the code is processed, it generates a two + instruction sequence. */ + +extern void mips_asm_file_start (); + +#define ASM_FILE_START(STREAM) mips_asm_file_start (STREAM) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON " #APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF " #NO_APP\n" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"$0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", \ + "t1", "t2", "t3", "t4", "t5", "t6", "t7","s0", \ + "s1","s2","s3","s4","s5","s6","s7","t8","t9", \ + "k0","k1","gp","sp","fp","ra", \ + "$f0","$f1","$f2","$f3","$f4","$f5","$f6","$f7","$f8","$f9", \ +"$f10","$f11","$f12","$f13","$f14","$f15","$f16","$f17","$f18","$f19", \ +"$f20","$f21","$f22","$f23","$f24","$f25","$f26","$f27","$f28","$f29", \ +"$f30","$f31" \ +} +#define REGISTER_NUMCHAR \ +{ \ +"$0","$1","$2","$3","$4","$5","$6","$7","$8","$9", \ +"$10","$11","$12","$13","$14","$15","$16","$17","$18","$19", \ +"$20","$21","$22","$23","$24","$25","$26","$27","$28","$sp", \ +"$fp","$31", \ +"$f0","$f1","$f2","$f3","$f4","$f5","$f6","$f7","$f8","$f9", \ +"$f10","$f11","$f12","$f13","$f14","$f15","$f16","$f17","$f18","$f19", \ +"$f20","$f21","$f22","$f23","$f24","$f25","$f26","$f27","$f28","$f29", \ +"$f30","$f31" \ +} + +#define REG_NAME(reg) (TARGET_NAME_REGS ? reg_names[reg] : reg_numchar[reg]) + + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. + CODE is used as follows: + + LIST OF PRINT OPERAND CODES: + + 'x' X is CONST_INT, prints 16 bits in hex format. + 'd' output integer constant in decimal, + ':' Prints an 'u' if flag -mnofixed-ovfl (for addu vs. add) */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == ':') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ \ + if ((CODE) == ':') \ + { \ + if (TARGET_NOFIXED_OVFL) \ + fprintf(FILE,"u"); \ + } \ + \ + else if (GET_CODE (X) == REG) \ + { \ + int regnum = REGNO (X); \ + \ + if (CODE == 'M') \ + regnum += MOST_SIGNIFICANT_WORD; \ + else if (CODE == 'L') \ + regnum += LEAST_SIGNIFICANT_WORD; \ + else if (CODE == 'D') \ + regnum++; \ + \ + fprintf (FILE, "%s", \ + ((TARGET_NAME_REGS) ? reg_names : reg_numchar)[regnum]); \ + } \ + \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + { \ + union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); \ + u.i[1] = CONST_DOUBLE_HIGH (X); \ + if (GET_MODE (X) == SFmode) \ + { \ + float f; \ + f = u.d; \ + u.d = f; \ + } \ + fprintf (FILE, "%.20e", u.d); \ + } \ + \ + else if ((CODE == 'x') && (GET_CODE(X) == CONST_INT)) \ + fprintf(FILE,"0x%x", 0xffff & (INTVAL(X))); \ + \ + else if ((CODE == 'd') && (GET_CODE(X) == CONST_INT)) \ + fprintf(FILE,"%d", (INTVAL(X))); \ + \ + else if ((CODE) == 'd') \ + fatal ("Code d was found & insn was not CONST_INT"); \ + \ + else \ + output_addr_const (FILE, X); \ +} + + +/* Print a memory operand whose address is X, on file FILE. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ \ + register rtx addr = ADDR; \ + register char **reg_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + \ + switch (GET_CODE (addr)) \ + { \ + default: \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #1"); \ + break; \ + \ + case REG: \ + fprintf (FILE, "0(%s)", reg_ptr [REGNO (addr)]); \ + break; \ + \ + case PLUS: \ + { \ + register rtx reg = (rtx)0; \ + register rtx offset = (rtx)0; \ + register rtx arg0 = XEXP (addr, 0); \ + register rtx arg1 = XEXP (addr, 1); \ + \ + if (GET_CODE (arg0) == REG) \ + { \ + reg = arg0; \ + offset = arg1; \ + if (GET_CODE (offset) == REG) \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs"); \ + } \ + else if (GET_CODE (arg1) == REG) \ + { \ + reg = arg1; \ + offset = arg0; \ + } \ + else if (CONSTANT_P (arg0) && CONSTANT_P (arg1)) \ + { \ + output_addr_const (FILE, addr); \ + break; \ + } \ + else \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs"); \ + \ + if (!CONSTANT_P (offset)) \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2"); \ + \ + output_addr_const (FILE, offset); \ + fprintf (FILE, "(%s)", reg_ptr [REGNO (reg)]); \ + } \ + break; \ + \ + case LABEL_REF: \ + case SYMBOL_REF: \ + case CONST_INT: \ + case CONST: \ + output_addr_const (FILE, addr); \ + break; \ + } \ +} + + +/* How to tell the debugger about changes of source files. Note, the + mips ECOFF format cannot deal with changes of files inside of + functions, which means the output of parser generators like bison + is generally not debuggable without using the -l switch. Lose, + lose, lose. Silicon graphics seems to want all .file's hardwired + to 1. */ + +#ifndef SET_FILE_NUMBER +#define SET_FILE_NUMBER() ++num_source_filenames +#endif + +#define ASM_OUTPUT_SOURCE_FILENAME(STREAM, NAME) \ +{ \ + SET_FILE_NUMBER (); \ + fprintf (STREAM, "\t%s.file\t%d \"%s\"\n", \ + (TARGET_GAS || !inside_function) ? "" : "#", \ + num_source_filenames, NAME); \ +} + +/* This is how to output a note the debugger telling it the line number + to which the following sequence of instructions corresponds. + Silicon graphics puts a label after each .loc. */ + +#ifndef LABEL_AFTER_LOC +#define LABEL_AFTER_LOC(STREAM) +#endif + +#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) \ +{ \ + fprintf (STREAM, "\n\t.loc\t%d %d\n", num_source_filenames, LINE); \ + LABEL_AFTER_LOC (STREAM); \ +} + +/* The MIPS implementation uses some labels for it's own purposed. The + following lists what labels are created, and are all formed by the + pattern $L[a-z].*. The machine independent portion of GCC creates + labels matching: $L[A-Z][0-9]+ and $L[0-9]+. + + LM[0-9]+ Sillicon graphics label before each stmt. + $Lb[0-9]+ Begin blocks for MIPS debug support + $Ldtable Beginning of the PIC data table + $Le[0-9]+ End blocks for MIPS debug support + $Ls[0-9]+ FP-SP difference if -fomit-frame-pointer */ + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. + + If we are optimizing the gp, remember that this label has been put + out, so we know not to emit an .extern for it in mips_asm_file_end. + We use one of the common bits in the IDENTIFIER tree node for this, + since those bits seem to be unused, and we don't have any method + of getting the decl nodes from the name. */ + +#ifndef COLLECT +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + assemble_name (STREAM, NAME); \ + fputs (":\n", STREAM); \ + \ + if (TARGET_GP_OPT && mips_section_threshold != 0) \ + { \ + tree name_tree = get_identifier (NAME); \ + TREE_ADDRESSABLE (name_tree) = 1; \ + } \ +} while (0) + +#else +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + assemble_name (STREAM, NAME); \ + fputs (":\n", STREAM); \ +} while (0) +#endif + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + do { \ + fputs ("\t.globl\t", STREAM); \ + assemble_name (STREAM, NAME); \ + fputs ("\n", STREAM); \ + } while (0) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + fputs ("\n\t.comm\t", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ",%u\n", (ROUNDED)); \ + \ + if (TARGET_GP_OPT && mips_section_threshold != 0) \ + { \ + tree name_tree = get_identifier (NAME); \ + TREE_ADDRESSABLE (name_tree) = 1; \ + } \ +} while (0) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + fputs ("\n\t.lcomm\t", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ",%u\n", (ROUNDED)); \ + \ + if (TARGET_GP_OPT && mips_section_threshold != 0) \ + { \ + tree name_tree = get_identifier (NAME); \ + TREE_ADDRESSABLE (name_tree) = 1; \ + } \ +} while (0) + + +/* This says how to output an external. It would be possible not to + output anything and let undefined symbol become external. However + the assembler uses length information on externals to allocate in + data/sdata bss/sbss, thereby saving exec time. */ + +#define ASM_OUTPUT_EXTERNAL(STREAM,DECL,NAME) \ + mips_output_external(STREAM,DECL,NAME) + +/* This says what to print at the end of the assembly file */ +#define ASM_FILE_END(STREAM) mips_asm_file_end(STREAM) + + +/* This is how to declare a function name. The actual work of + emitting the label is moved to function_prologue, so that we can + get the line number correctly emitted before the .ent directive, + and after any .file directives. + + Also, switch files if we are optimizing the global pointer. */ + +#define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) \ +{ \ + extern FILE *asm_out_text_file; \ + if (TARGET_GP_OPT) \ + STREAM = asm_out_text_file; \ + \ + current_function_name = NAME; \ +} + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + fprintf (STREAM, "%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ + fprintf (STREAM, "$%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*$%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(STREAM,VALUE) \ +{ \ + union { double d; long l[2]; } u2; \ + u2.d = VALUE; \ + fprintf (STREAM, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n", \ + u2.l[0], u2.d, u2.l[1]); \ +} + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(STREAM,VALUE) \ +{ \ + union { float f; long l; } u2; \ + u2.f = VALUE; \ + fprintf (STREAM, "\t.word\t0x%08lx\t\t# %.12g\n", u2.l, u2.f); \ +} + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.half\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +/* This is how to output an assembler line defining an `int' constant, + which is not in tree format (for collect.c). */ + +#define ASM_OUTPUT_INT_CONST(STREAM,VALUE) \ + fprintf(STREAM, "\t.word\t%d\n", VALUE) + +/* This is how to output an assembler line defining an external/static + address which is not in tree format (for collect.c). */ + +#define ASM_OUTPUT_PTR_INT_SUM(STREAM, NAME, VALUE) \ +do { \ + fprintf (STREAM, "\t.word\t"); \ + ASM_OUTPUT_LABELREF (STREAM, NAME); \ + fprintf (STREAM, "+%d\n", VALUE); \ +} while (0) + +#define ASM_OUTPUT_LABELREF_AS_INT(STREAM, NAME) \ +do { \ + fprintf (STREAM, "\t.word\t"); \ + ASM_OUTPUT_LABELREF (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t0x%x\n", (VALUE)); \ +} + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t$L%d\n", VALUE); \ +} + +/* This is how to output an element of a case-vector that is relative. + (We do not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, VALUE, REL) \ +{ \ + fprintf (STREAM, "\t.word\t$L%d-$L%d\n", VALUE, REL); \ +} + +/* This is how to emit the initial label for switch statements. We + need to put the switch labels somewhere else from the text section, + because the MIPS assembler gets real confused about line numbers if + .word's appear in the text section. */ + +#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, JUMPTABLE) \ +{ \ + rdata_section (); \ + ASM_OUTPUT_ALIGN (STREAM, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM); \ +} + +/* Output at the end of a switch's jump table. */ + +#define ASM_OUTPUT_CASE_END(STREAM, NUM, INSN) \ +{ \ + text_section (); \ +} + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ +{ \ + int mask = (1 << (LOG)) - 1; \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* This is how to output an assembler line to to advance the location + counter by SIZE bytes. */ +#define ASM_OUTPUT_SKIP(STREAM,SIZE) \ +{ \ + fprintf (STREAM, "\t.space\t%u\n", (SIZE)); \ +} + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = LEN, cur_pos = 17; \ + register unsigned char *string = (unsigned char *)STRING; \ + fprintf (STREAM, "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', STREAM); \ + putc (c, STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", STREAM); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", STREAM); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, STREAM); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf (STREAM, "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf (STREAM, "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf (STREAM, "\"\n"); \ +} while (0) + +/* Handle certain cpp directives used in header files on sysV. */ +#define SCCS_DIRECTIVE + +/* Output #ident as a in the read-only data section. */ +#define ASM_OUTPUT_IDENT(FILE, STRING) \ +{ \ + char *p = STRING; \ + int size = strlen (p) + 1; \ + rdata_section (); \ + assemble_string (p, size); \ +} + + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\t.text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\t.data" + +/* Output before writable short data. */ + +#define SDATA_SECTION_ASM_OP "\t.sdata" + +/* Output before read-only data. */ + +#define RDATA_SECTION_ASM_OP "\t.rdata" + +/* What other sections we support other than the normal .data/.text. */ + +#define EXTRA_SECTIONS in_sdata, in_rdata, in_last_p1 + +/* Define the additional functions to select our additional sections. */ + +/* on the MIPS it is not a good idea to put constants in the text + section, since this defeats the sdata/data mechanism. This is + especially true when -O is used. In this case an effort is made to + address with faster (gp) register relative addressing, which can + only get at sdata and sbss items (there is no stext !!) However, + if the constant is too large for sdata, and it's readonly, it + will go into the .rdata section. */ + +#define EXTRA_SECTION_FUNCTIONS \ +void \ +sdata_section () \ +{ \ + if (in_section != in_sdata) \ + { \ + fprintf (asm_out_file, "%s\n", SDATA_SECTION_ASM_OP); \ + in_section = in_sdata; \ + } \ +} \ + \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +/* Given a decl node or constant node, choose the section to output it in + and select that section. */ + +#define SELECT_SECTION_MODE(MODE,RTX) \ +{ \ + extern int mips_section_threshold; \ + if ((GET_MODE_SIZE(MODE) / BITS_PER_UNIT) <= mips_section_threshold \ + && mips_section_threshold > 0) \ + sdata_section (); \ + else \ + rdata_section (); \ +} \ + +#define SELECT_SECTION(DECL) \ +{ \ + extern int mips_section_threshold; \ + if (int_size_in_bytes (TREE_TYPE (DECL)) <= mips_section_threshold \ + && mips_section_threshold > 0) \ + sdata_section (); \ + else if (TREE_CODE (DECL) == STRING_CST) \ + { \ + if (flag_writable_strings) \ + data_section (); \ + else \ + rdata_section (); \ + } \ + else if (TREE_CODE (DECL) != VAR_DECL) \ + rdata_section (); \ + else if (!TREE_READONLY (DECL) || TREE_VOLATILE (DECL)) \ + data_section (); \ + else \ + rdata_section (); \ +} + + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ +do { \ + extern char *reg_numchar[]; \ + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + fprintf (STREAM, "\tsubu\t%s,%s,4\n\tsw\t%s,0(%s)\n", \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[REGNO], \ + reg_name_ptr[STACK_POINTER_REGNUM]); \ +} while (0) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ +do { \ + extern char *reg_numchar[]; \ + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + fprintf (STREAM, "\tlw\t%s,0(%s)\n\taddu\t%s,%s,4\n", \ + reg_name_ptr[REGNO], \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[STACK_POINTER_REGNUM]); \ +} while (0) + + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + + +/* Tell G++'s collect that MIPS' based ports do not have leading + underscores. */ + +#ifndef NO_UNDERSCORES +#define NO_UNDERSCORES +#endif NO_UNDERSCORES + +/* Tell G++ that we need to run collect. */ + +#ifndef USE_COLLECT +#define USE_COLLECT +#endif + +#ifndef EXTENDED_COFF +#define EXTENDED_COFF +#endif + +/* The following are for collect.c which has it's own idea of + which macros should be used. */ + +#define ASM_INT_OP ".word " +#define ASM_SHORT_OP ".half " +#define ASM_CHAR_OP ".byte " diff --git a/gcc-1.40/config/tm-news.h b/gcc-1.40/config/tm-news.h new file mode 100644 index 0000000..6ed2771 --- /dev/null +++ b/gcc-1.40/config/tm-news.h @@ -0,0 +1,408 @@ +/* Definitions of target machine for GNU compiler. SONY NEWS-OS 3.0 version. + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef USE_GAS +/* This controls conditionals in tm-m68k.h. */ +#define MOTOROLA +#define SONY_ASM +#endif + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT 7 + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Sony, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#ifdef news700 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews700" +#endif +#ifdef news800 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews800" +#endif +#ifdef news900 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews900" +#endif +#ifdef news1500 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1500" +#endif +#ifdef news1700 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1700" +#endif +#ifdef news1800 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1800" +#endif +#ifdef news1900 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1900" +#endif + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Override parts of tm-m68k.h to fit Sony's assembler syntax. */ + +#undef POINTER_BOUNDARY +#undef BIGGEST_ALIGNMENT +#undef CALL_USED_REGISTERS +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_PROFILER + +#ifdef MOTOROLA +#undef FUNCTION_PROLOGUE +#undef FUNCTION_EPILOGUE +#undef REGISTER_NAMES +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_SKIP +#undef ASM_FORMAT_PRIVATE_NAME +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#endif + +#undef ASM_OUTPUT_ALIGN + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* There is no point aligning anything to a rounder boundary than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* NEWS makes d2, d3, fp2 and fp3 unsaved registers, unlike the Sun system. */ + +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0} + +/* NEWS returns floats and doubles in fp0, not d0/d1. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#ifdef MOTOROLA + +/* Don't try to define `gcc_compiled.' since the assembler does not + accept symbols with periods. This is no real loss since GDB only + really needs it for parms passed in registers. */ +#define ASM_IDENTIFY_GCC(FILE) + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (fsize < 0x8000) \ + fprintf (FILE, "\tlink fp,#%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf (FILE, "\tlink.l fp,#%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink fp,#0\n\tsub.l #%d,sp\n", fsize); } \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if (mask != 0) \ + fprintf (FILE, "\tfmovem.x #0x%x,-(sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovem.l #0x%x,-(sp)\n", mask); } + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmove.l #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask)) \ + { fprintf (FILE, "\tmove.l #%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmove.l (-%d,fp,a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmove.l (-%d,fp),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovem.l (-%d,fp,a0.l),#0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovem.l (sp)+,#0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovem.l (-%d,fp),#0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem.x (-%d,fp,a0.l),#0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem.x (sp)+,#0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem.x (-%d,fp),#0x%x\n", \ + foffset + fsize, fmask); } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk fp\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd #%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* Difference from tm-m68k.h is in `fp' instead of `a6'. */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7"} + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", reg_names[REGNO]) + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 13), \ + sprintf ((OUTPUT), "%s$$$%d", (NAME), (LABELNO))) + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "-(sp)"); \ + else if (CODE == '+') fprintf (FILE, "(sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(sp)"); \ + else if (CODE == '!') fprintf (FILE, "ccr"); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "#0f%.9e", u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#0d%.20e", u.d); } \ + else if (CODE == 'b') output_addr_const (FILE, X); \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(L%d.b,pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "("); \ + if (addr != 0) { \ + output_addr_const (FILE, addr); \ + putc (',', FILE); } \ + fprintf (FILE, "%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#else /* Using GAS, which uses the MIT assembler syntax, like a Sun. */ + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmovl #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#endif /* MOTOROLA */ diff --git a/gcc-1.40/config/tm-newsgas.h b/gcc-1.40/config/tm-newsgas.h new file mode 100644 index 0000000..ac36e6b --- /dev/null +++ b/gcc-1.40/config/tm-newsgas.h @@ -0,0 +1,7 @@ +/* In Sony versions before 3.0, use the GNU Assembler, because the + system's assembler has no way to assemble the difference of two + labels for the displacement in a switch-dispatch instruction. */ + +#define USE_GAS + +#include "tm-news.h" diff --git a/gcc-1.40/config/tm-next.h b/gcc-1.40/config/tm-next.h new file mode 100644 index 0000000..4292b27 --- /dev/null +++ b/gcc-1.40/config/tm-next.h @@ -0,0 +1,98 @@ +/* tm-next.h: Definitions for Next as target machine for GNU C compiler. */ + +#include "tm-m68k.h" + +/* Enable recent gcc to compile under the old gcc in Next release 1.0. */ +#define __inline inline + +/* See tm-m68k.h. 7 means 68020/030 with 68881/882. */ + +#define TARGET_DEFAULT 7 + +/* These compiler options take an argument. */ + +#define WORD_SWITCH_TAKES_ARG(STR) \ + (!strcmp (STR, "Ttext") || !strcmp (STR, "Tdata")) + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -DNeXT -Dunix -D__MACH__" + +/* Machine dependent ccp options. */ + +#define CPP_SPEC "%{bsd:-D__STRICT_BSD__}" + +/* Machine dependent ld options. */ + +#define LINK_SPEC "%{Z} %{M} %{Mach} %{segcreate*} %{seglinkedit}" + +/* Machine dependent libraries. */ + +#define LIB_SPEC "%{!p:%{!pg:-lsys_s}} %{pg:-lsys_p}" + +/* We specify crt0.o as -lcrt0.o so that ld will search the library path. */ +#define STARTFILE_SPEC \ + "%{pg:-lgcrt0.o}%{!pg: \ + %{p:%e-p profiling is no longer supported. Use -pg instead.} \ + %{!p:-lcrt0.o}}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* We want C++ style comments to be supported for Objective-C */ + +#define CPLUSPLUS + +/* Why not? */ + +#define DOLLARS_IN_IDENTIFIERS 1 + +#if 0 /* These pertain to code changes that are not present in 1.36. */ + +/* Allow Mach -MD and -MMD make depend switches. */ + +#define MACH_MAKE_DEPEND + +/* These options take an argument. Note that we don't support -Ttext or -Tdata. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "MD") || !strcmp (STR, +"MMD")) + +#endif /* 0 */ + +/* Allow #sscs (but don't do anything). */ + +#define SCCS_DIRECTIVE + +/* We use Dbx symbol format. */ + +#define DBX_DEBUGGING_INFO + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "#0r%.9g", (VALUE))) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "#0r%.20g", (VALUE))) diff --git a/gcc-1.40/config/tm-ns32k.h b/gcc-1.40/config/tm-ns32k.h new file mode 100644 index 0000000..16cb7b4 --- /dev/null +++ b/gcc-1.40/config/tm-ns32k.h @@ -0,0 +1,1457 @@ +/* Definitions of target machine for GNU compiler. NS32000 version. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dns32000 -Dunix" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (32000, National syntax)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile 32081 insns for floating point (not library calls). */ +#define TARGET_32081 (target_flags & 1) +/* Compile using rtd insn calling sequence. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 2) +/* Compile passing first two args in regs 0 and 1. */ +#define TARGET_REGPARM (target_flags & 4) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { { "32081", 1}, \ + { "soft-float", -1}, \ + { "rtd", 2}, \ + { "nortd", -2}, \ + { "regparm", 4}, \ + { "noregparm", -4}, \ + { "", TARGET_DEFAULT}} + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the ns32k. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the ns32k. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* This is not true on the ns32k. */ +/* #define WORDS_BIG_ENDIAN */ + +/* Number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 32000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* Define this if move instructions will actually fail to work + when given unaligned data. National claims that the NS32032 + works without strict alignment, but rumor has it that operands + crossing a page boundary cause unpredictable results. */ +#define STRICT_ALIGNMENT + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ +#define FIRST_PSEUDO_REGISTER 18 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the ns32k, these are the FP, SP, (SB and PC are not included here). */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 1, 1} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS {1, 1, 1, 0, 0, 0, 0, 0, \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + On the ns32k, all registers are 32 bits long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 32000, all registers can hold all modes, except that + double precision floats (and double ints) must fall on even-register + boundaries */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((MODE) == DFmode \ + ? (((REGNO) & 1) == 0 \ + && (TARGET_32081 ? (REGNO) < 16 : (REGNO) < 8)) \ + : (MODE) == DImode ? ((REGNO) & 1) == 0 && (REGNO) < 8 \ + : 1) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == DFmode || (MODE1) == DImode) == ((MODE2) == DFmode || (MODE2) == DImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* NS32000 pc is not overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 17 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 16 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 16 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 1 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 2 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FLOAT_REGS, + GEN_AND_MEM_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "GENERAL_REGS", "FLOAT_REGS", "GEN_AND_FLOAT_REGS", "GEN_AND_MEM_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {0, 0x00ff, 0xff00, 0xffff, 0x300ff, 0x3ffff, } + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) < 8 ? GENERAL_REGS : (REGNO) < 16 ? FLOAT_REGS : ALL_REGS) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GEN_AND_MEM_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'r' ? GENERAL_REGS \ + : (C) == 'f' ? FLOAT_REGS \ + : (C) == 'x' ? GEN_AND_MEM_REGS \ + : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + On the ns32k, these letters are used as follows: + + I : Matches integers which are valid shift amounts for scaled indexing. + These are 0, 1, 2, 3 for byte, word, double, and quadword. + J : Matches integers which fit a "quick" operand. + K : Matches integers 0 to 7 (for inss and exts instructions). */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((VALUE) < 8 && (VALUE) + 8 >= 0 ? \ + ((C) == 'I' ? (0 <= (VALUE) && (VALUE) <= 3) : \ + (C) == 'J' ? (VALUE) <= 7 : \ + (C) == 'K' ? 0 <= (VALUE) : 0) : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 32000, this is the size of MODE in words */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 32000, sp@- in a byte insn really pushes a BYTE. */ +#define PUSH_ROUNDING(BYTES) (BYTES) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + On the 32000, the RET insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RET can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RET is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the 32000 the return value is in R0, + or perhaps in F0 is there is fp support. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_32081 \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the 32000 the return value is in R0, + or perhaps F0 is there is fp support. */ + +#define LIBCALL_VALUE(MODE) \ + (((MODE) == DFmode || (MODE) == SFmode) && TARGET_32081 \ + ? gen_rtx (REG, MODE, 8) \ + : gen_rtx (REG, MODE, 0)) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the 32000, R0 and F0 are the only registers thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) (((N) & ~8) == 0) + +/* 1 if N is a possible register number for function argument passing. + On the 32000, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the ns32k, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the ns32k, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the 32000 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in r0, r1. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 0) + +#ifndef MAIN_FUNCTION_PROLOGUE +#define MAIN_FUNCTION_PROLOGUE +#endif + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + int used_regs_buf[8], *bufp = used_regs_buf; \ + int used_fregs_buf[8], *fbufp = used_fregs_buf; \ + extern char call_used_regs[]; \ + MAIN_FUNCTION_PROLOGUE; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *bufp++ = regno; \ + } \ + *bufp = -1; \ + for (; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; \ + } \ + *fbufp = -1; \ + bufp = used_regs_buf; \ + if (frame_pointer_needed) \ + { \ + fprintf (FILE, "\tenter ["); \ + while (*bufp >= 0) \ + { \ + fprintf (FILE, "r%d", *bufp++); \ + if (*bufp >= 0) \ + fputc (',', FILE); \ + } \ + fprintf (FILE, "],%d\n", SIZE); \ + } \ + else while (*bufp >= 0) \ + fprintf (FILE, "\tmovd r%d,tos\n", *bufp++); \ + fbufp = used_fregs_buf; \ + while (*fbufp >= 0) \ + { \ + if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ + fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \ + else \ + { \ + fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \ + fbufp += 2; \ + } \ + } \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. + + THIS DEFINITION FOR THE 32000 IS A GUESS. IT HAS NOT BEEN TESTED. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\taddr LP%d,r0\n\tbsr mcount\n", (LABELNO)) + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +/* #define EXIT_IGNORE_STACK */ + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ extern int current_function_pops_args; \ + extern int current_function_args_size; \ + register int regno; \ + int used_regs_buf[8], *bufp = used_regs_buf; \ + int used_fregs_buf[8], *fbufp = used_fregs_buf; \ + extern char call_used_regs[]; \ + *fbufp++ = -2; \ + for (regno = 8; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; \ + } \ + fbufp--; \ + while (fbufp > used_fregs_buf) \ + { \ + if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ + { \ + fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \ + fbufp -= 2; \ + } \ + else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \ + } \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + *bufp++ = regno; \ + if (frame_pointer_needed) \ + { \ + fprintf (FILE, "\texit ["); \ + while (bufp > used_regs_buf) \ + { \ + fprintf (FILE, "r%d", *--bufp); \ + if (bufp > used_regs_buf) \ + fputc (',', FILE); \ + } \ + fprintf (FILE, "]\n"); \ + } \ + else \ + { \ + while (bufp > used_regs_buf) \ + fprintf (FILE, "\tmovd tos,r%d\n", *--bufp); \ + } \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\tret %d\n", current_function_args_size); \ + else fprintf (FILE, "\tret 0\n"); } + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#if 0 +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + if (GET_CODE (ADDR) == REG && REGNO (ADDR) == FRAME_POINTER_REGNUM) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && GET_CODE (XEXP (ADDR, 0)) == REG \ + && REGNO (XEXP (ADDR, 0)) == FRAME_POINTER_REGNUM \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (gen_rtx (REG, Pmode, STACK_POINTER_REGNUM), \ + offset + (DEPTH)); } } +#else +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ + if (check_reg(ADDR, FRAME_POINTER_REGNUM)) { \ + register int regno, offset = (DEPTH) - 4; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + if (GET_CODE (ADDR) == REG && REGNO (ADDR) == FRAME_POINTER_REGNUM) \ + ADDR = plus_constant(stack_pointer_rtx, offset); \ + else if (GET_CODE(ADDR) == PLUS) { \ + register rtx a0 = XEXP(ADDR, 0); \ + if (GET_CODE(a0) == REG && REGNO(a0) == FRAME_POINTER_REGNUM) \ + if (GET_CODE(XEXP(ADDR, 1)) == CONST_INT) \ + ADDR = plus_constant(stack_pointer_rtx, \ + offset + INTVAL(XEXP(ADDR, 1))); \ + else \ + ADDR = plus_constant(gen_rtx(PLUS, Pmode, \ + stack_pointer_rtx, XEXP (ADDR, 1)), \ + offset); \ + else if (GET_CODE(a0) == MEM) { \ + register rtx a1 = XEXP(a0, 0); \ + if (GET_CODE(a1) == REG && REGNO(a1) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, offset)), \ + XEXP(ADDR, 1)); \ + else if (GET_CODE(a1) == PLUS && GET_CODE(XEXP(a1, 0)) == REG \ + && REGNO(XEXP(a1, 0)) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset+INTVAL(XEXP(a1, 1)))),\ + XEXP(ADDR, 1)); \ + else \ + abort(); \ + } else if (GET_CODE(XEXP(ADDR, 1)) == MEM) { \ + register rtx a1 = XEXP(XEXP(ADDR, 1), 0); \ + if (GET_CODE(a1) == REG && REGNO(a1) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + XEXP(ADDR, 0), \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset))); \ + else if (GET_CODE(a1) == PLUS && GET_CODE(XEXP(a1, 0)) == REG \ + && REGNO(XEXP(a1, 0)) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + XEXP(ADDR, 0), \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset+INTVAL(XEXP(a1, 1)))));\ + else \ + abort(); \ + } else \ + abort(); \ + } else if (GET_CODE(ADDR) == MEM) { \ + register rtx a0 = XEXP(ADDR, 0); \ + if (GET_CODE (a0) == REG && REGNO (a0) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, offset)); \ + else if (GET_CODE(a0) == PLUS && GET_CODE(XEXP(a0, 0)) == REG \ + && REGNO(XEXP(a0, 0)) == FRAME_POINTER_REGNUM \ + && GET_CODE(XEXP(a0, 1)) == CONST_INT) \ + ADDR = gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset + INTVAL(XEXP(a0, 1)))); \ + else \ + abort(); \ + } else \ + abort(); \ + } +#endif + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +/* note that FP and SP cannot be used as an index. What about PC? */ +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8 \ + || (REGNO) == FRAME_POINTER_REGNUM || (REGNO) == STACK_POINTER_REGNUM) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST \ + || (GET_CODE (X) == CONST_INT \ + && ((unsigned)INTVAL (X) >= 0xe0000000 \ + || (unsigned)INTVAL (X) < 0x20000000))) + +#define CONSTANT_ADDRESS_NO_LABEL_P(X) \ + (GET_CODE (X) == CONST_INT \ + && ((unsigned)INTVAL (X) >= 0xe0000000 \ + || (unsigned)INTVAL (X) < 0x20000000)) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + (REGNO (X) < 8 || REGNO (X) >= FIRST_PSEUDO_REGISTER) +/* Nonzero if X is a hard reg that can be used as a base reg + of if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (REGNO (X) < 8 || REGNO (X) >= FRAME_POINTER_REGNUM) +/* Nonzero if X is a floating point reg or a pseudo reg. */ + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +/* 1 if X is an address that we could indirect through. */ +/***** NOTE ***** There is a bug in the Sequent assembler which fails + to fixup addressing information for symbols used as offsets + from registers which are not FP or SP (or SB or PC). This + makes _x(fp) valid, while _x(r0) is invalid. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) + +#define MEM_REG(X) \ + ((GET_CODE (X) == REG && (REGNO (X) ^ 16) < 2) \ + || (GET_CODE (X) == SYMBOL_REF)) + +#define INDIRECTABLE_2_ADDRESS_P(X) \ + (GET_CODE (X) == MEM \ + && (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \ + || (GET_CODE (xfoo0) == PLUS \ + && GET_CODE (XEXP (xfoo0, 0)) == REG \ + && MEM_REG (XEXP (xfoo0, 0)) \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \ + || CONSTANT_ADDRESS_P (xfoo0))) + +#define INDIRECTABLE_ADDRESS_P(X) \ + (INDIRECTABLE_1_ADDRESS_P(X) \ + || INDIRECTABLE_2_ADDRESS_P (X) \ + || (GET_CODE (X) == PLUS \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1)) \ + && INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0)))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_1_ADDRESS_P(X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \ + if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \ + goto ADDR; \ +} + +/* 1 if PROD is either a reg times size of mode MODE + or just a reg, if MODE is just one byte. Actually, on the ns32k, + since the index mode is independent of the operand size, + we can match more stuff... + + This macro's expansion uses the temporary variables xfoo0, xfoo1 + and xfoo2 that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +((GET_CODE (PROD) == REG && REG_OK_FOR_INDEX_P (PROD)) \ + || (GET_CODE (PROD) == MULT \ + && (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + (GET_CODE (xfoo1) == CONST_INT \ + && GET_CODE (xfoo0) == REG \ + && FITS_INDEX_RANGE (INTVAL (xfoo1)) \ + && REG_OK_FOR_INDEX_P (xfoo0))))) + +#define FITS_INDEX_RANGE(X) \ + ((xfoo2 = (unsigned)(X)-1), \ + ((xfoo2 < 4 && xfoo2 != 2) || xfoo2 == 7)) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfooy, xfooz, xfoo0, xfoo1; \ + unsigned xfoo2; \ + xfooy = X; \ + GO_IF_NONINDEXED_ADDRESS (xfooy, ADDR); \ + if (GET_CODE (xfooy) == PLUS) \ + { \ + if (GET_CODE (XEXP (xfooy, 1)) == CONST_INT \ + && GET_CODE (XEXP (xfooy, 0)) == PLUS) \ + xfooy = XEXP (xfooy, 0); \ + else if (GET_CODE (XEXP (xfooy, 0)) == CONST_INT \ + && GET_CODE (XEXP (xfooy, 1)) == PLUS) \ + xfooy = XEXP (xfooy, 1); \ + xfooz = XEXP (xfooy, 1); \ + if (INDEX_TERM_P (xfooz, MODE)) \ + { rtx t = XEXP (xfooy, 0); GO_IF_NONINDEXED_ADDRESS (t, ADDR); }\ + xfooz = XEXP (xfooy, 0); \ + if (INDEX_TERM_P (xfooz, MODE)) \ + { rtx t = XEXP (xfooy, 1); GO_IF_NONINDEXED_ADDRESS (t, ADDR); }\ + } \ + else if (INDEX_TERM_P (xfooy, MODE)) \ + goto ADDR; \ + else if (GET_CODE (xfooy) == PRE_DEC) \ + if (REGNO (XEXP (xfooy, 0)) == STACK_POINTER_REGNUM) goto ADDR; \ + else abort (); \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the ns32k, we do nothing */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the ns32k, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \ + goto LABEL;} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. + Can do SImode, but HI mode is more efficient. */ +#define CASE_VECTOR_MODE HImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* #define SHIFT_COUNT_TRUNCATED */ + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (INTVAL (RTX) <= 7 && INTVAL (RTX) >= -8) return 0; \ + if (INTVAL (RTX) < 0x4000 && INTVAL (RTX) >= -0x4000) \ + return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This bit means that what ought to be in the Z bit + should be tested in the F bit. */ +#define CC_Z_IN_F 04000 + +/* This bit means that what ought to be in the Z bit + is complemented in the F bit. */ +#define CC_Z_IN_NOT_F 010000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_DEST (EXP)) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); \ + } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + else { /* nothing happens? CC_STATUS_INIT; */} \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + printf ("here!\n", cc_status.value2 = 0); \ +} + +#define OUTPUT_JUMP(NORMAL, NO_OV) \ +{ if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "fp", "sp"} + +/* How to renumber registers for dbx and gdb. + NS32000 may need more change in the numeration. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO < 8) ? (REGNO)+4 : (REGNO)) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to align the code that follows an unconditional branch. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf (FILE, "\t.align 4\n") + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovd %s,tos\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovd tos,%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ +/* ** Notice that the second element is LI format! */ +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-LI%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. */ + +/* %$ means print the prefix for an immediate operand. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '$' || (CODE) == '?') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') fprintf (FILE, "$"); \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0d%.20e", u.d); } \ + else \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* Print a memory operand whose address is X, on file FILE. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + int mem=0, multval, offset_printed; \ + char reg1_str[256], reg2_str[256]; \ + retry: \ + switch (GET_CODE (addr)) \ + { \ + case MEM: \ + fprintf (FILE, "0("); \ + addr = XEXP (addr, 0); \ + mem =1; \ + goto retry; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + if (REGNO(XEXP(addr, 0)) != STACK_POINTER_REGNUM) \ + fprintf(FILE, ")1:%d", REGNO(XEXP(addr,0))); \ + else fprintf (FILE, "tos", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + if (REGNO(XEXP(addr, 0)) != STACK_POINTER_REGNUM) \ + fprintf(FILE, ")2:%d", REGNO(XEXP(addr,0))); \ + else fprintf (FILE, "tos", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case MULT: \ + reg1 = XEXP (addr, 0); /* [rX:Y] */ \ + reg2 = XEXP (addr, 1); /* CONST/REG */ \ + if (GET_CODE (reg1) == CONST_INT && GET_CODE(reg2) == REG) { \ + reg1 = reg2; \ + reg2 = XEXP (addr, 0); /* [rX:Y] */ \ + } else \ + if (GET_CODE (reg2) != CONST_INT || \ + GET_CODE (reg1) != REG) { \ + abort(); \ + } \ + fprintf (FILE, "0[%s:%c]", \ + reg_names[ REGNO(reg1) ], \ + "XbwXdXXXq"[INTVAL (reg2)]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + multval = 0; \ + reg1_str[0] = 0; reg2_str[0] = 0; \ + offset_printed = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) \ + || GET_CODE (XEXP (addr, 0)) == MEM) \ + { \ + /* CONST / MEM(PLUS((REG)(CONST))) */ \ + offset = XEXP (addr, 0); \ + /* (REG) / PLUS((REG)(CONST)) / MULT((REG)(CONST)) */ \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) \ + || GET_CODE (XEXP (addr, 1)) == MEM) \ + { \ + /* CONST / MEM(PLUS((REG)(CONST))) */ \ + offset = XEXP (addr, 1); \ + /* (REG) / PLUS((REG)(CONST)) / MULT((REG)(CONST)) */ \ + addr = XEXP (addr, 0); \ + } \ + if (offset != 0) { \ + if (GET_CODE (offset) == MEM) { \ + offset = XEXP (offset, 0); /* skip MEM */ \ + switch (GET_CODE (offset)) { \ + case REG: \ + sprintf (reg1_str, "(%s)", \ + reg_names[REGNO (offset)]); \ + offset = 0; \ + break; \ + case PLUS: \ + if (!CONSTANT_ADDRESS_P (XEXP (offset, 1))) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, PLUS, PLUS\n"); \ + print_rtl(FILE, offset); \ + exit (1); \ + } \ + if (GET_CODE (XEXP(offset,0)) != REG) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, PLUS, REG\n"); \ + print_rtl(FILE, offset); \ + exit (1); \ + } \ + sprintf (reg1_str, "(%s))", \ + reg_names[REGNO (XEXP(offset,0))]); \ + offset = XEXP (offset, 1); \ + break; \ + default: \ + abort(); \ + } \ + } else { /* !MEM */ \ + if (!CONSTANT_ADDRESS_P (offset)) { \ + abort(); \ + } \ + output_addr_const (FILE, offset); \ + offset_printed = 1; \ + offset = 0; \ + } \ + } \ + \ + if (GET_CODE (addr) == PLUS) { \ + if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); /* [rX:Y] */ \ + addr = XEXP (addr, 1); /* CONST/REG */ \ + if (GET_CODE (XEXP (reg1, 1)) != CONST_INT || \ + GET_CODE (XEXP (reg1, 0)) != REG) { \ + abort(); \ + } \ + sprintf (reg2_str, "[%s:%c]", \ + reg_names[ REGNO(XEXP (reg1, 0)) ], \ + "XbwXdXXXq"[INTVAL (XEXP (reg1, 1))]); \ + reg1 = 0; \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); /* [rX:Y] */ \ + addr = XEXP (addr, 0); /* CONST */ \ + if (GET_CODE (XEXP (reg1, 1)) != CONST_INT || \ + GET_CODE (XEXP (reg1, 0)) != REG) { \ + abort(); \ + } \ + sprintf (reg2_str, "[%s:%c]", \ + reg_names[ REGNO(XEXP (reg1, 0)) ], \ + "XbwXdXXXq"[INTVAL (XEXP (reg1, 1))]); \ + reg1 = 0; \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG \ + && REGNO (XEXP (addr, 0)) < 8) \ + { \ + sprintf (reg2_str, "[%s:b]", \ + reg_names[ REGNO(XEXP (addr, 0)) ]); \ + addr = XEXP (addr, 1); /* CONST / REG */ \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG \ + && REGNO (XEXP (addr, 1)) < 8) \ + { \ + sprintf (reg2_str, "[%s:b]", \ + reg_names[ REGNO(XEXP (addr, 1)) ]); \ + addr = XEXP (addr, 0); /* CONST / REG */ \ + } \ + else abort (); \ + } \ + if (addr) \ + switch (GET_CODE (addr)) { \ + case MULT: \ + if(*reg2_str) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, INDEX, two mults\n"); \ + print_rtl(FILE, addr); \ + exit (1); \ + } \ + reg1 = XEXP (addr, 0); /* [rX:Y] */ \ + addr = XEXP (addr, 1); /* CONST */ \ + if (GET_CODE (addr) != CONST_INT) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, INDEX, !CONS3 (%d)\n", \ + GET_CODE (addr)); \ + print_rtl(FILE, addr); \ + exit (1); \ + } \ + sprintf (reg2_str, "[%s:%c]", reg_names[ REGNO(reg1) ], \ + "XbwXdXXXq"[INTVAL (addr)]); \ + break; \ + case REG: \ + if (!*reg1_str) { \ + if (offset || offset_printed) \ + sprintf (reg1_str, "(%s)", reg_names[REGNO (addr)]); \ + else \ + sprintf (reg1_str, "0(%s)", reg_names[REGNO (addr)]); \ + } else if (!*reg2_str) \ + sprintf (reg2_str, "[%s:b]", \ + reg_names[REGNO (addr)]); \ + else abort(); \ + break; \ + case MEM: \ + addr = XEXP(addr,0); \ + switch (GET_CODE(addr)) { \ + case REG: \ + if (!*reg1_str) { \ + if (offset || offset_printed) \ + sprintf (reg1_str, "(0(%s))", \ + reg_names[REGNO (addr)]); \ + else \ + sprintf (reg1_str, "0(0(%s))", \ + reg_names[REGNO (addr)]); \ + } else \ + abort(); \ + break; \ + case PLUS: \ + if (GET_CODE (XEXP (addr, 0)) == REG) { \ + if (!*reg1_str) { \ + sprintf (reg1_str, "(%s))", \ + reg_names[REGNO(XEXP(addr, 0))]); \ + offset = XEXP(addr, 1); \ + } else \ + abort(); \ + } else { \ + if (!*reg1_str) { \ + sprintf (reg1_str, "(%s))", \ + reg_names[REGNO(XEXP(addr, 1))]); \ + offset = XEXP(addr, 0); \ + } else \ + abort(); \ + } \ + break; \ + default: \ + abort(); \ + } \ + break; \ + default: \ + if (offset_printed) \ + fprintf (FILE, "+"); \ + output_addr_const (FILE, addr); \ + offset_printed ++; \ + } \ + if (offset) { \ + if(!offset_printed) \ + fputc ('0', FILE); \ + fputc ('(', FILE); \ + output_addr_const (FILE, offset); \ + } \ + if (*reg1_str) \ + fprintf (FILE, "%s", reg1_str); \ + if (*reg2_str) \ + fprintf (FILE, "%s", reg2_str); \ + break; \ + default: \ + output_addr_const (FILE, addr); \ + } \ + if(mem) \ + fprintf(FILE,")");} + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc-1.40/config/tm-pyr.h b/gcc-1.40/config/tm-pyr.h new file mode 100644 index 0000000..6d1c593 --- /dev/null +++ b/gcc-1.40/config/tm-pyr.h @@ -0,0 +1,1406 @@ +/* Definitions of target machine for GNU compiler for Pyramid 90 Series. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * If you're going to change this, and you haven't already, + * you should get and read + * ``OSx Operating System Porting Guide'', + * publication number 4100-0066-A + * Revision A + * Pyramid Technology Corporation. + * + * or whatever the most recent version is. In any case, page and + * section number references given herein refer to this document. + * + * The instruction table for gdb lists the available insns and + * the valid addressing modes. + * + * Any other information on the Pyramid architecture is proprietary + * and hard to get. (Pyramid cc -S and adb are also useful.) + * + */ + +/*** Run-time compilation parameters selecting different hardware subsets. ***/ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dpyr -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (pyr)"); + +extern int target_flags; + +/* Nonzero if compiling code that Unix assembler can assemble. */ +#define TARGET_UNIX_ASM (target_flags & 1) + +/* Use the indexed addressing modes (were once not known to work). + Leaving this in means we can disable them and so find out what + they win us. */ +#define TARGET_INDEX (target_flags & 2) + +/* Implement stdarg in the same fashion used on all other machines. */ +#define TARGET_GNU_STDARG (target_flags & 4) + +/* Compile using RETD to pop off the args. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. + This contravenes the Pyramid calling convention, so we don't + do it yet. */ + +#define TARGET_RETD (target_flags & 8) + +/* Macros used in the machine description to test the flags. */ + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. + + -mgnu will be useful if we ever have GAS on a pyramid. + -mindex was used to enable indexing when I didn't understand + how pyramid's indexing modes worked. */ + +#define TARGET_SWITCHES \ + { {"unix", 1}, \ + {"gnu", -1}, \ + {"index", 2}, \ + {"noindex", -2}, \ + {"gnu-stdarg", 4}, \ + {"nognu-stdarg", -4}, \ + {"retd", 8}, \ + {"no-retd", -8}, \ + { "", TARGET_DEFAULT}} + +/* Default target_flags if no switches specified. + + (equivalent to "-munix -mindex -mgnu-stdarg") */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (1 + 2 + 4) +#endif + +/*** Target machine storage layout ***/ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the pyramid. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +#define WORDS_BIG_ENDIAN + +/* Number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +/* --> FIXME: I don't know if this is what pyr cc does. */ +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so dhrystone will run faster. + Pyramid documentation says the best alignment is to align + on the size of a cache line, which is 16 bytes. + Newer pyrs have single insns that do strcmp() and strcpy(), so this + may not actually win anything. */ +/* Try to increase aligment. */ + +/* Use kludge to maintain alignment for pyramid. See + DATA_SECTION_ASM_OP below. */ +#define CONSTANT_ALIGNMENT(CODE, TYPEALIGN) \ + ((CODE) == STRING_CST ? (TYPEALIGN) * 4 : (TYPEALIGN)) + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/*** Standard register usage. ***/ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ + +/* Nota Bene: + Pyramids have 64 addressable 32-bit registers, arranged as four + groups: global, parameter, local, and temporary. + The sixteen global registers are fairly conventional; the last + four are overloaded with a PSW, frame pointer, and stack pointer. + The non-dedicated global registers used to be reserved for Pyramid + operating systems, and still have cryptic and undocumented uses for + certain library calls. We avoid them. + + The parameter, local, and temporary registers provide _register_ + _windowing_. Each procedure call has its own set of these 48 + registers, which constitute its call frame. (These frames are + allocated on a stack separate from the conventional data stack, + called the _control_ _stack_. + facility hereby the temporary registers of frame n + become the parameter registers of frame n+1, viz.: + + 0 15 0 15 0 15 + +------------+------------+------------+ + | | | | + +------------+------------+------------+ + Parameter Local Temporary + + ^ + | + v + + 0 15 0 15 0 15 + +------------+------------+------------+ + | | | | + +------------+------------+------------+ + Parameter Local Temporary + + + Temporary registers are used for parameter passing, and are not + preserved across calls. TR14 and TR15 are reserved and should + never be used; since they are used to save the next frame's PC + and stack pointer, their contents may be destroyed at any time by + an interrupt. + */ + +#define PYR_GREG(n) (n) +#define PYR_PREG(n) (16+(n)) +#define PYR_LREG(n) (32+(n)) +#define PYR_TREG(n) (48+(n)) + +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + + On the pyramid, these are LOGPSW, CFP, SP, PC, but we leave the other + global regs alone as well. */ + +#define FIXED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + +/* #define DEFAULT_CALLER_SAVES */ + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + On the pyramid, all registers are one word long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the pyramid, all registers can hold all modes. */ + +/* -->FIXME: this is not the case for 64-bit quantities in tr11/12 through + --> TR14/15. This should be fixed, but to do it correctly, we also + --> need to fix MODES_TIEABLE_P. Yuk. We ignore this, since GCC should + --> do the "right" thing due to FIXED_REGISTERS. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) 1 + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Pyramid pc is overloaded on global register 15. */ +#define PC_REGNUM PYR_GREG(15) + +/* Register to use for pushing function arguments. + --> on Pyramids, the data stack pointer. */ +#define STACK_POINTER_REGNUM PYR_GREG(14) + +/* Base register for access to local variables of the function. + Pyramid uses CFP (GR13) as both frame pointer and argument pointer. */ +#define FRAME_POINTER_REGNUM 13 /* PYR_GREG(13) */ + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. + + Setting this to 1 can't break anything. Since the Pyramid has + register windows, I don't know if defining this to be zero can + win anything. It could changed later, if it wins. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 13 /* PYR_GREG(13) */ + +/* Register in which static-chain is passed to a function. */ +/* If needed, Pyramid says to use temporary register 12. */ +#define STATIC_CHAIN_REGNUM PYR_TREG(12) + +/* Register in which address to store a structure value + is passed to a function. + On a Pyramid, this is temporary register 0 (TR0). */ + +#define STRUCT_VALUE_REGNUM PYR_TREG(0) +#define STRUCT_VALUE_INCOMING_REGNUM PYR_PREG(0) + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The pyramid has only one kind of registers, so NO_REGS and ALL_REGS + are the only classes. */ + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {{0,0}, {0xffffffff,0xffffffff}} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) ALL_REGS + +/* The class value for index registers, and the one for base regs. */ + +#define BASE_REG_CLASS ALL_REGS +#define INDEX_REG_CLASS ALL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) NO_REGS + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the pyramid, this is always the size of MODE in words, + since all registers are the same size. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + --> For the Pyramid, 'I' can be used for the 6-bit signed integers + --> (-32 to 31) allowed as immediate short operands in many + --> instructions. 'J' cane be used for any value that doesn't fit + --> in 6 bits. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= -32 && (VALUE) < 32 : \ + (C) == 'J' ? (VALUE) < -32 || (VALUE) >= 32 : \ + (C) == 'K' ? (VALUE) == 0xff || (VALUE) == 0xffff : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 + + +/*** Stack layout; function entry, exit and calling. ***/ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +/* FIXME: this used to work when defined as 0. But that makes gnu + stdargs clobber the first arg. What gives?? */ +#define STARTING_FRAME_OFFSET 0 + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + The Pyramid OSx Porting Guide says we are never to do this; + using RETD in this way violates the Pyramid calling convention. + We may nevertheless provide this as an option. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RETD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* --> Pyramid has register windows. + --> The caller sees the return value is in TR0(/TR1) regardless of + --> its type. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), PYR_TREG(0)) + +/* --> but the callee has to leave it in PR0(/PR1) */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), PYR_PREG(0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* --> On Pyramid the return value is in TR0/TR1 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, PYR_TREG(0)) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value + as seen by the caller. + + On the Pyramid, TR0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == PYR_TREG(0)) + +/* 1 if N is a possible register number for function argument passing. + On the Pyramid, the first twelve temporary registers are available. */ + +/* FIXME FIXME FIXME + it's not clear whether this macro should be defined from the point + of view of the caller or the callee. Since it's never actually used + in GNU CC, the point is somewhat moot :-). + + This definition is consistent with register usage in the md's for + other register-window architectures (sparc and spur). + */ +#define FUNCTION_ARG_REGNO_P(N) ((PYR_TREG(0) <= (N)) && ((N) <= PYR_TREG(11))) + +/*** Parameter passing: FUNCTION_ARG and FUNCTION_INCOMING_ARG ***/ + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On Pyramids, each parameter is passed either completely on the stack + or completely in registers. No parameter larger than a double may + be passed in a register. Also, no struct or union may be passed in + a register, even if it would fit. + + So parameters are not necessarily passed "consecutively". + Thus we need a vector data type: one element to record how many + parameters have been passed in registers and on the stack, + respectively. + + ((These constraints seem like a gross waste of registers. But if we + ignore the constraint about structs & unions, we won`t be able to + freely mix gcc-compiled code and pyr cc-compiled code. It looks + like better argument passing conventions, and a machine-dependent + flag to enable them, might be a win.)) */ + + +#define CUMULATIVE_ARGS int + +/* Define the number of registers that can hold paramters. + This macro is used only in other macro definitions below. */ +#define NPARM_REGS 12 + +/* Decide whether or not a parameter can be put in a register. + (We may still have problems with libcalls. GCC doesn't seem + to know about anything more than the machine mode. I trust + structures are never passed to a libcall... + + If compiling with -mgnu-stdarg, this definition should make + functions using the gcc-supplied stdarg, and calls to such + functions (declared with an arglist ending in"..."), work. + But such fns won't be able to call pyr cc-compiled + varargs fns (eg, printf(), _doprnt.) + + If compiling with -mnognu-stdarg, this definition should make + calls to pyr cc-compiled functions work. Functions using + the gcc-supplied stdarg will be utterly broken. + There will be no better solution until RMS can be persuaded that + one is needed. + + This macro is used only in other macro definitions below. + (well, it may be used in out-pyr.c, because the damn pyramid cc + can't handle the macro definition of PARAM_SAFE_FOR_REG_P ! */ + + +#define INNER_PARAM_SAFE_HELPER(TYPE) \ + ((TARGET_GNU_STDARG ? (! TREE_ADDRESSABLE ((tree)TYPE)): 1) \ + && (TREE_CODE ((tree)TYPE) != RECORD_TYPE) \ + && (TREE_CODE ((tree)TYPE) != UNION_TYPE)) + +#ifdef __GNUC__ +#define PARAM_SAFE_HELPER(TYPE) \ + INNER_PARAM_SAFE_HELPER((TYPE)) +#else +extern int inner_param_safe_helper(); +#define PARAM_SAFE_HELPER(TYPE) \ + inner_param_safe_helper((tree)(TYPE)) +#endif + +/* Be careful with the expression (long) (TYPE) == 0. + Writing it in more obvious/correct forms makes the Pyr cc + dump core! */ +#define PARAM_SAFE_FOR_REG_P(MODE, TYPE, NAMED) \ + (((MODE) != BLKmode) \ + && ((TARGET_GNU_STDARG) ? (NAMED) : 1) \ + && ((((long)(TYPE))==0) || PARAM_SAFE_HELPER((TYPE)))) + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = (FNTYPE && !flag_pcc_struct_return && aggregate_value_p (FNTYPE))) + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +#define FUNCTION_ARG_HELPER(CUM, MODE, TYPE, NAMED) \ +(PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \ + ? (NPARM_REGS >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + ? gen_rtx (REG, (MODE), PYR_TREG(CUM)) \ + : 0) \ + : 0) +#ifdef __GNUC__ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + FUNCTION_ARG_HELPER(CUM, MODE, TYPE, NAMED) +#else +/***************** Avoid bug in Pyramid OSx compiler... ******************/ +#define FUNCTION_ARG (rtx) pyr_function_arg +extern void* pyr_function_arg (); +#endif + +/* Define where a function finds its arguments. + This is different from FUNCTION_ARG because of register windows. */ + +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ +(PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \ + ? (NPARM_REGS >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + ? gen_rtx (REG, (MODE), PYR_PREG(CUM)) \ + : 0) \ + : 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ +((CUM) += (PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \ + ? ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4) \ + : 0)) + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#if FRAME_POINTER_REQUIRED + +/* We always have frame pointers */ + +/* Don't set up a frame pointer if it's not referenced. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + int _size = (SIZE) + current_function_pretend_args_size; \ + if (_size + current_function_args_size != 0 \ + || current_function_calls_alloca) \ + { \ + fprintf (FILE, "\tadsf $%d\n", _size); \ + if (current_function_pretend_args_size > 0) \ + fprintf (FILE, "\tsubw $%d,cfp\n", \ + current_function_pretend_args_size); \ + } \ +} + +#else /* !FRAME_POINTER_REQUIRED */ + +/* Don't set up a frame pointer if `frame_pointer_needed' tells us + there is no need. Also, don't set up a frame pointer if it's not + referenced. */ + +/* The definition used to be broken. Write a new one. */ + +#endif /* !FRAME_POINTER_REQUIRED */ + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmova LP%d,tr0\n\tcall mcount\n", (LABELNO)); + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. + Don't know if this works on Pyrs. */ + +#if 0 /* don't do basic_block profiling yet */ +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, \ + "\tmtstw LPBX0,tr0\n\tbne LPI%d\n\tmova LP%d,TR0\n\tcall __bb_init_func\nLPI%d:\n", \ + LABELNO, LABELNO); + +/* Output assembler code to increment the count associated with + the basic block number BLOCKNO. Not sure how to do this on pyrs. */ +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, "\taddw", 4 * BLOCKNO) +#endif /* don't do basic_block profiling yet */ + +/* When returning from a function, the stack pointer does not matter + (as long as there is a frame pointer). */ + +/* This should return non-zero when we really set up a frame pointer. + Otherwise, GCC is directed to preserve sp by returning zero. */ +extern int current_function_pretend_args_size; +extern int current_function_args_size; +extern int current_function_calls_alloca; +#define EXIT_IGNORE_STACK \ + (get_frame_size () + current_function_pretend_args_size \ + + current_function_args_size != 0 \ + || current_function_calls_alloca) \ + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +/* ---> Since we always have a frame pointer, it is safe for this + to not work. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ + fatal ("compiler error, Pyramid call without frame ptr!\n") + +/*** Addressing modes, and classification of registers for them. ***/ + +/* #define HAVE_POST_INCREMENT */ /* pyramid has none of these */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +/* All registers except gr0 OK as index or base registers. */ + +#define REGNO_OK_FOR_BASE_P(regno) \ +((0 < (regno) && (regno) < FIRST_PSEUDO_REGISTER) || reg_renumber[regno] > 0) + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((0 < (regno) && (regno) < FIRST_PSEUDO_REGISTER) || reg_renumber[regno] > 0) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 /* check MAX_REGS_PER_ADDRESS */ + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) 1 +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) 1 + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is actually machine-independent. */ + + +/* Go to ADDR if X is indexable -- ie, neither indexed nor offset. + Note that X is indexable iff x is offset. */ +#define GO_IF_INDEXABLE_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if ((CONSTANT_ADDRESS_P (xfoob)) \ + || (GET_CODE (xfoob) == REG && (REG_OK_FOR_BASE_P (xfoob)))) \ + goto ADDR; \ + } + + +/* Go to label ADDR if X is a valid address that doesn't use indexing. + This is so if X is either a simple address, or the contents of a register + plus an offset. + This macro also gets used in output-pyramid.h in the function that + recognizes non-indexed operands. */ + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ \ + if (GET_CODE (X) == REG) \ + goto ADDR; \ + GO_IF_INDEXABLE_ADDRESS (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { /* Handle offset(reg) represented with offset on left */ \ + if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + { if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + goto ADDR; \ + } \ + /* Handle offset(reg) represented with offset on right */ \ + if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + goto ADDR; \ + } \ + } \ +} + +/* 1 if PROD is either a reg or a reg times a valid offset multiplier + (ie, 2, 4, or 8). + This macro's expansion uses the temporary variables xfoo0 and xfoo1 + that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +((GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \ + || (GET_CODE (PROD) == MULT \ + && \ + (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + ((GET_CODE (xfoo0) == CONST_INT \ + && (INTVAL (xfoo0) == 1 \ + || INTVAL (xfoo0) == 2 \ + || INTVAL (xfoo0) == 4 \ + || INTVAL (xfoo0) == 8) \ + && GET_CODE (xfoo1) == REG \ + && REG_OK_FOR_INDEX_P (xfoo1)) \ + || \ + (GET_CODE (xfoo1) == CONST_INT \ + && (INTVAL (xfoo1) == 1 \ + || INTVAL (xfoo1) == 2 \ + || INTVAL (xfoo1) == 4 \ + || INTVAL (xfoo1) == 8) \ + && GET_CODE (xfoo0) == REG \ + && REG_OK_FOR_INDEX_P (xfoo0)))))) + + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xone, xtwo, xfoo0, xfoo1; \ + GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + if (TARGET_INDEX && GET_CODE (X) == PLUS) \ + { \ + /* Handle <address>[index] represented with index-sum outermost */\ + xone = XEXP (X, 0); \ + xtwo = XEXP (X, 1); \ + if (INDEX_TERM_P (xone, MODE)) \ + { GO_IF_INDEXABLE_ADDRESS (xtwo, ADDR); } \ + /* Handle <address>[index] represented with index-sum innermost */\ + if (INDEX_TERM_P (xtwo, MODE)) \ + { GO_IF_INDEXABLE_ADDRESS (xone, ADDR); } \ + } \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + --> FIXME: We haven't yet figured out what optimizations are useful + --> on Pyramids. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + There don't seem to be any such modes on pyramids. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/*** Miscellaneous Parameters ***/ + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/*#define CASE_VECTOR_PC_RELATIVE*/ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. + It's just a guess. I have no idea of insn cost on pyrs. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +/* This is untrue for pyramid. The cvtdw instruction generates a trap + for input operands that are out-of-range for a signed int. */ +/* #define FIXUNS_TRUNC_LIKE_FIX_TRUNC */ + +/* Define this macro if the preprocessor should silently ignore + '#sccs' directives. */ +/* #define SCCS_DIRECTIVE */ + +/* Define this macro if the preprocessor should silently ignore + '#ident' directives. */ +/* #define IDENT_DIRECTIVE */ + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 8 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* number of bits in an 'int' on target machine */ +#define INT_TYPE_SIZE 32 + +/* 1 if byte access requires more than one instruction */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Define this macro if it is as good or better to call a constant + function address than to call an address kept in a register. +/* #define NO_FUNCTION_CSE */ + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* There are no flag store insns on a pyr. */ +/* #define STORE_FLAG_VALUE */ + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (CONST_OK_FOR_LETTER_P (INTVAL (RTX),'I')) return 0; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/*** Condition Code Information ***/ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the pyr. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* This is a very simple definition of NOTICE_UPDATE_CC. + Many cases can be optimized, to improve condition code usage. + Maybe we should handle this entirely in the md, since it complicated + to describe the way pyr sets cc. */ + +#define TRULY_UNSIGNED_COMPARE_P(X) \ + (X == GEU || X == GTU || X == LEU || X == LTU) +#define CC_VALID_FOR_UNSIGNED 2 + +#define CC_STATUS_MDEP_INIT cc_status.mdep = 0 + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + notice_update_cc(EXP, INSN) + +/*** Output of Assembler Code ***/ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, ((TARGET_UNIX_ASM)? "" : "#NO_APP\n")); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON ((TARGET_UNIX_ASM) ? "" : "#APP\n") + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF ((TARGET_UNIX_ASM) ? "" : "#NO_APP\n") + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"gr0", "gr1", "gr2", "gr3", "gr4", "gr5", "gr6", "gr7", "gr8", \ + "gr9", "gr10", "gr11", "logpsw", "cfp", "sp", "pc", \ + "pr0", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", \ + "pr8", "pr9", "pr10", "pr11", "pr12", "pr13", "pr14", "pr15", \ + "lr0", "lr1", "lr2", "lr3", "lr4", "lr5", "lr6", "lr7", \ + "lr8", "lr9", "lr10", "lr11", "lr12", "lr13", "lr14", "lr15", \ + "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", \ + "tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15"} + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Our preference is for dbx rather than sdb. + Yours may be different. */ +#define DBX_DEBUGGING_INFO +/* #define SDB_DEBUGGING_INFO */ + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS 1 + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME); + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.half "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tsubw $4,sp\n\tmovw %s,(sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovw (sp),%s\n\taddw $4,sp\n", reg_names[REGNO]) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.word L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. + + On Pyramids, .align takes only args between 2 and 5. + */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG) < 2 ? 2 : (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + On the Pyr, we support the conventional CODE characters: + + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + which are never used. */ + +/* FIXME : should be more robust with CONST_DOUBLE. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names [REGNO (X)]); \ + \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "$0f%.0e", u1.f); \ + else \ + fprintf (FILE, "$0x%x", u1.i); } \ + \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0d%.20e", u.d); } \ + \ + else if (CODE == 'N') \ + switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("eq", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GT: \ + case GTU: fputs ("gt", FILE); break; \ + case LT: \ + case LTU: fputs ("lt", FILE); break; \ + case GE: \ + case GEU: fputs ("ge", FILE); break; \ + case LE: \ + case LEU: fputs ("le", FILE); break; \ + } \ + \ + else if (CODE == 'C') \ + switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("eq", FILE); break; \ + case GT: \ + case GTU: fputs ("le", FILE); break; \ + case LT: \ + case LTU: fputs ("ge", FILE); break; \ + case GE: \ + case GEU: fputs ("lt", FILE); break; \ + case LE: \ + case LEU: fputs ("gt", FILE); break; \ + } \ + \ + else if (CODE == 'R') \ + switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("eq", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GT: \ + case GTU: fputs ("lt", FILE); break; \ + case LT: \ + case LTU: fputs ("gt", FILE); break; \ + case GE: \ + case GEU: fputs ("le", FILE); break; \ + case LE: \ + case LEU: fputs ("ge", FILE); break; \ + } \ + \ + else { putc ('$', FILE); output_addr_const (FILE, X); } \ +} + +/* Print a memory operand whose address is ADDR, on file FILE. */ +/* This is horrendously complicated. */ +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ \ + register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset, scale; \ + retry: \ + switch (GET_CODE (addr)) \ + { \ + case MEM: \ + fprintf (stderr, "bad Mem "); debug_rtx (addr); \ + addr = XEXP (addr, 0); \ + abort (); \ + case REG: \ + fprintf (FILE, "(%s)", reg_names [REGNO (addr)]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) \ + || GET_CODE (XEXP (addr, 0)) == MEM) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) \ + || GET_CODE (XEXP (addr, 1)) == MEM) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) \ + { \ + if (reg1 == 0) \ + reg1 = addr; \ + else \ + reg2 = addr; \ + addr = 0; \ + } \ + if (offset != 0) \ + { \ + if (addr != 0) { \ + fprintf (stderr, "\nBad addr "); debug_rtx (addr); \ + abort ();} \ + addr = offset; \ + } \ + if (reg1 != 0 && GET_CODE (reg1) == MULT) \ + { breg = reg2; ireg = reg1; } \ + else if (reg2 != 0 && GET_CODE (reg2) == MULT) \ + { breg = reg1; ireg = reg2; } \ + else if (reg2 != 0 || GET_CODE (addr) == MEM) \ + { breg = reg2; ireg = reg1; } \ + else \ + { breg = reg1; ireg = reg2; } \ + if (addr != 0) \ + output_address (offset); \ + if (breg != 0) \ + { if (GET_CODE (breg) != REG) \ + { \ + fprintf (stderr, "bad Breg"); debug_rtx (addr); \ + abort (); \ + } \ + fprintf (FILE, "(%s)", reg_names[REGNO (breg)]); } \ + if (ireg != 0) \ + { \ + if (GET_CODE (ireg) == MULT) \ + { \ + scale = XEXP (ireg, 1); \ + ireg = XEXP (ireg, 0); \ + if (GET_CODE (ireg) != REG) \ + { register rtx tem; \ + tem = ireg; ireg = scale; scale = tem; \ + } \ + if (GET_CODE (ireg) != REG) { \ + fprintf (stderr, "bad idx "); debug_rtx (addr); \ + abort (); } \ + if ((GET_CODE (scale) == CONST_INT) && (INTVAL(scale) >= 1))\ + fprintf (FILE, "[%s*0x%x]", reg_names[REGNO (ireg)], \ + INTVAL(scale)); \ + else \ + fprintf (FILE, "[%s*1]", reg_names[REGNO (ireg)]); \ + } \ + else if (GET_CODE (ireg) == REG) \ + fprintf (FILE, "[%s*1]", reg_names[REGNO (ireg)]); \ + else \ + { \ + fprintf (stderr, "Not indexed at all!"); debug_rtx (addr);\ + abort (); \ + } \ + } \ + break; \ + default: \ + output_addr_const (FILE, addr); \ + } \ +} diff --git a/gcc-1.40/config/tm-seq386.h b/gcc-1.40/config/tm-seq386.h new file mode 100644 index 0000000..615c6cf --- /dev/null +++ b/gcc-1.40/config/tm-seq386.h @@ -0,0 +1,79 @@ +/* Definitions for Sequent Intel 386. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-i386.h" + +/* Use the BSD assembler syntax. */ + +#include "tm-bsd386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386 -Dsequent" + +/* Pass -Z and -ZO options to the linker. */ + +#define LINK_SPEC "%{Z*}" + +/* We don't want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* gcc order is ax, dx, cx, bx, si, di, bp, sp, st, st. + * dbx order is ax, dx, cx, st(0), st(1), bx, si, di, st(2), st(3), + * st(4), st(5), st(6), st(7), sp, bp */ +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) < 3 ? (n) : (n) < 6 ? (n) + 2 \ + : (n) == 6 ? 15 : (n) == 7 ? 14 : 3) + +/* Prevent anything from being allocated in the register pair cx/bx, + since that would confuse GDB. */ + +#undef HARD_REGNO_MODE_OK +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (hard_regno_mode_ok (REGNO, MODE) \ + && ! (REGNO == 2 && GET_MODE_SIZE (MODE) > 4)) + +/* Floating-point return values come in the FP register. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmovl $LP%d,%%eax\n\tcall mcount\n", (LABELNO)); + +/* Assember pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" diff --git a/gcc-1.40/config/tm-sequent.h b/gcc-1.40/config/tm-sequent.h new file mode 100644 index 0000000..d34c249 --- /dev/null +++ b/gcc-1.40/config/tm-sequent.h @@ -0,0 +1,110 @@ +/* Definitions of target machine for GNU compiler. SEQUENT NS32000 version. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Two flags to control how addresses are printed in assembler insns. */ +#define SEQUENT_ADDRESS_BUG 1 +#define SEQUENT_BASE_REGS + +#include "tm-ns32k.h" + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +#define TARGET_DEFAULT 1 + +/* Print subsidiary information on the compiler version in use. */ +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, Sequent syntax)"); + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dns32000 -Dsequent -Dunix" + +/* This is how to align the code that follows an unconditional branch. + Don't define it, since it confuses the assembler (we hear). */ + +#undef ASM_OUTPUT_ALIGN_CODE + +/* Assember pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" + +/* Control how stack adjust insns are output. */ +#define SEQUENT_ADJUST_STACK + +/* %$ means print the prefix for an immediate operand. + On the sequent, no prefix is used for such. */ + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') ; \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + fprintf (FILE, "0("); \ + output_address (xfoo); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "0d%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "0f%.20e", u.d); } \ + else output_addr_const (FILE, X); } + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) diff --git a/gcc-1.40/config/tm-sparc.h b/gcc-1.40/config/tm-sparc.h new file mode 100644 index 0000000..6924a17 --- /dev/null +++ b/gcc-1.40/config/tm-sparc.h @@ -0,0 +1,1435 @@ +/* Definitions of target machine for GNU compiler, for Sun SPARC. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + +/* Specify library to handle `-a' basic block profiling. */ + +#define LIB_SPEC "%{a:/usr/lib/bb_link.o} \ +%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* Provide required defaults for linker -e and -d switches. + Also, it is hard to debug with shared libraries, + so don't use them if going to debug. */ + +#define LINK_SPEC "%{!e*:-e start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{Bstatic}" + +/* Special flags to the Sun-4 assembler when using pipe for input. */ + +#define ASM_SPEC " %{pipe:-} " + +/* Prevent error on `-dalign', `-sun4' and `-target sun4' options. */ + +#define CC1_SPEC "%{dalign:} %{sun4:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "target")) + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dsparc -Dsun -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (sparc)"); + +/* Generate DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Nonzero if we should generate code to use the fpu. */ +#define TARGET_FPU (target_flags & 1) + +/* Nonzero if we should use FUNCTION_EPILOGUE. Otherwise, we + use fast return insns, but lose some generality. */ +#define TARGET_EPILOGUE (target_flags & 2) + +/* Nonzero if we expect to be passed through the Sun + optimizing assembler. This requires us to generate + code which we otherwise would not. For example, + calls via pointers-to-functions must be output + specially because Sun assemble does not do proper flow + analysis for this case. */ +#define TARGET_SUN_ASM (target_flags & 4) + +/* Nonzero if we should do eager peepholes for conditional branch + scheduling. */ +#define TARGET_EAGER (target_flags & 8) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { {"fpu", 1}, \ + {"soft-float", -1}, \ + {"epilogue", 2}, \ + {"no-epilogue", -2}, \ + {"sun-asm", 4}, \ + {"eager", 8}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 3 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* This is true on the SPARC. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For SPARC we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 64 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Things that must be doubleword aligned cannot go in the text section, + because the linker fails to align the text section enough! + Put them in the data section. */ +#define MAX_TEXT_ALIGN 32 + +#define SELECT_SECTION(T) \ +{ \ + if (TREE_CODE (T) == VAR_DECL) \ + { \ + if (TREE_READONLY (T) && ! TREE_VOLATILE (T) \ + && DECL_ALIGN (T) <= MAX_TEXT_ALIGN) \ + text_section (); \ + else \ + data_section (); \ + } \ + if (*tree_code_type[(int) TREE_CODE (T)] == 'c') \ + { \ + if ((TREE_CODE (T) == STRING_CST && flag_writable_strings) \ + || TYPE_ALIGN (TREE_TYPE (T)) > MAX_TEXT_ALIGN) \ + data_section (); \ + else \ + text_section (); \ + } \ +} + +/* Use text section for a constant + unless we need more alignment than that offers. */ +#define SELECT_RTX_SECTION(MODE, X) \ +{ \ + if (GET_MODE_BITSIZE (MODE) <= MAX_TEXT_ALIGN)\ + text_section (); \ + else \ + data_section (); \ +} + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + + SPARC has 32 fullword registers and 32 floating point registers. */ + +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On SPARC, this includes all the global registers + (registers r[0] through r[7]) and the callee return + address register, r[15]. */ +#define FIXED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 1, 1, \ + \ + 1, 1, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 1, 1, \ + \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On SPARC, ordinary registers hold 32 bits worth; + this means both integer and floating point registers. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On SPARC, the cpu registers can hold any mode but the float registers + can only hold SFmode or DFmode. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 32 ? ((GET_MODE_SIZE (MODE) <= 4) ? 1 : ((REGNO) & 1) == 0) : \ + ((MODE) == SFmode ? 1 : (MODE) == DFmode && ((REGNO) & 1) == 0)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* SPARC pc isn't overloaded on a register that the compiler knows about. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 14 + +/* Actual top-of-stack address is 92 greater + than the contents of the stack pointer register. */ +#define STACK_POINTER_OFFSET 92 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 30 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 30 + +/* Register in which static-chain is passed to a function. */ +/* ??? */ +#define STATIC_CHAIN_REGNUM 1 + + +/* Functions which return large structures get the address + to place the wanted value at offset 64 from the frame. */ +#define STRUCT_VALUE_OFFSET 64 /* Used only in other #defines in this file. */ +#define STRUCT_VALUE \ + gen_rtx (MEM, Pmode, \ + gen_rtx (PLUS, SImode, stack_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, STRUCT_VALUE_OFFSET))) +#define STRUCT_VALUE_INCOMING \ + gen_rtx (MEM, Pmode, \ + gen_rtx (PLUS, SImode, frame_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, STRUCT_VALUE_OFFSET))) + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The SPARC has two kinds of registers, general and floating point. */ + +enum reg_class { NO_REGS, GENERAL_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "GENERAL_REGS", "FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {{0, 0}, {-1, 0}, {0, -1}, {-1, -1}} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) >= 32 ? FP_REGS : GENERAL_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_REGS : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For SPARC, `I' is used for the range of constants an insn + can actually contain. + `J' is used for the range which is just zero (since that is R0). + `K' is used for the 5-bit operand of a compare insns. */ + +#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x1000) < 0x2000) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) ((VALUE) + 0x1000) < 0x2000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On SPARC, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET -16 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On SPARC, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* Offset of first parameter from the argument pointer register value. + This is 64 for the ins and locals, plus 4 for the struct-return reg + if this function isn't going to use it. */ +#define FIRST_PARM_OFFSET(FNDECL) \ + (DECL_MODE (DECL_RESULT (fndecl)) == BLKmode \ + ? STRUCT_VALUE_OFFSET : STRUCT_VALUE_OFFSET + 4) + +/* Offset from top-of-stack address to location to store the + function parameter if it can't go in a register. + Addresses for following parameters are computed relative to this one. */ +#define FIRST_PARM_CALLER_OFFSET(FNDECL) \ + (STRUCT_VALUE_OFFSET + 4 - STACK_POINTER_OFFSET) + +/* When a parameter is passed in a register, stack space is still + allocated for it. */ +#define REG_PARM_STACK_SPACE + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* Some subroutine macros specific to this machine. */ +#define BASE_RETURN_VALUE_REG(MODE) \ + ((MODE) == SFmode || (MODE) == DFmode ? 32 : 8) +#define BASE_OUTGOING_VALUE_REG(MODE) \ + ((MODE) == SFmode || (MODE) == DFmode ? 32 : 24) +#define BASE_PASSING_ARG_REG(MODE) (8) +#define BASE_INCOMING_ARG_REG(MODE) (24) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On SPARC the value is found in the first "output" register. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), BASE_RETURN_VALUE_REG (TYPE_MODE (VALTYPE))) + +/* But the called function leaves it in the first "input" register. */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), BASE_OUTGOING_VALUE_REG (TYPE_MODE (VALTYPE))) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, MODE, BASE_RETURN_VALUE_REG (MODE)) + +/* 1 if N is a possible register number for a function value + as seen by the caller. + On SPARC, the first "output" reg is used for integer values, + and the first floating point register is used for floating point values. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 8 || (N) == 32) + +/* 1 if N is a possible register number for function argument passing. + On SPARC, these are the "output" registers. */ + +#define FUNCTION_ARG_REGNO_P(N) ((N) < 14 && (N) > 7) + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On SPARC, this is a single integer, which is a number of words + of arguments scanned so far (including the invisible argument, + if any, which holds the structure-value-address). + Thus 7 or more means all following args should go on the stack. */ + +#define CUMULATIVE_ARGS int + +/* Define the number of register that can hold parameters. + This macro is used only in other macro definitions below. */ +#define NPARM_REGS 6 + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On SPARC, the offset always starts at 0: the first parm reg is always + the same reg. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4)) + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On SPARC the first six args are normally in registers + and the rest are pushed. Any arg that starts within the first 6 words + is at least partially passed in a register unless its data type forbids. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((CUM) < NPARM_REGS \ + && ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), BASE_PASSING_ARG_REG (MODE) + (CUM)) : 0) + +/* Define where a function finds its arguments. + This is different from FUNCTION_ARG because of register windows. */ + +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ +((CUM) < NPARM_REGS \ + && ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), BASE_INCOMING_ARG_REG (MODE) + (CUM)) : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. + Any arg that starts in the first 6 regs but won't entirely fit in them + needs partial registers on the Sparc. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ + (((CUM) < NPARM_REGS \ + && ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + && ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) - NPARM_REGS > 0) \ + ? (NPARM_REGS - (CUM)) \ + : 0) + +/* Output the label for a function definition. */ + +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ +{ \ + extern tree double_type_node, float_type_node; \ + if (TREE_TYPE (DECL) == float_type_node) \ + fprintf (FILE, "\t.proc 6\n"); \ + else if (TREE_TYPE (DECL) == double_type_node) \ + fprintf (FILE, "\t.proc 7\n"); \ + else if (TREE_TYPE (DECL) == void_type_node) \ + fprintf (FILE, "\t.proc 0\n"); \ + else fprintf (FILE, "\t.proc 1\n"); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ +} + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +/* On SPARC, move-double insns between fpu and cpu need an 8-byte block + of memory. If any fpu reg is used in the function, we allocate + such a block here, at the bottom of the frame, just in case it's needed. + + If this function is a leaf procedure, then we may choose not + to do a "save" insn. Currently we do this only if it touches + the "output" registers. The "local" and "input" registers + are off limits. It might be better to allow one such register + to go to the stack, but I doubt it. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int current_function_pretend_args_size; \ + extern int frame_pointer_needed; \ + int fsize = (((SIZE) + 7 - STARTING_FRAME_OFFSET) & -8); \ + int actual_fsize; \ + int n_fregs = 0, i; \ + int n_iregs = 64; \ + for (i = 32; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + n_fregs++; \ + for (i = 16; i < 32; i++) \ + if (regs_ever_live[i]) { n_iregs = 96; break; } \ + fprintf (FILE, "\t!#PROLOGUE# 0\n"); \ + actual_fsize = fsize + n_iregs + (n_fregs*4+7 & -8); \ + fsize += current_function_pretend_args_size+7 & -8; \ + actual_fsize += current_function_pretend_args_size+7 & -8; \ + if (actual_fsize < 4096) \ + fprintf (FILE, "\tsave %%sp,-%d,%%sp\n", actual_fsize); \ + else \ + { \ + fprintf (FILE, "\tsethi %%hi(0x%x),%%g1\n\tadd %%g1,%%lo(0x%x),%%g1\n", \ + -actual_fsize, -actual_fsize); \ + fprintf (FILE, "\tsave %%sp,%%g1,%%sp\n"); \ + } \ + fprintf (FILE, "\t!#PROLOGUE# 1\n"); \ + if (n_fregs) \ + { \ + for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + if (regs_ever_live[i+1] && ! call_used_regs[i+1]) \ + fprintf (FILE, "\tstd %s,[%%sp+0x%x]\n", \ + reg_names[i], n_iregs + 4 * n_fregs), \ + n_fregs += 2, i += 1; \ + else \ + fprintf (FILE, "\tstf %s,[%%sp+0x%x]\n", \ + reg_names[i], n_iregs + 4 * n_fregs++); \ + } \ + } \ + if (regs_ever_live[32]) \ + fprintf (FILE, "\tst %s,[%%fp-16]\n\tst %s,[%%fp-12]\n", \ + reg_names[0], reg_names[0]); \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tsethi %%hi(LP%d),%%o0\n\tcall mcount\n\tor %%lo(LP%d),%%o0,%%o0\n", \ + (LABELNO), (LABELNO)) + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tld [%%lo(LPBX0)+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%%lo(LPBX0),%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n", \ + (LABELNO), (LABELNO)) + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. */ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ +{ \ + int blockn = (BLOCKNO); \ + fprintf (FILE, "\tsethi %%hi(LPBX2+%d),%%g1\n\tld [%%lo(LPBX2+%d)+%%g1],%%g2\n\ +\tadd %%g2,1,%%g2\n\tst %%g2,[%%lo(LPBX2+%d)+%%g1]\n", \ + 4 * blockn, 4 * blockn, 4 * blockn); \ + CC_STATUS_INIT; /* We have clobbered %g1. Also %g2. */ \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +extern int may_call_alloca; +extern int current_function_pretend_args_size; + +#define EXIT_IGNORE_STACK \ + (get_frame_size () != 0 \ + || may_call_alloca || current_function_pretend_args_size) + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +/* This declaration is needed due to traditional/ANSI + incompatibilities which cannot be #ifdefed away + because they occur inside of macros. Sigh. */ +extern union tree_node *current_function_decl; + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int may_call_alloca; \ + extern int current_function_pretend_args_size; \ + extern int max_pending_stack_adjust; \ + extern int frame_pointer_needed; \ + int fsize = (((SIZE) + 7 - STARTING_FRAME_OFFSET) & -8); \ + int actual_fsize; \ + int n_fregs = 0, i; \ + int n_iregs = 64; \ + for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + n_fregs++; \ + for (i = 16; i < 32; i++) \ + if (regs_ever_live[i]) { n_iregs = 96; break; } \ + actual_fsize = fsize + n_iregs + (n_fregs*4+7 & -8); \ + actual_fsize += current_function_pretend_args_size+7 & -8; \ + fsize += current_function_pretend_args_size+7 & -8; \ + if (n_fregs) \ + { \ + char *base; \ + int offset; \ + if (fsize < 4096) \ + { base = "%fp"; offset = n_iregs - actual_fsize; } \ + else \ + { base = "%g1"; offset = n_iregs; \ + if (fsize < 4096) \ + fprintf (FILE, "sethi %%hi(0x%x),%%g1\n\tadd %%g1,%%lo(0x%x),%%g1\n\tadd %%fp,%%g1,%%g1\n", -actual_fsize, -actual_fsize);\ + } \ + for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + if (regs_ever_live[i+1] && ! call_used_regs[i+1]) \ + fprintf (FILE, "\tldd [%s%+d],%s\n", \ + base, offset + 4 * n_fregs, \ + reg_names[i]), \ + n_fregs += 2, i += 1; \ + else \ + fprintf (FILE, "\tldf [%s%+d],%s\n", \ + base, offset + 4 * n_fregs++, \ + reg_names[i]); \ + } \ + } \ + fprintf (FILE, "\tret\n\trestore\n"); \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 0x20) < 32 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 32) + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the SPARC, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + Anything but a CONST_DOUBLE can be made to work. */ + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) != CONST_DOUBLE) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) (((unsigned) REGNO (X)) - 32 >= 32) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (((unsigned) REGNO (X)) - 32 >= 32) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + On SPARC, the actual legitimate addresses must be REG+REG or REG+SMALLINT. + But we can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. + + Try making SYMBOL_REF (and other things which are CONSTANT_ADDRESS_P) + a legitimate address, regardless. Because the only insns which can use + memory are load or store insns, the added hair in the machine description + is not that bad. It should also speed up the compiler by halving the number + of insns it must manage for each (MEM (SYMBOL_REF ...)) involved. */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (GET_CODE (X) == REG) \ + { if (REG_OK_FOR_BASE_P (X)) goto ADDR; } \ + else if (GET_CODE (X) == PLUS) \ + { \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && INTVAL (XEXP (X, 1)) >= -0x1000 \ + && INTVAL (XEXP (X, 1)) < 0x1000) \ + goto ADDR; \ + } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + { \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) >= -0x1000 \ + && INTVAL (XEXP (X, 0)) < 0x1000) \ + goto ADDR; \ + } \ + } \ + else if (CONSTANT_ADDRESS_P (X)) \ + goto ADDR; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. */ + +/* On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (GET_CODE (x) == SYMBOL_REF) \ + (X) = copy_to_reg (X); \ + if (memory_address_p (MODE, X)) \ + goto WIN; } + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the SPARC this is never true. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE SImode + +/* Define this if addresses of constant functions + shouldn't be put through pseudo regs where they can be cse'd. + Desirable on machines where ordinary constants are expensive + but a CALL with constant address is cheap. */ +#define NO_FUNCTION_CSE + +/* Define subroutines to call to handle multiply and divide. + Use the subroutines that Sun's library provides. + The `*' prevents an underscore from being prepended by the compiler. */ + +#define DIVSI3_LIBCALL "*.div" +#define UDIVSI3_LIBCALL "*.udiv" +#define MODSI3_LIBCALL "*.rem" +#define UMODSI3_LIBCALL "*.urem" +#define MULSI3_LIBCALL "*.mul" +#define UMULSI3_LIBCALL "*.umul" + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (INTVAL (RTX) < 0x1000 && INTVAL (RTX) >= -0x1000) return 0; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This holds the value sourcing %hi(%g1). We keep this info + around so that mem/mem ops, such as increment and decrement, + etc, can be performed reasonably. */ +#define CC_STATUS_MDEP rtx + +/* Nonzero if the results of the previous comparison are + in the floating point condition code register. */ + +#define CC_IN_FCCR 04000 + +/* Nonzero if the results of the previous comparison are + int the coprocessor's condition code register. */ + +#define CC_IN_CCCR 010000 + +/* Nonzero if we know (easily) that floating point register f0 + (f1) contains the value 0. */ +#define CC_F0_IS_0 020000 +#define CC_F1_IS_0 040000 + +/* Nonzero if we know the value of %hi(%g1). */ +#define CC_KNOW_HI_G1 0100000 + +#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0) + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (SET_DEST (EXP) == cc0_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { rtx x = cc_status.mdep; int know = cc_status.flags & CC_KNOW_HI_G1; \ + CC_STATUS_INIT; \ + if (x && know) \ + { cc_status.mdep = x; cc_status.flags |= CC_KNOW_HI_G1; } \ + } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (SET_DEST (XVECEXP (EXP, 0, 0)) == cc0_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_SRC (XVECEXP (EXP, 0, 0))) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { rtx x = cc_status.mdep; int know = cc_status.flags & CC_KNOW_HI_G1; \ + CC_STATUS_INIT; \ + if (x && know) \ + { cc_status.mdep = x; cc_status.flags |= CC_KNOW_HI_G1; } \ + } \ + } \ + else if (GET_CODE (EXP) == PARALLEL) \ + /* insn-peep has changed this insn beyond recognition + by NOTICE_UPDATE_CC. However, we know it is either + a call or a branch with a delay slot filled, so we can + give up on knowing condition codes in any case. */ \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ +} + +#define OUTPUT_JUMP(NORMAL, NO_OV, FLOAT) \ +{ if (cc_prev_status.flags & CC_IN_FCCR) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(file) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", \ + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", \ + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \ + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", \ + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", \ + "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", \ + "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", \ + "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31"} \ + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* On Sun 4, this limit is 2048. We use 1500 to be safe, + since the length can run past this up to a continuation point. */ +#define DBX_CONTIN_LENGTH 1500 + +/* This is how to output a note to DBX telling it the line number + to which the following sequence of instructions corresponds. + + This is needed for SunOS 4.0, and should not hurt for 3.2 + versions either. */ +#define ASM_OUTPUT_SOURCE_LINE(file, line) \ + { static int sym_lineno = 1; \ + fprintf (file, ".stabn 68,0,%d,LM%d\nLM%d:\n", \ + line, sym_lineno, sym_lineno); \ + sym_lineno += 1; } + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".global ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.half "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.word L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (SPARC does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) != 0) \ + fprintf (FILE, "\t.align %d\n", (1<<(LOG))) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.skip %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".global ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fputs ("\n.common ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,\"bss\"\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\n.reserve ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,\"bss\"\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On SPARC, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. + It can also be `m', meaning that X is a memory reference but print + its address as a non-memory operand. + + Codes C, N, F, I, and U are used for printing the opcodes of conditional + branches. C prints the opcode for a given condition; N the negated opcode. + F prints the negated floating point opcode (different because of nans). + I prints the opcode that ignores the overflow bit, and U its negation. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if ((CODE) == 'm') \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == MEM) \ + { \ + fputc ('[', FILE); \ + output_address (XEXP (X, 0)); \ + fputc (']', FILE); \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + abort (); \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "%%g0"); \ + else if ((CODE) == 'C') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("e", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GT: fputs ("g", FILE); break; \ + case GE: fputs ("ge", FILE); break; \ + case LT: fputs ("l", FILE); break; \ + case LE: fputs ("le", FILE); break; \ + case GTU: fputs ("gu", FILE); break; \ + case GEU: fputs ("geu", FILE); break; \ + case LTU: fputs ("lu", FILE); break; \ + case LEU: fputs ("leu", FILE); break; \ + } \ + else if ((CODE) == 'I') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("e", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GE: fputs ("pos", FILE); break; \ + case LT: fputs ("neg", FILE); break; \ + default: \ + abort (); \ + } \ + else if ((CODE) == 'U') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("e", FILE); break; \ + case GE: fputs ("neg", FILE); break; \ + case LT: fputs ("pos", FILE); break; \ + default: \ + abort (); \ + } \ + else if ((CODE) == 'N') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("e", FILE); break; \ + case GT: fputs ("le", FILE); break; \ + case GE: fputs ("l", FILE); break; \ + case LT: fputs ("ge", FILE); break; \ + case LE: fputs ("g", FILE); break; \ + case GTU: fputs ("leu", FILE); break; \ + case GEU: fputs ("lu", FILE); break; \ + case LTU: fputs ("geu", FILE); break; \ + case LEU: fputs ("gu", FILE); break; \ + } \ + else if ((CODE) == 'F') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("e", FILE); break; \ + case GT: fputs ("ule", FILE); break; \ + case GE: fputs ("ul", FILE); break; \ + case LT: fputs ("uge", FILE); break; \ + case LE: fputs ("ug", FILE); break; \ + default: abort (); \ + } \ + else { output_addr_const (FILE, X); }} + +/* Print a memory address as an operand to reference that memory location. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx base, index = 0; \ + int offset = 0; \ + register rtx addr = ADDR; \ + if (GET_CODE (addr) == REG) \ + { \ + fprintf (FILE, "%s", reg_names[REGNO (addr)]); \ + } \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == CONST_INT) \ + offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);\ + else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);\ + else \ + base = XEXP (addr, 0), index = XEXP (addr, 1); \ + fprintf (FILE, "%s", reg_names[REGNO (base)]); \ + if (index == 0) \ + fprintf (FILE, "%+d", offset); \ + else \ + fprintf (FILE, "+%s", reg_names[REGNO (index)]); \ + } \ + else \ + { \ + output_addr_const (FILE, addr); \ + } \ +} + diff --git a/gcc-1.40/config/tm-spur.h b/gcc-1.40/config/tm-spur.h new file mode 100644 index 0000000..485b07f --- /dev/null +++ b/gcc-1.40/config/tm-spur.h @@ -0,0 +1,1033 @@ +/* Definitions of target machine for GNU compiler, for SPUR chip. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dspur" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (spur)"); + +/* Run-time compilation parameters selecting different hardware subsets. + + On the SPUR, we don't yet need any. */ + +extern int target_flags; + +/* Nonzero if we should generate code to use the fpu. */ +#define TARGET_FPU (target_flags & 1) + +/* Nonzero if we should expand constant shifts into series of shift + instructions. */ +#define TARGET_EXPAND_SHIFTS (target_flags & 2) + +/* Nonzero if we should generate long jumps for compares. */ +#define TARGET_LONG_JUMPS (target_flags & 4) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { {"fpu", 1}, \ + {"soft-float", -1}, \ + {"expand-shifts", 2}, \ + {"lib-shifts", -2}, \ + {"long-jumps", 4}, \ + {"short-jumps", -4}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 0 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is a moot question on the SPUR due to the lack of bit-field insns. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on SPUR. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* For SPUR we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 64 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 64 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + + SPUR has 32 fullword registers and 15 floating point registers. */ + +#define FIRST_PSEUDO_REGISTER 47 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On SPUR, this includes all the global registers + and the callee return address register. */ +#define FIXED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, \ + 1, 0, 0, 0, 0, 0, \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, \ + 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On SPUR, ordinary registers hold 32 bits worth; + a single floating point register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 32 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On SPUR, the cpu registers can hold any mode but the float registers + can hold only SFmode or DFmode. And they can't hold anything if use + of hardware floating point is disabled. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((REGNO) < 32 && (GET_MODE_SIZE (MODE) <= 4 || (REGNO) < 31)) \ + || (TARGET_FPU && ((MODE) == SFmode || (MODE) == DFmode))) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* SPUR pc isn't overloaded on a register that the compiler knows about. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 4 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 25 + +/* Register in which static-chain is passed to a function. */ +/* ??? */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 27 +#define STRUCT_VALUE_INCOMING_REGNUM 11 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The 68000 has two kinds of registers, hence four classes. */ + +enum reg_class { NO_REGS, GENERAL_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "GENERAL_REGS", "FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {{0, 0}, {-1, 0}, {0, 0x7fff}, {-1, 0x7fff}} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) >= 32 ? FP_REGS : GENERAL_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_REGS : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For SPUR, `I' is used for the range of constants an insn + can actually contain. + `J' is used for the range which is just zero (since that is R0). + `K' is used for the 5-bit operand of a compare insns. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) ((VALUE) + 0x2000) < 0x4000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On SPUR, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On SPUR, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On SPUR the value is found in the second "output" register. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 27) + +/* But the called function leaves it in the second "input" register. */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 11) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 27) + +/* 1 if N is a possible register number for a function value + as seen by the caller. + On SPUR, the first "output" reg is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 27) + +/* 1 if N is a possible register number for function argument passing. + On SPUR, these are the "output" registers. */ + +#define FUNCTION_ARG_REGNO_P(N) ((N) < 32 && (N) > 26) + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On SPUR, this is a single integer, which is a number of words + of arguments scanned so far (including the invisible argument, + if any, which holds the structure-value-address). + Thus 5 or more means all following args should go on the stack. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On SPUR, the offset normally starts at 0, but starts at 4 bytes + when the function gets a structure-value-address as an + invisible first argument. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = ((FNTYPE) != 0 && aggregate_value_p ((FNTYPE)))) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4)) + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On SPUR the first five words of args are normally in registers + and the rest are pushed. But any arg that won't entirely fit in regs + is pushed. Also, any non-word-aligned structure is pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(5 >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), 27 + (CUM)) \ + : 0) + +/* Define where a function finds its arguments. + This is different from FUNCTION_ARG because of register windows. */ + +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ +(5 >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), 11 + (CUM)) \ + : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +/* On spur, move-double insns between fpu and cpu need an 8-byte block + of memory. If any fpu reg is used in the function, we allocate + such a block here, at the bottom of the frame, just in case it's needed. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int current_function_pretend_args_size; \ + int fsize = ((SIZE) + 7) & ~7; \ + int nregs, i, fp_used = 0; \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + if (regs_ever_live[i]) fp_used = 1; \ + } \ + if (fp_used) fsize += 8; \ + fprintf (FILE, "0:\trd_special r24,pc\n"); \ + fprintf (FILE, "\tand r24,r24,$~0x3\n"); \ + fprintf (FILE, "\tadd_nt r25,r4,$%d\n", \ + - current_function_pretend_args_size); \ + if (fsize + nregs != 0 || current_function_pretend_args_size > 0)\ + { \ + int n = - fsize - nregs * 16; \ + if (n >= -8192) \ + fprintf (FILE, "\tadd_nt r4,r25,$%d\n", n); \ + else \ + { \ + fprintf (FILE, "\tadd_nt r4,r25,$-8192\n"); \ + n += 8192; \ + while (n < -8192) \ + fprintf (FILE, "\tadd_nt r4,r4,$-8192\n"), n += 8192; \ + if (n != 0) \ + fprintf (FILE, "\tadd_nt r4,r4,$%d\n", n); \ + } \ + } \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + fprintf (FILE, "\tst_ext1 %s,r4,$%d\n", \ + reg_names[i], 8 * nregs++); \ + fprintf (FILE, "\tst_ext2 %s,r4,$%d\n", \ + reg_names[i], 8 * nregs++); \ + } \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + abort (); + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +extern int may_call_alloca; +extern int current_function_pretend_args_size; + +#define EXIT_IGNORE_STACK \ + (get_frame_size () != 0 \ + || may_call_alloca || current_function_pretend_args_size) + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int may_call_alloca; \ + extern int current_function_pretend_args_size; \ + int fsize = ((SIZE) + 7) & ~7; \ + int nregs, i, fp_used = 0; \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + if (regs_ever_live[i]) fp_used = 1; \ + } \ + if (fp_used) fsize += 8; \ + if (nregs != 0) \ + { \ + fprintf (FILE, "\tadd_nt r4,r25,$%d\n", - fsize - nregs * 16); \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + fprintf (FILE, "\tld_ext1 %s,r4,$%d\n\tnop\n", \ + reg_names[i], 8 * nregs++); \ + fprintf (FILE, "\tld_ext2 %s,r4,$%d\n\tnop\n", \ + reg_names[i], 8 * nregs++); \ + } \ + } \ + if (fsize != 0 || nregs != 0 || may_call_alloca \ + || current_function_pretend_args_size > 0) \ + fprintf (FILE, "\tadd_nt r4,r25,$%d\n", \ + current_function_pretend_args_size); \ + fprintf (FILE, "\treturn r10,$8\n\tnop\n"); \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 0x20) < 14 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 14) + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the SPUR, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x2000) < 0x4000)\ + || (GET_CODE (X) == SYMBOL_REF && (X)->unchanging)) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) (((unsigned) REGNO (X)) - 32 >= 14) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (((unsigned) REGNO (X)) - 32 >= 14) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + On SPUR, the actual legitimate addresses must be REG+SMALLINT or REG+REG. + Actually, REG+REG is not legitimate for stores, so + it is obtained only by combination on loads. + We can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (GET_CODE (X) == REG \ + && REG_OK_FOR_BASE_P (X)) \ + goto ADDR; \ + if (GET_CODE (X) == SYMBOL_REF && (X)->unchanging) \ + goto ADDR; \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && INTVAL (XEXP (X, 1)) >= -0x2000 \ + && INTVAL (XEXP (X, 1)) < 0x2000) \ + goto ADDR; \ + } \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. */ + +/* On SPUR, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (memory_address_p (MODE, X)) \ + goto WIN; } + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the SPUR this is never true. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 0 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 1 + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* Don't try to use the `x' type-cross-reference character in DBX data. + Also has the consequence of putting each struct, union or enum + into a separate .stabs, containing only cross-refs to the others. */ +#define DBX_NO_XREFS + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE SImode + +/* Define this if addresses of constant functions + shouldn't be put through pseudo regs where they can be cse'd. + Desirable on machines where ordinary constants are expensive + but a CALL with constant address is cheap. */ +#define NO_FUNCTION_CSE + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (INTVAL (RTX) < 0x2000 && INTVAL (RTX) >= -0x2000) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* (None are needed on SPUR.) */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* The SPUR does not really have a condition code. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ CC_STATUS_INIT; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r30", "r31", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", \ + "f10", "f11", "f12", "f13", "f14" } + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double %.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.single %.12e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output code to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tadd_nt r4,r4,$-4\n\tst_32 %s,r4,$0\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tld_32 %s,r4,$0\n\tadd_nt r4,r4,$4\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (SPUR does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) != 0) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On SPUR, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + abort (); \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "r0"); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* Print a memory address as an operand to reference that memory location. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx base, index = 0; \ + int offset = 0; \ + register rtx addr = ADDR; \ + if (GET_CODE (addr) == REG) \ + { \ + fprintf (FILE, "%s,$0", reg_names[REGNO (addr)]); \ + } \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == CONST_INT) \ + offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);\ + else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);\ + else \ + base = XEXP (addr, 0), index = XEXP (addr, 1); \ + fprintf (FILE, "%s,", reg_names[REGNO (base)]); \ + if (index == 0) \ + fprintf (FILE, "$%d", offset); \ + else \ + fprintf (FILE, "%s,", reg_names[REGNO (index)]); \ + } \ + else \ + { \ + fprintf (FILE, "r24,$("); \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "-0b)"); \ + } \ +} diff --git a/gcc-1.40/config/tm-sun2.h b/gcc-1.40/config/tm-sun2.h new file mode 100644 index 0000000..6ae8d86 --- /dev/null +++ b/gcc-1.40/config/tm-sun2.h @@ -0,0 +1,67 @@ +/* Definitions of target machine for GNU compiler. Sun 68010 version. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-m68k.h" + +/* See tm-m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT 0 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix" + +/* Prevent error on `-sun2' and `-target sun2' options. */ + +#define CC1_SPEC "%{sun2:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "target")) + +/* Specify what to link with. */ + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} " + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO diff --git a/gcc-1.40/config/tm-sun2os4.h b/gcc-1.40/config/tm-sun2os4.h new file mode 100644 index 0000000..17b4c49 --- /dev/null +++ b/gcc-1.40/config/tm-sun2os4.h @@ -0,0 +1,57 @@ +/* Definitions of target machine for GNU compiler. For Sun 2 running Sunos 4. + Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-sun2.h" + +#undef LINK_SPEC +#define LINK_SPEC "%{!e*:-e start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{-Bstatic}" + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000,0\n") \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000\n") \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.9g", (VALUE))) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.20g", (VALUE))) diff --git a/gcc-1.40/config/tm-sun3-nfp.h b/gcc-1.40/config/tm-sun3-nfp.h new file mode 100644 index 0000000..0a6005d --- /dev/null +++ b/gcc-1.40/config/tm-sun3-nfp.h @@ -0,0 +1,5 @@ +/* Define target machine as a Sun 3 with no 68881. */ + +#define TARGET_DEFAULT 5 + +#include "tm-sun3.h" diff --git a/gcc-1.40/config/tm-sun3.h b/gcc-1.40/config/tm-sun3.h new file mode 100644 index 0000000..90f54b0 --- /dev/null +++ b/gcc-1.40/config/tm-sun3.h @@ -0,0 +1,186 @@ +/* Definitions of target machine for GNU compiler. Sun 68000/68020 version. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This comment is here to see if it will keep Sun's cpp from dying. */ + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +/* Define __HAVE_FPA__ or __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else +#if TARGET_DEFAULT & 0100 + +/* -mfpa is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{m68881:-D__HAVE_68881__ }%{!m68881:-D__HAVE_FPA__ }}\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#endif +#endif + +/* Prevent error on `-sun3' and `-target sun3' options. */ + +#define CC1_SPEC "%{sun3:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "target")) + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix" + +/* STARTFILE_SPEC to include sun floating point initialization + This is necessary (tr: Sun does it) for both the m68881 and the fpa + routines. + Note that includes knowledge of the default specs for gcc, ie. no + args translates to the same effect as -m68881 + I'm not sure what would happen below if people gave contradictory + arguments (eg. -msoft-float -mfpa) */ + +#if TARGET_DEFAULT & 0100 +/* -mfpa is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{m68881:Mcrt1.o%s} \ + %{msoft-float:Fcrt1.o%s} \ + %{!m68881:%{!msoft-float:Wcrt1.o%s}}" +#else +#if TARGET_DEFAULT & 2 +/* -m68881 is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{mfpa:Wcrt1.o%s} \ + %{msoft-float:Fcrt1.o%s} \ + %{!mfpa:%{!msoft-float:Mcrt1.o%s}}" +#else +/* -msoft-float is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{m68881:Mcrt1.o%s} \ + %{mfpa:Wcrt1.o%s} \ + %{!m68881:%{!mfpa:Fcrt1.o%s}}" +#endif +#endif + +/* Specify library to handle `-a' basic block profiling. */ + +/* Specify library to handle `-a' basic block profiling. + Control choice of libm.a (if user says -lm) + based on fp arith default and options. */ + +#if TARGET_DEFAULT & 0100 +/* -mfpa is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft}%{m68881:-L/usr/lib/f68881}\ +%{!msoft_float:%{!m68881:-L/usr/lib/ffpa}}" +#else +#if TARGET_DEFAULT & 2 +/* -m68881 is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft}%{!msoft-float:%{!mfpa:-L/usr/lib/f68881}}\ +%{mfpa:-L/usr/lib/ffpa}" +#else +/* -msoft-float is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{!m68881:%{!mfpa:-L/usr/lib/fsoft}}%{m68881:-L/usr/lib/f68881}\ +%{mfpa:-L/usr/lib/ffpa}" +#endif +#endif + +/* Provide required defaults for linker -e and -d switches. + Also, it is hard to debug with shared libraries, + so don't use them if going to debug. */ + +#define LINK_SPEC "%{!e*:-e start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{-Bstatic}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000,0\n") \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000\n") \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.9g", (VALUE))) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.20g", (VALUE))) diff --git a/gcc-1.40/config/tm-sun386.h b/gcc-1.40/config/tm-sun386.h new file mode 100644 index 0000000..0b54855 --- /dev/null +++ b/gcc-1.40/config/tm-sun386.h @@ -0,0 +1,218 @@ +/* Definitions for Sun assembler syntax for the Intel 80386. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#define TARGET_VERSION fprintf (stderr, " (80386, Sun syntax)"); + +/* Define the syntax of instructions and addresses. */ + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +#ifdef __STDC__ +#define AS2(a,b,c) #a " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is L then CH is `l'). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX ".L" + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs ("$", (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs ("$", (FILE)) + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE "\t.byte\t" +#define ASM_SHORT "\t.value\t" +#define ASM_LONG "\t.long\t" +#define ASM_DOUBLE "\t.double\t" + +/* String containing the assembler's comment-starter. */ + +#define COMMENT_BEGIN "/" + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + extern char *version_string, *language_string; \ + { \ + int len = strlen (dump_base_name); \ + char *na = dump_base_name + len; \ + char shorter[15]; \ + /* NA gets DUMP_BASE_NAME sans directory names. */\ + while (na > dump_base_name) \ + { \ + if (na[-1] == '/') \ + break; \ + na--; \ + } \ + strncpy (shorter, na, 14); \ + shorter[14] = 0; \ + fprintf (FILE, "\t.file\t\"%s\"\n", shorter); \ + } \ + fprintf (FILE, "\t.version\t\"%s %s\"\n", \ + language_string, version_string); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) + +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.optim\n") + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "/APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "/NO_APP\n" + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE)) + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\t.text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\t.data" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This is how to store into the string BUF + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + (fputs ("\t.globl\t", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* How to output an ASCII string constant. */ + +#define ASM_OUTPUT_ASCII(FILE, p, size) \ +{ int i=0; \ + while (i < size) \ + { if (i%10 == 0) { if (i!=0) fprintf (FILE, "\n"); \ + fprintf (FILE, ASM_BYTE); } \ + else fprintf (FILE, ","); \ + fprintf (FILE, "0x%x",(p[i++] & 0377)) ;} \ + fprintf (FILE, "\n"); } diff --git a/gcc-1.40/config/tm-sun386i.h b/gcc-1.40/config/tm-sun386i.h new file mode 100644 index 0000000..edcebfe --- /dev/null +++ b/gcc-1.40/config/tm-sun386i.h @@ -0,0 +1,105 @@ +/* Definitions for Intel 386 running SunOS 4.0. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-i386.h" + +/* Use the Sun assembler syntax. */ + +#include "tm-sun386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Use crt0.o as a startup file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}\ +%{sun386:}" +/* That last item is just to prevent a spurious error. */ + +/* It is hard to debug with shared libraries, + so don't use them if going to debug. */ + +#undef LINK_SPEC +#define LINK_SPEC "%{!e*:-e _start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{-Bstatic}" + +/* Extra switches to give the assembler. */ + +#define ASM_SPEC "-i386" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386 -Dsun386 -Dsun" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We don't want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Force structure alignment to the type used for a bitfield. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +/* This is partly guess. */ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ + ((n) == 0 ? 11 : (n) == 1 ? 9 : (n) == 2 ? 10 : (n) == 3 ? 8 \ + : (n) == 4 ? 5 : (n) == 5 ? 4 : (n) == 6 ? 6 : (n)) + +/* Every debugger symbol must be in the text section. + Otherwise the assembler or the linker screws up. */ + +#define DEBUG_SYMS_TEXT + +/* This NOP insn makes profiling not fail. */ + +#define ASM_IDENTIFY_GCC(FILE) \ +fprintf (FILE, (profile_flag ? "gcc_compiled.:\n\tnop\n" : "gcc_compiled.:\n")) diff --git a/gcc-1.40/config/tm-sun3mach.h b/gcc-1.40/config/tm-sun3mach.h new file mode 100644 index 0000000..602da86 --- /dev/null +++ b/gcc-1.40/config/tm-sun3mach.h @@ -0,0 +1,8 @@ +#include "tm-sun3.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dsun3 -Dunix -DMACH -DCMU -DMTXINU -DBIT_MSF -DBYTE_MSF" + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC diff --git a/gcc-1.40/config/tm-sun3os3.h b/gcc-1.40/config/tm-sun3os3.h new file mode 100644 index 0000000..c4afb4e --- /dev/null +++ b/gcc-1.40/config/tm-sun3os3.h @@ -0,0 +1,5 @@ +#include "tm-sun3.h" + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC diff --git a/gcc-1.40/config/tm-sun3os3nf.h b/gcc-1.40/config/tm-sun3os3nf.h new file mode 100644 index 0000000..44e57f7 --- /dev/null +++ b/gcc-1.40/config/tm-sun3os3nf.h @@ -0,0 +1,5 @@ +#include "tm-sun3-nfp.h" + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC diff --git a/gcc-1.40/config/tm-sun4os3.h b/gcc-1.40/config/tm-sun4os3.h new file mode 100644 index 0000000..a0334d9 --- /dev/null +++ b/gcc-1.40/config/tm-sun4os3.h @@ -0,0 +1,15 @@ +#include "tm-sparc.h" + +/* Define the Sun-asm flag, which is necessary for Sun 4 with os version 3. */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 7 + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tsethi %%hi(LP%d),%%o0\n\tcall .mcount\n\tor %%lo(LP%d),%%o0,%%o0\n", \ + (LABELNO), (LABELNO)) + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC + diff --git a/gcc-1.40/config/tm-tahoe.h b/gcc-1.40/config/tm-tahoe.h new file mode 100644 index 0000000..de9901f --- /dev/null +++ b/gcc-1.40/config/tm-tahoe.h @@ -0,0 +1,850 @@ +/* Definitions of target machine for GNU compiler. Tahoe version. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * File: tm-tahoe.h + * + * This port made at the University of Buffalo by Devon Bowen, + * Dale Wiles and Kevin Zachmann. + * + * Mail bugs reports or fixes to: gcc@cs.buffalo.edu + */ + + +/* + * Run-time Target Specification + */ + +/* we want "tahoe" and "unix" auto-defined for all future compilations */ + +#define CPP_PREDEFINES "-Dtahoe -Dunix" + +/* have cc1 print that this is the tahoe version */ + +#define TARGET_VERSION printf (" (tahoe)"); + +/* this is required in all tm files to hold flags */ + +extern int target_flags; + +/* Zero if it is safe to output .dfloat and .float pseudos. */ +#define TARGET_HEX_FLOAT (target_flags & 1) + +#define TARGET_DEFAULT 1 + +#define TARGET_SWITCHES \ + { {"hex-float", 1}, \ + {"no-hex-float", -1}, \ + { "", TARGET_DEFAULT} } + + +/* + * Storage Layout + */ + +/* tahoe uses a big endian byte order */ + +#define BYTES_BIG_ENDIAN + +/* tahoe uses a big endian word order */ + +#define WORDS_BIG_ENDIAN + +/* standard byte size is usable on tahoe */ + +#define BITS_PER_UNIT 8 + +/* longs on the tahoe are 4 byte groups */ + +#define BITS_PER_WORD 32 + +/* from the last two params we get 4 bytes per word */ + +#define UNITS_PER_WORD 4 + +/* addresses are 32 bits (one word) */ + +#define POINTER_SIZE 32 + +/* pointers should align every 32 bits */ + +#define POINTER_BOUNDARY 32 + +/* all parameters line up on 32 boundaries */ + +#define PARM_BOUNDARY 32 + +/* stack should line up on 32 boundaries */ + +#define STACK_BOUNDARY 32 + +/* line functions up on 32 bits */ + +#define FUNCTION_BOUNDARY 32 + +/* the biggest alignment the tahoe needs in 32 bits */ + +#define BIGGEST_ALIGNMENT 32 + +/* we have to align after an 'int : 0' in a structure */ + +#define EMPTY_FIELD_BOUNDARY 32 + +/* structures must be made of full bytes */ + +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* tahoe is picky about data alignment */ + +#define STRICT_ALIGNMENT + +/* keep things standard with pcc */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* this section is borrowed from the vax version since the */ +/* formats are the same in both of the architectures */ + +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = 1.7014117331926443e+38; } \ + else if ((d) < -1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = -1.7014117331926443e+38; } \ + else if (((d) > 0) && ((d) < 2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + else if (((d) < 0) && ((d) > -2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + } + + +/* + * Register Usage + */ + +/* define 15 general regs plus one for the floating point reg (FPP) */ + +#define FIRST_PSEUDO_REGISTER 17 + +/* let the compiler know what the fp, sp and pc are */ + +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0} + +/* lots of regs aren't guarenteed to return from a call. The FPP reg */ +/* must be included in these since it can't be saved by the reg mask */ + +#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* The FPP can handle any type, but the others may require as many as */ +/* two regs depending on the mode needed */ + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (REGNO != 16 ? ((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) : 1) + +/* any mode greater than 4 bytes (doubles) can only go in an even regs */ +/* and the FPP can only hold SFmode and DFmode */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (REGNO != 16 ? (GET_MODE_SIZE (MODE) <= 4 ? 1 : (REGNO % 2 - 1)) : \ + (MODE == SFmode || MODE == DFmode)) + +/* if mode1 or mode2, but not both, are doubles then modes cannot be tied */ + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((MODE1 == DFmode) == (MODE2 == DFmode)) + +/* the program counter is reg 15 */ + +#define PC_REGNUM 15 + +/* the stack pointer is reg 14 */ + +#define STACK_POINTER_REGNUM 14 + +/* the frame pointer is reg 13 */ + +#define FRAME_POINTER_REGNUM 13 + +/* tahoe does require an fp */ + +#define FRAME_POINTER_REQUIRED 1 + +/* since tahoe doesn't have a argument pointer, make it the fp */ + +#define ARG_POINTER_REGNUM 13 + +/* this isn't currently used since C doesn't support this feature */ + +#define STATIC_CHAIN_REGNUM 0 + +/* we'll use reg 1 for structure passing cause the destination */ +/* of the eventual movblk requires it to be there anyway. */ + +#define STRUCT_VALUE_REGNUM 1 + + +/* + * Register Classes + */ + +/* tahoe has two types of regs. GENERALY_REGS are all the regs up */ +/* to number 15. FPP_REG is the special floating point processor */ +/* register class (only one reg). */ + +enum reg_class {NO_REGS,GENERAL_REGS,FPP_REG,ALL_REGS,LIM_REG_CLASSES}; + +/* defines the number of reg classes. */ + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* this defines what the classes are officially named for debugging */ + +#define REG_CLASS_NAMES \ + {"NO_REGS","GENERAL_REGS","FPP_REG","ALL_REGS"} + +/* set general regs to be the first 16 regs and the fpp reg to be 17th */ + +#define REG_CLASS_CONTENTS {0,0xffff,0x10000,0x1ffff} + +/* register class for the fpp reg is FPP_REG, all others are GENERAL_REGS */ + +#define REGNO_REG_CLASS(REGNO) (REGNO == 16 ? FPP_REG : GENERAL_REGS) + +/* only gereral registers can be used as a base reg */ + +#define BASE_REG_CLASS GENERAL_REGS + +/* only gereral registers can be used to index */ + +#define INDEX_REG_CLASS GENERAL_REGS + +/* 'a' as a contraint in the md file means the FFP_REG class */ + +#define REG_CLASS_FROM_LETTER(C) (C == 'a' ? FPP_REG : NO_REGS) + +/* any general reg but the fpp can be a base reg */ + +#define REGNO_OK_FOR_BASE_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER - 1 || reg_renumber[regno] >= 0) + +/* any general reg except the pc and fpp can be an index reg */ + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER - 2 || reg_renumber[regno] >= 0) + +/* if your loading a floating point constant, it can't be done */ +/* through a register. Force it to be a memory constant. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_DOUBLE) ? NO_REGS : CLASS) + +/* for the fpp reg, all modes fit; for any others, you need two for doubles */ + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + (CLASS != FPP_REG ? ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) : 1) + +/* we don't define any special constant sizes so all should fail */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) 0 + +/* we don't define any special double sizes so all should fail */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 + + +/* + * Describing Stack Layout + */ + +/* tahoe stack grows from high to low memory */ + +#define STACK_GROWS_DOWNWARD + +/* Define this if longjmp restores from saved registers + rather than from what setjmp saved. */ +#define LONGJMP_RESTORE_FROM_STACK + +/* tahoe call frames grow from high to low memory on the stack */ + +#define FRAME_GROWS_DOWNWARD + +/* the tahoe fp points to the *top* of the frame instead of the */ +/* bottom, so we have to make this offset a constant large enough */ +/* to jump over the biggest frame possible. */ + +#define STARTING_FRAME_OFFSET -52 + +/* tahoe always pushes 4 bytes unless it's a double in which case */ +/* it pushes a full 8 bytes. */ + +#define PUSH_ROUNDING(BYTES) (BYTES <= 4 ? 4 : 8) + +/* the first parameter in a function is at the fp + 4 */ + +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* the tahoe return function takes care of everything on the stack */ + +#define RETURN_POPS_ARGS(FUNTYPE) 1 + +/* function values for all types are returned in register 0 */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* libarary routines also return things in reg 0 */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* Tahoe doesn't return structures in a reentrant way */ + +#define PCC_STATIC_STRUCT_RETURN + +/* we only return values from a function in reg 0 */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* we never pass args through a register */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 + +/* int is fine to hold the argument summary in FUNCTION_ARG */ + +#define CUMULATIVE_ARGS int + +/* we just set CUM to 0 before the FUNCTION_ARG call. No matter what */ +/* we make it, FUNCTION_ARG will return 0 anyway */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* all modes push their size rounded to the nearest word boundary */ +/* except block which is the size of the block rounded up */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* this is always false since we never pass params in regs */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* this code calculates the register entry mask and sets up */ +/* the stack pointer for the function. The stack is set down */ +/* far enough from the fp to jump over any push regs and local */ +/* vars. This is a problem since the tahoe has the fp pointing */ +/* to the top of the frame and the compiler must know the off- */ +/* set off the fp to the local vars. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER-1; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) \ + mask |= 1 << regno; \ + fprintf (FILE, "\t.word 0x%x\n", mask); \ + if (SIZE != 0) fprintf (FILE, "\tsubl3 $%d,fp,sp\n", (SIZE) - STARTING_FRAME_OFFSET); } + +/* to call the profiler, push the variable value onto the stack */ +/* and call mcount like a regular function. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tpushl $LP%d\n\tcallf $8,mcount\n", (LABELNO)); + +/* all stack handling at the end of a function is handled by the */ +/* return command. */ + +#define EXIT_IGNORE_STACK 1 + +/* this never gets executed since the system knows it always gets */ +/* an fp to work with. It just prints a friendly message since the */ +/* person must be playing with the tm file defs */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ + { abort(); } + + +/* + * Library Subroutine Names + */ + +/* udiv is a valid C library routine in libc.a, so we call that */ + +#define UDIVSI3_LIBCALL "*udiv" + +/* urem is a valid C library routine in libc.a, so we call that */ + +#define UMODSI3_LIBCALL "*urem" + + +/* + * Addressing Modes + */ + +/* constant addresses can be treated exactly the same as normal constants */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* we can have as many as two regs in any given address */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* The following is all the code for GO_IF_LEGITIMATE_ADDRESS */ +/* most of this taken directly from the vax tm file since the */ +/* tahoe and vax addressing modes are nearly identicle. */ + +/* Is x an indirectable address? */ + +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) + +/* If x is a non-indexed-address, go to ADDR. */ + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_ADDRESS_P (xfoob)) goto ADDR; \ + xfoob = XEXP (X, 0); \ + if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \ + goto ADDR; \ + if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && GET_CODE (xfoob) == REG && REGNO (xfoob) == 14) \ + goto ADDR; } + +/* Is PROD an index term in mode MODE. */ + +#define INDEX_TERM_P(PROD, MODE) \ +(GET_MODE_SIZE (MODE) == 1 \ + ? (GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \ + : (GET_CODE (PROD) == MULT \ + && \ + (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + ((GET_CODE (xfoo0) == CONST_INT \ + && INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo1) == REG \ + && REG_OK_FOR_INDEX_P (xfoo1)) \ + || \ + (GET_CODE (xfoo1) == CONST_INT \ + && INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo0) == REG \ + && REG_OK_FOR_INDEX_P (xfoo0)))))) + +/* Is the addition to the index a reg? */ + +#define GO_IF_REG_PLUS_INDEX(X, MODE, ADDR) \ +{ register rtx xfooa; \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && (xfooa = XEXP (X, 1), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1)) \ + && (xfooa = XEXP (X, 0), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; } } + +/* Is the rtx X a valid memoy address for operand of mode MODE? */ +/* If it is, go to ADDR */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfoo, xfoo0, xfoo1; \ + GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { xfoo = XEXP (X, 0); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 1), ADDR); } \ + xfoo = XEXP (X, 1); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 0), ADDR); } \ + if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + { if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 1), MODE, ADDR); } \ + if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 0), MODE, ADDR); } } } + +/* Register 16 can never be used for index or base */ + +#ifndef REG_OK_STRICT +#define REG_OK_FOR_INDEX_P(X) (REGNO(X) != 16) +#define REG_OK_FOR_BASE_P(X) (REGNO(X) != 16) +#else +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#endif + +/* Addressing is too simple to allow optimizing here */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Post_inc and pre_dec always adds 4 */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE(ADDR) == POST_INC || GET_CODE(ADDR) == PRE_DEC) \ + goto LABEL; \ + if (GET_CODE (ADDR) == PLUS) \ + { if (CONSTANT_ADDRESS_P (XEXP (ADDR, 0)) \ + && GET_CODE (XEXP (ADDR, 1)) == REG); \ + else if (CONSTANT_ADDRESS_P (XEXP (ADDR, 1)) \ + && GET_CODE (XEXP (ADDR, 0)) == REG); \ + else goto LABEL; }} + +/* Double's are not legitimate as immediate operands */ + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) != CONST_DOUBLE) + + +/* + * Miscellaneous Parameters + */ + +/* the elements in the case jump table are all words */ + +#define CASE_VECTOR_MODE HImode + +/* each of the table elements in a case are relative to the jump addess */ + +#define CASE_VECTOR_PC_RELATIVE + +/* tahoe case instructions just fall through to the next instruction */ +/* if not satisfied. It doesn't support a default action */ + +#define CASE_DROPS_THROUGH + +/* the standard answer is given here and work ok */ + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* in a general div case, it's easiest to use TRUNC_DIV_EXPR */ + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* the standard seems to be leaving char's as signed so we left it */ +/* this way even though we think they should be unsigned! */ + +#define DEFAULT_SIGNED_CHAR 1 + +/* the most we can move without cutting down speed is 4 bytes */ + +#define MOVE_MAX 4 + +/* our int is 32 bits */ + +#define INT_TYPE_SIZE 32 + +/* byte access isn't really slower than anything else */ + +#define SLOW_BYTE_ACCESS 0 + +/* zero extension is more than one instruction so try to avoid it */ + +#define SLOW_ZERO_EXTEND + +/* any bits higher than the low 4 are ignored in the shift count */ +/* so don't bother zero extending or sign extending them */ + +#define SHIFT_COUNT_TRUNCATED + +/* we don't need to officially convert from one fixed type to another */ +/* in order to use it as that type. We can just assume it's the same */ + +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* pass chars as ints */ + +#define PROMOTE_PROTOTYPES + +/* pointers can be represented by an si mode expression */ + +#define Pmode SImode + +/* function addresses are made by specifying a byte address */ + +#define FUNCTION_MODE QImode + +/* all the costs here were borrowed from the vax version of the */ +/* tm file. They're pretty much the same in the tahoe */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + + +/* + * Condition Code Information + */ + +/* Condition codes still break in one case that we haven't tracked */ +/* down yet, so we have to leave them like this for now. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE(EXP) == SET && GET_CODE(SET_DEST(EXP)) == CC0) { \ + cc_status.flags = 0; \ + cc_status.value1 = SET_DEST(EXP); \ + cc_status.value2 = SET_SRC(EXP); \ + } else \ + CC_STATUS_INIT; } + + +/* + * Output of Assembler Code + */ + +/* start the assembly by turning off APP */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n\n"); + +/* the instruction that turns on the APP for the gnu assembler */ + +#define ASM_APP_ON "#APP\n" + +/* the instruction that turns off the APP for the gnu assembler */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* what to output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* what to output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* this is what we call each of the regs. notice that the FPP reg is */ +/* called "ac". This should never get used due to the way we've set */ +/* up FPP instructions in the md file. But we call it "ac" here to */ +/* fill the list. */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "fp", "sp", "pc", "ac"} + +/* registers are called the same thing in dbx anything else */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* allow generation of dbx info in the assembly */ + +#define DBX_DEBUGGING_INFO + +/* our dbx doesn't support this */ + +#define DBX_NO_XREFS + +/* we don't want symbols broken up */ + +#define DBX_CONTIN_LENGTH 0 + +/* this'll really never be used, but we'll leave it at this */ + +#define DBX_CONTIN_CHAR '?' + +/* labels are the label followed by a colon and a newline */ +/* must be a statement, so surround it in a null loop */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* use the .globl directive to make labels global for the linker */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* output a label by appending an underscore to it */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* use the standard format for printing internal labels */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* a * is used for label indirection in unix assembly */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* outputing a double is easy cause we only have one kind */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +{ \ + union { int i[2]; double d;} temp; \ + temp.d = (VALUE); \ + if (TARGET_HEX_FLOAT) \ + fprintf ((FILE), "\t.long 0x%x,0x%x # %.20e\n", \ + temp.i[0], temp.i[1], temp.d); \ + else \ + fprintf (FILE, "\t.dfloat 0d%.20e\n", temp.d); \ +} + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +{ \ + union { int i; float f;} temp; \ + temp.f = (float) (VALUE); \ + if (TARGET_HEX_FLOAT) \ + fprintf ((FILE), "\t.long 0x%x # %.20e\n", \ + temp.i, temp.f); \ + else \ + fprintf (FILE, "\t.float 0f%.20e\n", temp.f); \ +} + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* this is the insn to push a register onto the stack */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpushl %s\n", reg_names[REGNO]) + +/* this is the insn to pop a register from the stack */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovl (sp)+,%s\n", reg_names[REGNO]) + +/* this is required even thought tahoe doesn't support it */ +/* cause the C code expects it to be defined */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This aligns the assembler output */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + LOG ? fprintf (FILE, "\t.align %d\n", (LOG)) : 0 + +/* This is how to skip over some space */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This defines common variables across files */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This defines a common varible in the local file */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* code to generate a label */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* parenthesis for expressions in the assembly */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ + +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print an operand. Some difference from the vax code, + since the tahoe can't support immediate floats and doubles. + + %@ means print the proper alignment operand for aligning after a casesi. + This depends on the assembler syntax. + This is 1 for our assembler, since .align is logarithmic. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '@') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '@') \ + putc ('1', FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* When the operand is an address, call print_operand_address to */ +/* do the work from output-tahoe.c. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) + diff --git a/gcc-1.40/config/tm-tower-as.h b/gcc-1.40/config/tm-tower-as.h new file mode 100644 index 0000000..1edf4dd --- /dev/null +++ b/gcc-1.40/config/tm-tower-as.h @@ -0,0 +1,616 @@ +/* Definitions of target machine for GNU compiler. + Copyright (C) 1990 Free Software Foundation, Inc. + + Written by Robert Andersson, International Systems, Oslo, Norway. + Send bug reports, questions and improvements to ra@intsys.no. + + For NCR Tower 32/4x0 and 32/6x0 running System V Release 3. + This file outputs assembler source suitable for the native Tower as + and with sdb debugging symbols. See tm-tower.h for more comments. + + This file was based on tm-m68k.h, tm-hp9k320.h and tm-3b1.h + as of the 1.37.1 version. + + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-tower.h" + + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also, define special define used to identify the Tower assembler. */ + +#define CPP_SPEC "-D__TOWER_ASM__ %{m68881:-D__HAVE_68881__}" + +/* The startfiles and libraries depend on the -p and -m68881 options. + The Tower does not support the -pg option. */ + +#define STARTFILE_SPEC \ +"%{p:%{m68881:/usr/lib/fp/mcrt1.o}%{!m68881:/lib/mcrt1.o}} \ + %{!p:%{m68881:/usr/lib/fp/crt1.o}%{!m68881:/lib/crt1.o}}" + +/* These four macros control how m68k.md is expanded. */ + +#define MOTOROLA +#define SGS +#define SONY_ASM +#define HPUX_ASM + +/* Turn on SDB debugging info. */ + +#define SDB_DEBUGGING_INFO + +/* This is only useful if gdb is changed, but doesn't harm anyway. */ + +#define ASM_IDENTIFY_GCC(FILE) \ + fprintf (FILE, "gcc_compiled%%:\n") + +/* All the ASM_OUTPUT macros need to conform to the Tower as syntax. */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + fprintf (FILE, "\tfile\t\"%s\"\n", FILENAME) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +#define ASM_OUTPUT_IDENT(FILE, NAME) \ + fprintf (FILE, "\tident\t\"%s\" \n", NAME) + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + { register int sp = 0, lp = 0; \ + fprintf (FILE, "\tbyte\t"); \ + loop: \ + if (PTR[sp] > ' ' && ! (PTR[sp] & 0x80) && PTR[sp] != '\\') \ + { lp += 3; \ + fprintf (FILE, "'%c", PTR[sp]); } \ + else \ + { lp += 5; \ + fprintf (FILE, "0x%x", PTR[sp]); } \ + if (++sp < LEN) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf (FILE, "\n\tbyte\t"); } \ + else \ + putc (',', FILE); \ + goto loop; } \ + putc ('\n', FILE); } + +/* Translate Motorola opcodes such as `jbeq' + into SGS/Tower opcodes such as `beq.w'. + Change `move' to `mov'. + Change `cmpm' to `cmp'. + Change `divsl' to `tdivs'. + Change `divul' to `tdivu'. + Change `ftst' to `ftest'. + Change `fmove' to `fmov'. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; } \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p' && (PTR)[3] == 'm') \ + { fprintf ((FILE), "cmp"); (PTR) += 4; } \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 's' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivs"); (PTR) += 5; } \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'u' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivu"); (PTR) += 5; } \ + else if ((PTR)[0] == 'f' && (PTR)[1] == 't' \ + && (PTR)[2] == 's' && (PTR)[3] == 't') \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if ((PTR)[0] == 'f' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'o' && (PTR)[3] == 'v' \ + && (PTR)[4] == 'e') \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ +} + + + +/* Override parts of tm-m68k.h to fit the Tower assembler. + This section needs to track changes done to tm-m68k.h in the future. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k, Motorola/SGS/Tower32 syntax)"); + +#undef BLOCK_PROFILER +#undef FUNCTION_BLOCK_PROFILER +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount%%\n", (LABEL_NO)) + +/* The prologue is identical to the one in tm-m68k.h except that the + assembler syntax is different. */ + +#undef FUNCTION_PROLOGUE +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (TARGET_68020 || fsize < 0x8000) \ + fprintf (FILE, "\tlink %%a6,&%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink %%a6,&0\n\tsub.l &%d,%%sp\n", fsize); } \ + for (regno = 24; regno < 56; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + fprintf(FILE, "\tfpmoved %s,-(%%sp)\n", \ + reg_names[regno]); \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if ((mask & 0xff) != 0) \ + fprintf (FILE, "\tfmovm &0x%x,-(%%sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovm.l &0x%x,-(%%sp)\n", mask); } + +/* The epilogue is identical to the one in tm-m68k.h except that: + a) The assembler syntax is different. + b) Pointers are returned both in %d0 and %a0. + c) FUNCTION_EXTRA_EPILOGUE is not needed. */ + +#undef FUNCTION_EPILOGUE +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset, fpoffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + extern int current_function_returns_pointer; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; fpoffset = 0; \ + for (regno = 24 ; regno < 56 ; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + fpoffset = nregs*8; \ + nregs = 0; \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = fpoffset + nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask || fpoffset)) \ + { fprintf (FILE, "\tmov.l &%d,%%a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmov.l -%d(%%a6,%%a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmov.l -%d(%%a6),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovm.l -%d(%%a6,%%a0.l),&0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovm.l (%%sp)+,&0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovm.l -%d(%%a6),&0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovm -%d(%%a6,%%a0.l),&0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovm (%%sp)+,&0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovm -%d(%%a6),&0x%x\n", \ + foffset + fsize, fmask); } \ + if (fpoffset != 0) \ + for (regno = 55; regno >= 24; regno--) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) { \ + if (big) \ + fprintf(FILE, "\tfpmoved -%d(%%a6,%%a0.l),%s\n", \ + fpoffset + fsize, reg_names[regno]); \ + else if (! frame_pointer_needed) \ + fprintf(FILE, "\tfpmoved (%%sp)+,%s\n", \ + reg_names[regno]); \ + else \ + fprintf(FILE, "\tfpmoved -%d(%%a6),%s\n", \ + fpoffset + fsize, reg_names[regno]); \ + fpoffset -= 8; \ + } \ + if (current_function_returns_pointer) \ + fprintf (FILE, "\tmov.l %%d0,%%a0\n"); \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk %%a6\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd &%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ +( fprintf (FILE, "#NO_APP\n"), \ + sdbout_filename ((FILE), main_input_filename)) + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "\ttext" + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "\tdata" + +/* This says how to output an assembler line to define a global common symbol. + We use SIZE rather than ROUNDED, as this is what the native cc does. */ + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", ((SIZE) == 0) ? (ROUNDED) : (SIZE))) + +/* This says how to output an assembler line to define a local common symbol. + We use SIZE rather than ROUNDED, as this is what the native cc does. */ + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", ((SIZE) == 0) ? (ROUNDED) : (SIZE))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#undef ASM_FORMAT_PRIVATE_NAME +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 11), \ + sprintf ((OUTPUT), "%s%%%%%d", (NAME), (LABELNO))) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#undef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ +do { fputs ("\tglobal ", FILE); \ + assemble_name (FILE, NAME); \ + fputs ("\n", FILE); \ + } while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf ((FILE), "%s%%%d:\n", (PREFIX), (NUM)) + +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); \ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long l[2]; } tem; \ + tem.d = (VALUE); \ + fprintf(FILE, "\tlong 0x%x,0x%x\n", tem.l[0], tem.l[1]); \ + } while (0) + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\tlong 0x%x\n", tem.l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#undef ASM_OUTPUT_INT +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tlong "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#undef ASM_OUTPUT_SHORT +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tshort "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#undef ASM_OUTPUT_CHAR +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#undef ASM_OUTPUT_BYTE +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tbyte 0x%x\n", (VALUE)) + +#undef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "&"); \ + else if (CODE == '-') fprintf (FILE, "-(%%sp)"); \ + else if (CODE == '+') fprintf (FILE, "(%%sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(%%sp)"); \ + else if (CODE == '!') fprintf (FILE, "%%cc"); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + fprintf (FILE, "&0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + fprintf (FILE, "&0x%x%08x", CONST_DOUBLE_LOW (X), CONST_DOUBLE_HIGH (X));\ + else { putc ('&', FILE); output_addr_const (FILE, X); }} + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that the table is + exactly 10 bytes away. */ + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "10(%%pc,%s.w", \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "10(%%pc,%s.l", \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "10(%%pc,%s.w)", \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + output_addr_const (FILE, addr); \ + }} + + + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); diff --git a/gcc-1.40/config/tm-tower.h b/gcc-1.40/config/tm-tower.h new file mode 100644 index 0000000..68e74a6 --- /dev/null +++ b/gcc-1.40/config/tm-tower.h @@ -0,0 +1,100 @@ +/* Definitions of target machine for GNU compiler. + Copyright (C) 1990 Free Software Foundation, Inc. + + Written by Robert Andersson, International Systems, Oslo, Norway. + Please send bug reports, questions and improvements to ra@intsys.no. + + For NCR Tower 32/4x0 and 32/6x0 running System V Release 3. + I don't have access to 200/700/800/850 machines, so I don't know if it + works on those as well. It shouldn't be far from it however. + The hardware floating point support is completely untested, as I do + not have access to a machine with a 6888x FPU in it. + It does not work on the System V Release 2 based OS releases. Making it + work will not be easy, due to the silly way in which stack expansion is + implemented in the OS. + + This file is included in both tm-tower-as.h and tm-tower-gc.h, and contains + definitions common to both of them. Do *NOT* include this file directly. + + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "tm-m68k.h" + + +/* See tm-m68k.h. 5 means 68020 with no 68881. */ + +#define TARGET_DEFAULT 5 + +/* Names to predefine in the preprocessor for this target machine. */ + +#ifdef tower32_200 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_200" +#endif +#ifdef tower32_600 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_600" +#endif +#ifdef tower32_700 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_700" +#endif +#ifdef tower32_800 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_800" +#endif +#ifdef tower32_850 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_850" +#endif + +/* The startfiles and libraries depend on the -p and -m68881 options. + The Tower does not support the -pg option. */ + +#define LINK_SPEC \ +"%{p:%{m68881:-L/usr/lib/fp/libp} -L/usr/lib/libp} \ + %{m68881:-L/usr/lib/fp}" + +#define LIB_SPEC "-lc %{m68881:/usr/lib/fp/crtn.o}%{!m68881:/lib/crtn.o}" + +/* Use mem* functions, recognize #ident lines. */ + +#define TARGET_MEM_FUNCTIONS +#define IDENT_DIRECTIVE + +/* This is only used in g++, don't prepend underscore. */ + +#define NO_UNDERSCORES + +/* Every structure and union's size must be a multiple of two bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* All register names should have a leading % character. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", \ + "%fpa0", "%fpa1", "%fpa2", "%fpa3", "%fpa4", "%fpa5", "%fpa6", "%fpa7", \ + "%fpa8", "%fpa9", "%fpa10", "%fpa11", "%fpa12", "%fpa13", "%fpa14", "%fpa15",\ + "%fpa16","%fpa17", "%fpa18", "%fpa19", "%fpa20", "%fpa21", "%fpa22","%fpa23",\ + "%fpa24","%fpa25", "%fpa26", "%fpa27", "%fpa28", "%fpa29", "%fpa30","%fpa31"} + +/* We do not want leading underscores. */ + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) diff --git a/gcc-1.40/config/tm-ultrix.h b/gcc-1.40/config/tm-ultrix.h new file mode 100644 index 0000000..025dc0d --- /dev/null +++ b/gcc-1.40/config/tm-ultrix.h @@ -0,0 +1,7 @@ +#include "tm-vax.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dultrix -Dbsd4_2 -Dvax -Dunix -D__vax" + +/* By default, allow $ to be part of an identifier. */ +#define DOLLARS_IN_IDENTIFIERS 1 diff --git a/gcc-1.40/config/tm-vax.h b/gcc-1.40/config/tm-vax.h new file mode 100644 index 0000000..f92af96 --- /dev/null +++ b/gcc-1.40/config/tm-vax.h @@ -0,0 +1,1080 @@ +/* Definitions of target machine for GNU compiler. Vax version. + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dvax -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (vax)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Nonzero if compiling code that Unix assembler can assemble. */ +#define TARGET_UNIX_ASM (target_flags & 1) + +/* Nonzero if compiling with VAX-11 "C" style structure alignment */ +#define TARGET_VAXC_ALIGNMENT (target_flags & 2) + +/* Nonzero if compiling with `G'-format floating point */ +#define TARGET_G_FLOAT (target_flags & 4) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { {"unix", 1}, \ + {"gnu", -1}, \ + {"vaxc-alignment", 2}, \ + {"g", 4}, \ + {"g-float", 4}, \ + {"d", -4}, \ + {"d-float", -4}, \ + { "", TARGET_DEFAULT}} + +/* Default target_flags if no switches specified. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 1 +#endif + +/* Target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the vax. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the vax. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* This is not true on the vax. */ +/* #define WORDS_BIG_ENDIAN */ + +/* Number of bits in an addressible storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY (TARGET_VAXC_ALIGNMENT ? 8 : 32) + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY (TARGET_VAXC_ALIGNMENT ? 8 : 32) + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS (! TARGET_VAXC_ALIGNMENT) + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT (TARGET_VAXC_ALIGNMENT ? 8 : 32) + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +/* #define STRICT_ALIGNMENT */ + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ +#define FIRST_PSEUDO_REGISTER 16 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the vax, these are the AP, FP, SP and PC. */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + On the vax, all registers are one word long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the vax, all registers can hold all modes. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) 1 + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Vax pc is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 14 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 13 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 12 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 0 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 1 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The vax has only one kind of registers, so NO_REGS and ALL_REGS + are the only classes. */ + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS {0, 0xffff} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) ALL_REGS + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS ALL_REGS +#define BASE_REG_CLASS ALL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) NO_REGS + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) 0 + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the vax, this is always the size of MODE in words, + since all registers are the same size. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if longjmp restores from saved registers + rather than from what setjmp saved. */ +#define LONGJMP_RESTORE_FROM_STACK + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the vax, -(sp) pushes only the bytes of the operands. */ +#define PUSH_ROUNDING(BYTES) (BYTES) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + On the Vax, the RET insn always pops all the args for any function. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 1 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the Vax the return value is in R0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the Vax the return value is in R0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the Vax, R0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* 1 if N is a possible register number for function argument passing. + On the Vax, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the vax, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the vax, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the vax all args are pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) \ + mask |= 1 << regno; \ + fprintf (FILE, "\t.word 0x%x\n", mask); \ + MAYBE_VMS_FUNCTION_PROLOGUE(FILE) \ + if ((SIZE) >= 64) fprintf (FILE, "\tmovab %d(sp),sp\n", -SIZE);\ + else if (SIZE) fprintf (FILE, "\tsubl2 $%d,sp\n", (SIZE)); } + +/* tm-vms.h redefines this. */ +#define MAYBE_VMS_FUNCTION_PROLOGUE(FILE) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmovab LP%d,r0\n\tjsb mcount\n", (LABELNO)); + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\ttstl LPBX0\n\tjneq LPI%d\n\tpushal LPBX0\n\tcalls $1,__bb_init_func\nLPI%d:\n", \ + LABELNO, LABELNO); + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. This is a real pain in the + sphincter on a VAX, since we do not want to change any of the bits in the + processor status word. The way it is done here, it is pushed onto the stack + before any flags have changed, and then the stack is fixed up to account for + the fact that the instruction to restore the flags only reads a word. + It may seem a bit clumsy, but at least it works. +*/ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, "\tmovpsl -(sp)\n\tmovw (sp),2(sp)\n\taddl2 $2,sp\n\taddl2 $1,LPBX2+%d\n\tbicpsw $255\n\tbispsw (sp)+\n", \ + 4 * BLOCKNO) + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 1 + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. */ + +/* #define FUNCTION_EPILOGUE(FILE, SIZE) */ + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT +/* #define HAVE_POST_DECREMENT */ + +#define HAVE_PRE_DECREMENT +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) +#define REGNO_OK_FOR_BASE_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X) && LEGITIMATE_CONSTANT_P (X)) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#ifdef NO_EXTERNAL_INDIRECT_ADDRESS +#define LEGITIMATE_CONSTANT_P(X) \ + (! (GET_CODE ((X)) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == SYMBOL_REF \ + && EXTERNAL_SYMBOL_P (XEXP (XEXP ((X), 0), 0)))) +#else +#define LEGITIMATE_CONSTANT_P(X) 1 +#endif + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) 1 +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) 1 + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is actually machine-independent. */ + +/* 1 if X is an address that we could indirect through. */ +#ifdef NO_EXTERNAL_INDIRECT_ADDRESS +#define INDIRECTABLE_CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == SYMBOL_REF && !EXTERNAL_SYMBOL_P (X)) \ + || (GET_CODE (X) == CONST && LEGITIMATE_CONSTANT_P(X)) \ + || GET_CODE (X) == CONST_INT) + +#define INDIRECTABLE_ADDRESS_P(X) \ + (INDIRECTABLE_CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && INDIRECTABLE_CONSTANT_ADDRESS_P (XEXP (X, 1)))) +#else +#define INDIRECTABLE_CONSTANT_ADDRESS_P(X) CONSTANT_ADDRESS_P(X) +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) +#endif + +/* Non-zero if this is a valid address without indexing or indirection. */ +#define NONINDIRECT_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (NONINDIRECT_ADDRESS_P (xfoob)) goto ADDR; \ + xfoob = XEXP (X, 0); \ + if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \ + goto ADDR; \ + if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && GET_CODE (xfoob) == REG && REG_OK_FOR_BASE_P (xfoob)) \ + goto ADDR; } + +/* 1 if PROD is either a reg times size of mode MODE + or just a reg, if MODE is just one byte. + This macro's expansion uses the temporary variables xfoo0 and xfoo1 + that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +(GET_MODE_SIZE (MODE) == 1 \ + ? (GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \ + : (GET_CODE (PROD) == MULT \ + && \ + (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + ((GET_CODE (xfoo0) == CONST_INT \ + && INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo1) == REG \ + && REG_OK_FOR_INDEX_P (xfoo1)) \ + || \ + (GET_CODE (xfoo1) == CONST_INT \ + && INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo0) == REG \ + && REG_OK_FOR_INDEX_P (xfoo0)))))) + +/* Go to ADDR if X is the sum of a register + and a valid index term for mode MODE. */ +#define GO_IF_REG_PLUS_INDEX(X, MODE, ADDR) \ +{ register rtx xfooa; \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && (xfooa = XEXP (X, 1), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1)) \ + && (xfooa = XEXP (X, 0), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; } } + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfoo, xfoo0, xfoo1; \ + GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { /* Handle <address>[index] represented with index-sum outermost */\ + xfoo = XEXP (X, 0); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 1), ADDR); } \ + xfoo = XEXP (X, 1); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 0), ADDR); } \ + /* Handle offset(reg)[index] with offset added outermost */ \ + if (INDIRECTABLE_CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + { if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 1), MODE, ADDR); } \ + if (INDIRECTABLE_CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 0), MODE, ADDR); } } } + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the vax, nothing needs to be done. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the VAX, the predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand) + and all indexed address depend thus (because the index scale factor + is the length of the operand). */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \ + goto LABEL; \ + if (GET_CODE (ADDR) == PLUS) \ + { if (CONSTANT_ADDRESS_P (XEXP (ADDR, 0)) \ + && GET_CODE (XEXP (ADDR, 1)) == REG); \ + else if (CONSTANT_ADDRESS_P (XEXP (ADDR, 1)) \ + && GET_CODE (XEXP (ADDR, 0)) == REG); \ + else goto LABEL; }} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* Define this if the case instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE + +/* Define this if the case instruction drops through after the table + when the index is out of range. Don't define it if the case insn + jumps to the default label instead. */ +#define CASE_DROPS_THROUGH + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +#define FIXUNS_TRUNC_LIKE_FIX_TRUNC + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 8 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* #define SHIFT_COUNT_TRUNCATED */ + +/* Shift counts can be negative. */ +#define NEGATIVE_SHIFT_COUNTS 1 + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* + * We can use the BSD C library routines for the gnulib calls that are + * still generated, since that's what they boil down to anyways. + */ + +#define UDIVSI3_LIBCALL "*udiv" +#define UMODSI3_LIBCALL "*urem" + +/* Check a `double' value for validity for a particular machine mode. */ + +/* note that it is very hard to accidently create a number that fits in a + double but not in a float, since their ranges are almost the same */ +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 1.7014117331926444e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = 1.7014117331926444e+38; } \ + else if ((d) < -1.7014117331926444e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = -1.7014117331926444e+38; } \ + else if (((d) > 0) && ((d) < 2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + else if (((d) < 0) && ((d) > -2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + } + +/* For future reference: + D Float: 9 bit, sign magnitude, excess 128 binary exponent + normalized 56 bit fraction, redundant bit not represented + approximately 16 decimal digits of precision + + The values to use if we trust decimal to binary conversions: +#define MAX_D_FLOAT 1.7014118346046923e+38 +#define MIN_D_FLOAT .29387358770557188e-38 + + G float: 12 bit, sign magnitude, excess 1024 binary exponent + normalized 53 bit fraction, redundant bit not represented + approximately 15 decimal digits precision + + The values to use if we trust decimal to binary conversions: +#define MAX_G_FLOAT .898846567431157e+308 +#define MIN_G_FLOAT .556268464626800e-308 +*/ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the vax. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_SRC (EXP)) == CALL) \ + CC_STATUS_INIT; \ + else if (GET_CODE (SET_DEST (EXP)) != PC) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); } } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET \ + && GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) != PC) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); } \ + /* PARALLELs whose first element sets the PC are aob, sob insns. \ + They do change the cc's. So drop through and forget the cc's. */ \ + else CC_STATUS_INIT; \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + cc_status.value2 = 0; \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM \ + && cc_status.value2 \ + && GET_CODE (cc_status.value2) == MEM) \ + cc_status.value2 = 0; } +/* Actual condition, one line up, should be that value2's address + depends on value1, but that is too much of a pain. */ + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "ap", "fp", "sp", "pc"} + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* How to renumber registers for dbx and gdb. + Vax needs no change in the numeration. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* Output the .stabs for a C `static' variable in the data section. */ +#define DBX_STATIC_STAB_DATA_SECTION + +/* Vax specific: which type character is used for type double? */ + +#define ASM_DOUBLE_CHAR (TARGET_G_FLOAT ? 'g' : 'd') + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. + It is .dfloat or .gfloat, depending. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.%cfloat 0%c%.20e\n", ASM_DOUBLE_CHAR, \ + ASM_DOUBLE_CHAR, (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpushl %s\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovl (sp)+,%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The Vax does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. + On the Vax, the only code used is `#', indicating that either + `d' or `g' should be printed, depending on whether we're using dfloat + or gfloat. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '#') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '#') fputc (ASM_DOUBLE_CHAR, FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0%c%.20e", ASM_DOUBLE_CHAR, u.d); } \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* Print a memory operand whose address is X, on file FILE. + This uses a function in output-vax.c. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) diff --git a/gcc-1.40/config/tm-vaxv.h b/gcc-1.40/config/tm-vaxv.h new file mode 100644 index 0000000..78fbf05 --- /dev/null +++ b/gcc-1.40/config/tm-vaxv.h @@ -0,0 +1,62 @@ +/* Definitions of target machine for GNU compiler. Vax sysV version. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-vax.h" + +/* Cope with these under SysV */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +#undef DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf(FILE, "\t.align %d\n", 1 << (LOG)) + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE,NAME,SIZE,ROUNDED) \ +( data_section (), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ":\n\t.space %u\n", (ROUNDED))) + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +{ \ + char *s; \ + int i; \ + for (i = 0, s = (PTR); i < (LEN); s++, i++) \ + { \ + if ((i % 8) == 0) \ + fputs ("\n\t.byte\t", (FILE)); \ + fprintf ((FILE), "%s0x%x", (i%8?",":""), (unsigned)*s); \ + } \ + fputs ("\n", (FILE)); \ +} + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) diff --git a/gcc-1.40/config/tm-vms.h b/gcc-1.40/config/tm-vms.h new file mode 100644 index 0000000..2e91a73 --- /dev/null +++ b/gcc-1.40/config/tm-vms.h @@ -0,0 +1,117 @@ +/* Output variables, constants and external declarations, for GNU compiler. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define NO_EXTERNAL_INDIRECT_ADDRESS /* Alter some macro definitions. */ +#include "tm-vax.h" + +#undef CPP_PREDEFINES +#undef TARGET_VERSION +#undef TARGET_DEFAULT +#undef CALL_USED_REGISTERS +#undef MAYBE_VMS_FUNCTION_PROLOGUE + +/* Predefine this in CPP because VMS limits the size of command options + and GNU CPP is not used on VMS except with GNU C. */ +#define CPP_PREDEFINES "-Dvax -Dvms -DVMS -D__GNU__ -D__GNUC__" + +/* By default, allow $ to be part of an identifier. */ +#define DOLLARS_IN_IDENTIFIERS 1 + +#define TARGET_DEFAULT 1 +#define TARGET_VERSION fprintf (stderr, " (vax vms)"); + +#define CALL_USED_REGISTERS {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +#define __MAIN_NAME " main (" +/* + * The MAYBE_VMS_FUNCTION_PROLOGUE macro works for both gcc and g++. It + * first checks to see if the current routine is "main", which will only + * happen for GCC, and add the jsb if it is. If is not the case then try and + * see if __MAIN_NAME is part of current_function_name, which will only happen + * if we are running g++, and add the jsb if it is. In gcc there should never + * be a space in the function name, and in g++ there is always a "(" in the + * function name, thus there should never be any confusion. + */ +#define MAYBE_VMS_FUNCTION_PROLOGUE(FILE) \ +{ extern char *current_function_name; \ + if (!strcmp ("main", current_function_name)) \ + fprintf(FILE, "\tjsb _c$main_args\n"); \ + else { \ + char *p = current_function_name; \ + while (*p != '\0') \ + if (*p == *__MAIN_NAME) \ + if (strncmp(p, __MAIN_NAME, (sizeof __MAIN_NAME)-1) == 0) {\ + fprintf(FILE, "\tjsb _c$main_args\n");\ + break; \ + } else \ + p++; \ + else \ + p++; \ + }; \ +} + +#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) \ +{ if (DECL_INITIAL (DECL) == 0 && TREE_CODE (DECL) != FUNCTION_DECL) \ + { \ + if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl)) \ + const_section (); \ + else \ + data_section (); \ + fputs (".comm ", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",0\n"); \ + } \ +} + +#define NO_DOLLAR_IN_LABEL + +#define EXTRA_SECTIONS in_const + +#define EXTRA_SECTION_FUNCTIONS \ +const_section () \ +{ \ + if (in_section != in_const) { \ + fprintf(asm_out_file,".const\n"); \ + in_section = in_const; \ + } \ +} + +#define SELECT_SECTION(T) \ +{ \ + if (TREE_CODE (T) == VAR_DECL) \ + { \ + if (TREE_READONLY (T) && ! TREE_VOLATILE (T)) \ + { \ + if (TREE_PUBLIC (T)) \ + const_section (); \ + else \ + text_section (); \ + } \ + else \ + data_section (); \ + } \ + if (*tree_code_type[(int) TREE_CODE (T)] == 'c') \ + { \ + if ((TREE_CODE (T) == STRING_CST && flag_writable_strings)) \ + data_section (); \ + else \ + text_section (); \ + } \ +} + diff --git a/gcc-1.40/config/vax.md b/gcc-1.40/config/vax.md new file mode 100644 index 0000000..ae8611c --- /dev/null +++ b/gcc-1.40/config/vax.md @@ -0,0 +1,2166 @@ + +;;- Machine description for GNU compiler +;;- Vax Version +;; Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +; tstsi is first test insn so that it is the one to match +; a constant argument. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "g"))] + "" + "tstl %0") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "g"))] + "" + "tstw %0") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "g"))] + "" + "tstb %0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "gF"))] + "" + "tst%# %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "gF"))] + "" + "tstf %0") + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "cmpw %0,%1") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "cmpb %0,%1") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "gF") + (match_operand:DF 1 "general_operand" "gF")))] + "" + "cmp%# %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "gF") + (match_operand:SF 1 "general_operand" "gF")))] + "" + "cmpf %0,%1") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=g") + (match_operand:DF 1 "general_operand" "gF"))] + "" + "* +{ + if (operands[1] == dconst0_rtx) + return \"clr%# %0\"; + return \"mov%# %1,%0\"; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g") + (match_operand:SF 1 "general_operand" "gF"))] + "" + "* +{ + if (operands[1] == fconst0_rtx) + return \"clrf %0\"; + return \"movf %1,%0\"; +}") + +;; Some vaxes don't support this instruction. +;;(define_insn "movti" +;; [(set (match_operand:TI 0 "general_operand" "=g") +;; (match_operand:TI 1 "general_operand" "g"))] +;; "" +;; "movh %1,%0") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g") + (match_operand:DI 1 "general_operand" "g"))] + "" + "movq %1,%0") + +;; This handles constants which are not legitimate +;; for the sake of shared libraries on VMS. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "" "i"))] + "CONSTANT_P (operands[1]) && ! LEGITIMATE_CONSTANT_P (operands[1])" + "* +{ + operands[2] = XEXP (XEXP (operands[1], 0), 0); + operands[1] = XEXP (XEXP (operands[1], 0), 1); + return \"movl %2,%0\;addl2 %1,%0\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "supergeneral_operand" "g"))] + "" + "* +{ + rtx link; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"incl %0\"; + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + /* this is slower than a movl, except when pushing an operand */ + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)(~i) < 64) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, ~i); + return \"mcoml %1,%0\"; + } + if ((unsigned)i < 127) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 63); + operands[2] = gen_rtx (CONST_INT, VOIDmode, i-63); + return \"addl3 %2,%1,%0\"; + } + /* trading speed for space */ + if ((unsigned)i < 0x100) + return \"movzbl %1,%0\"; + if (i >= -0x80 && i < 0) + return \"cvtbl %1,%0\"; + if ((unsigned)i < 0x10000) + return \"movzwl %1,%0\"; + if (i >= -0x8000 && i < 0) + return \"cvtwl %1,%0\"; + } + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + return \"movl %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + rtx link; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"incw %0\"; + if (operands[1] == const0_rtx) + return \"clrw %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)((~i) & 0xffff) < 64) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, (~i) & 0xffff); + return \"mcomw %1,%0\"; + } + if ((unsigned)(i & 0xffff) < 127) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 63); + operands[2] = gen_rtx (CONST_INT, VOIDmode, (i-63) & 0xffff); + return \"addw3 %2,%1,%0\"; + } + /* this is a lot slower, and only saves 1 measly byte! */ + /* if ((unsigned)i < 0x100) + return \"movzbw %1,%0\"; */ + /* if (i >= -0x80 && i < 0) + return \"cvtbw %1,%0\"; */ + } + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const0_rtx) + return \"clrb %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)((~i) & 0xff) < 64) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, (~i) & 0xff); + return \"mcomb %1,%0\"; + } +#if 0 + /* ASCII alphabetics */ + if (((unsigned) INTVAL (operands[1]) &0xff) < 127) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 63); + operands[2] = gen_rtx (CONST_INT, VOIDmode, i-63); + return \"addb3 %2,%1,%0\"; + } +#endif + } + return \"movb %1,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_insn "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + (clobber (reg:SI 4)) + (clobber (reg:SI 5))] + "" + "movc3 %2,%1,%0") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwl %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtbl %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float_extend:DF (match_operand:SF 1 "general_operand" "gF")))] + "" + "cvtf%# %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))] + "" + "cvt%#f %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "movzwl %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (zero_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbl %1,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float:SF (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float:DF (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtl%# %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float:SF (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float:DF (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtw%# %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float:SF (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtbf %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float:DF (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtb%# %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#b %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#w %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (plus:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"add%#2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"add%#2 %1,%0\"; + return \"add%#3 %1,%2,%0\"; +}") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (plus:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"addf2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"addf2 %1,%0\"; + return \"addf3 %1,%2,%0\"; +}") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == -1) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG) + return \"movab %c2(%1),%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG) + { + if (push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + return \"movab %c2(%1),%0\"; + } + return \"addl3 %1,%2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (minus:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"sub%#2 %2,%0\"; + return \"sub%#3 %2,%1,%0\"; +}") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (minus:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"subf2 %2,%0\"; + return \"subf3 %2,%1,%0\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decl %0\"; + return \"subl2 %2,%0\"; + } + return \"subl3 %2,%1,%0\"; +}") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decw %0\"; + return \"subw2 %2,%0\"; + } + return \"subw3 %2,%1,%0\"; +}") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decb %0\"; + return \"subb2 %2,%0\"; + } + return \"subb3 %2,%1,%0\"; +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (mult:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mul%#2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mul%#2 %1,%0\"; + return \"mul%#3 %1,%2,%0\"; +}") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (mult:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mulf2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mulf2 %1,%0\"; + return \"mulf3 %1,%2,%0\"; +}") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mult:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mull2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mull2 %1,%0\"; + return \"mull3 %1,%2,%0\"; +}") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mult:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mulw2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mulw2 %1,%0\"; + return \"mulw3 %1,%2,%0\"; +}") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mult:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mulb2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mulb2 %1,%0\"; + return \"mulb3 %1,%2,%0\"; +}") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (div:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"div%#2 %2,%0\"; + return \"div%#3 %2,%1,%0\"; +}") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (div:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divf2 %2,%0\"; + return \"divf3 %2,%1,%0\"; +}") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (div:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divl2 %2,%0\"; + return \"divl3 %2,%1,%0\"; +}") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (div:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divw2 %2,%0\"; + return \"divw3 %2,%1,%0\"; +}") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (div:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divb2 %2,%0\"; + return \"divb3 %2,%1,%0\"; +}") + +;This is left out because it is very slow; +;we are better off programming around the "lack" of this insn. +;(define_insn "divmoddisi4" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (div:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g"))) +; (set (match_operand:SI 3 "general_operand" "=g") +; (mod:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")))] +; "" +; "ediv %2,%1,%0,%3") + +;; Bit-and on the vax is done with a clear-bits insn. +(define_expand "andsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (not:SI (match_operand:SI 2 "general_operand" "g"))))] + "" + " +{ + extern rtx expand_unop (); + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); + else + operands[2] = expand_unop (SImode, one_cmpl_optab, operands[2], 0, 1); +}") + +(define_expand "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (not:HI (match_operand:HI 2 "general_operand" "g"))))] + "" + " +{ + extern rtx expand_unop (); + rtx op = operands[2]; + if (GET_CODE (op) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ((1 << 16) - 1) & ~INTVAL (op)); + else + operands[2] = expand_unop (HImode, one_cmpl_optab, op, 0, 1); +}") + +(define_expand "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (not:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + " +{ + extern rtx expand_unop (); + rtx op = operands[2]; + if (GET_CODE (op) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ((1 << 8) - 1) & ~INTVAL (op)); + else + operands[2] = expand_unop (QImode, one_cmpl_optab, op, 0, 1); +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (not:SI (match_operand:SI 2 "general_operand" "g"))))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bicl2 %2,%0\"; + return \"bicl3 %2,%1,%0\"; +}") + +(define_insn "andcbhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (not:HI (match_operand:HI 2 "general_operand" "g"))))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bicw2 %2,%0\"; + return \"bicw3 %2,%1,%0\"; +}") + +(define_insn "andcbqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (not:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bicb2 %2,%0\"; + return \"bicb3 %2,%1,%0\"; +}") + +;; The following are needed because constant propagation can +;; create them starting from the bic insn patterns above. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ operands[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); + if (rtx_equal_p (operands[1], operands[0])) + return \"bicl2 %2,%0\"; + return \"bicl3 %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ operands[2] = gen_rtx (CONST_INT, VOIDmode, 0xffff & ~INTVAL (operands[2])); + if (rtx_equal_p (operands[1], operands[0])) + return \"bicw2 %2,%0\"; + return \"bicw3 %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ operands[2] = gen_rtx (CONST_INT, VOIDmode, 0xff & ~INTVAL (operands[2])); + if (rtx_equal_p (operands[1], operands[0])) + return \"bicb2 %2,%0\"; + return \"bicb3 %2,%1,%0\"; +}") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bisl2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"bisl2 %1,%0\"; + return \"bisl3 %2,%1,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bisw2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"bisw2 %1,%0\"; + return \"bisw3 %2,%1,%0\"; +}") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bisb2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"bisb2 %1,%0\"; + return \"bisb3 %2,%1,%0\"; +}") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"xorl2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"xorl2 %1,%0\"; + return \"xorl3 %2,%1,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"xorw2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"xorw2 %1,%0\"; + return \"xorw3 %2,%1,%0\"; +}") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"xorb2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"xorb2 %1,%0\"; + return \"xorb3 %2,%1,%0\"; +}") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (neg:DF (match_operand:DF 1 "general_operand" "gF")))] + "" + "mneg%# %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (neg:SF (match_operand:SF 1 "general_operand" "gF")))] + "" + "mnegf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + +;; Arithmetic right shift on the vax works by negating the shift count. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (QImode, operands[2]); +}") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + return \"addl2 %0,%0\"; + if (GET_CODE (operands[1]) == REG + && GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i == 1) + return \"addl3 %1,%1,%0\"; + if (i == 2) + return \"moval 0[%1],%0\"; + if (i == 3) + return \"movad 0[%1],%0\"; + } + return \"ashl %2,%1,%0\"; +}") + +;; Arithmetic right shift on the vax works by negating the shift count. +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (QImode, operands[2]); +}") + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "ashq %2,%1,%0") + +;; Rotate right on the vax works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (QImode, operands[2]); +}") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "rotl %2,%1,%0") + +;This insn is probably slower than a multiply and an add. +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")) +; (match_operand:SI 3 "general_operand" "g")))] +; "" +; "index %1,$0x80000000,$0x7fffffff,%3,%2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+ro") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "g"))] + "GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[2]) != 0) + return \"insv %3,%2,%1,%0\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (INTVAL (operands[1]) == 8) + return \"movb %3,%0\"; + return \"movw %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&g") + (zero_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extzv %3,%2,%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"movzbl %1,%0\"; + return \"movzwl %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extv %3,%2,%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"cvtbl %1,%0\"; + return \"cvtwl %1,%0\"; +}") + +;; Register-only SImode cases of bit-field insns. + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:SI 0 "general_operand" "r") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "general_operand" "r") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extv %3,%2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "general_operand" "r") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extzv %3,%2,%1,%0") + +;; Non-register cases. +;; nonimmediate_operand is used to make sure that mode-ambiguous cases +;; don't match these (and therefore match the cases above instead). + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extv %3,%2,%1,%0") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extzv %3,%2,%1,%0") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jneq %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jeql %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jleq %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlequ %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgeq %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgequ %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlss %l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlssu %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtr %l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtru %l0") + +;; Recognize jlbs and jlbc insns. +;; These come before the jbc and jbs recognizers so these will be preferred. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +;; These four entries allow a jlbc or jlbs to be made +;; by combination with a bic. +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbs %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbc %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbc %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbs %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbs %1,%0,%l2") + +;; Subtract-and-jump and Add-and-jump insns. +;; These are not used when output is for the Unix assembler +;; because it does not know how to modify them to reach far. + +;; Normal sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (gt (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Reversed sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (le (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (lt (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Normal aob insns. +(define_insn "" + [(set (pc) + (if_then_else + (lt (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +;; Reverse aob insns. +(define_insn "" + [(set (pc) + (if_then_else + (ge (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (gt (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +;; Something like a sob insn, but compares against -1. +;; This finds `while (foo--)' which was changed to `while (--foo != -1)'. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:SI (match_operand:SI 0 "general_operand" "g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decl %0\;jgequ %l1") + +;; Note that operand 1 is total size of args, in bytes, +;; and what the call insn wants is the number of words. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* + if (INTVAL (operands[1]) > 255 * 4) + /* Vax `calls' really uses only one byte of #args, so pop explicitly. */ + return \"calls $0,%0\;addl2 %1,sp\"; + operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 3)/ 4); + return \"calls %1,%0\"; +") + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* + if (INTVAL (operands[2]) > 255 * 4) + /* Vax `calls' really uses only one byte of #args, so pop explicitly. */ + return \"calls $0,%1\;addl2 %2,sp\"; + operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 3)/ 4); + return \"calls %2,%1\"; +") + +(define_insn "return" + [(return)] + "" + "ret") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "casesi" + [(set (pc) + (if_then_else (le (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (match_dup 1))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2") + +;; This used to arise from the preceding by simplification +;; if operand 1 is zero. Perhaps it is no longer necessary. +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (const_int 0))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;; This arises from the preceding by simplification if operand 1 is zero. +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (match_dup 0)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;; This arises from casesi if operand 0 is a constant, in range. +(define_insn "" + [(set (pc) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (match_operand:SI 0 "general_operand" "g")))) + (label_ref:SI (match_operand 3 "" ""))))] + "" + "casel %0,$0,%0") + +;; This arises from the above if both operands are the same. +(define_insn "" + [(set (pc) + (plus:SI (sign_extend:SI (mem:HI (pc))) + (label_ref:SI (match_operand 3 "" ""))))] + "" + "casel $0,$0,$0") + +;;- load or push effective address +;; These come after the move and add/sub patterns +;; because we don't want pushl $1 turned into pushad 1. +;; or addl3 r1,r2,r3 turned into movab 0(r1)[r2],r3. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + return \"movaw %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + return \"moval %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaf %a1\"; + return \"movaf %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:DF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushad %a1\"; + return \"movad %a1,%0\"; +}") + +;; Optimize extzv ...,z; andl2 ...,z +;; with other operands constant. +(define_peephole + [(set (match_operand:SI 0 "general_operand" "g") + (zero_extract:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g"))) + (set (match_operand:SI 4 "general_operand" "g") + (and:SI (match_dup 0) + (match_operand:SI 5 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[2]) + INTVAL (operands[3])) == 32 + && GET_CODE (operands[5]) == CONST_INT + && dead_or_set_p (insn, operands[0])" + "* +{ + unsigned long mask = INTVAL (operands[5]); + operands[3] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[3])); + + if ((floor_log2 (mask) + 1) >= INTVAL (operands[2])) + mask &= ((1 << INTVAL (operands[2])) - 1); + + operands[5] = gen_rtx (CONST_INT, VOIDmode, ~mask); + if (push_operand (operands[4], SImode)) + { + output_asm_insn (\"rotl %3,%1,%0\", operands); + return \"bicl3 %5,%0,%4\"; + } + else + { + output_asm_insn (\"rotl %3,%1,%4\", operands); + return \"bicl2 %5,%4\"; + } +}") + +;; Optimize andl3 x,y,z; extzv z,....,z + +(define_peephole + [(set (match_operand:SI 0 "general_operand" "g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g"))) + (set (match_operand 3 "general_operand" "g") + (zero_extract:SI (match_dup 0) + (match_operand:SI 4 "general_operand" "g") + (match_operand:SI 5 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[4]) == CONST_INT + && GET_CODE (operands[5]) == CONST_INT + && (INTVAL (operands[4]) + INTVAL (operands[5])) == 32 + && dead_or_set_p (insn, operands[0])" + "* +{ + unsigned long mask = INTVAL (operands[2]); + + mask &= ~((1 << INTVAL (operands[5])) - 1); + operands[2] = gen_rtx (CONST_INT, VOIDmode, ~mask); + + operands[5] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[5])); + + if (rtx_equal_p (operands[0], operands[1])) + output_asm_insn (\"bicl2 %2,%0\", operands); + else + output_asm_insn (\"bicl3 %2,%1,%0\", operands); + return \"rotl %5,%0,%3\"; +}") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/xm-3b1.h b/gcc-1.40/config/xm-3b1.h new file mode 100644 index 0000000..2dc36fe --- /dev/null +++ b/gcc-1.40/config/xm-3b1.h @@ -0,0 +1,7 @@ +#define USG + +#include "xm-m68k.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-aix386.h b/gcc-1.40/config/xm-aix386.h new file mode 100644 index 0000000..500e29f --- /dev/null +++ b/gcc-1.40/config/xm-aix386.h @@ -0,0 +1,53 @@ +/* Configuration for GNU C-compiler for IBM PS/2 running AIX/386. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#ifdef FALSE +#undef FALSE +#endif +#ifdef TRUE +#undef TRUE +#endif +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define USG + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) + +#ifdef __GNUC__ +#define alloca(n) __builtin_alloca(n) +#endif diff --git a/gcc-1.40/config/xm-alliant.h b/gcc-1.40/config/xm-alliant.h new file mode 100644 index 0000000..2028c62 --- /dev/null +++ b/gcc-1.40/config/xm-alliant.h @@ -0,0 +1,48 @@ +/* Configuration for GNU C-compiler for Alliant FX computers. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +/* Make the linker remove temporary labels, since the Alliant assembler + doesn't. */ + +#define LINK_SPEC "-X" + diff --git a/gcc-1.40/config/xm-altos3068.h b/gcc-1.40/config/xm-altos3068.h new file mode 100644 index 0000000..2dc36fe --- /dev/null +++ b/gcc-1.40/config/xm-altos3068.h @@ -0,0 +1,7 @@ +#define USG + +#include "xm-m68k.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-convex.h b/gcc-1.40/config/xm-convex.h new file mode 100644 index 0000000..bddbef2 --- /dev/null +++ b/gcc-1.40/config/xm-convex.h @@ -0,0 +1,61 @@ +/* Configuration for GNU C-compiler for Convex. + Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +#ifdef _POSIX_SOURCE + +/* Un-hide names hidden in Posix include files. */ + +#define S_IFMT _S_IFMT +#define S_IFREG _S_IFREG + +#else + +/* This definition is to prevent 8.0 include files from declaring prototypes. + Those include files ANSIfied, but the prototypes sometimes do not match. + There is no effect on pre-8.0 OS versions. */ + +#ifndef _PROTO +#define _PROTO(X) () +#endif + +#endif /* _POSIX_SOURCE */ + diff --git a/gcc-1.40/config/xm-delta68k.h b/gcc-1.40/config/xm-delta68k.h new file mode 100644 index 0000000..0decc16 --- /dev/null +++ b/gcc-1.40/config/xm-delta68k.h @@ -0,0 +1,8 @@ +#define USG +#define USE_C_ALLOCA + +#include "xm-m68k.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-genix.h b/gcc-1.40/config/xm-genix.h new file mode 100644 index 0000000..11d31de --- /dev/null +++ b/gcc-1.40/config/xm-genix.h @@ -0,0 +1,9 @@ +/* Config file for ns32k running system V. */ + +#include "xm-ns32k.h" + +#define USG + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-hp9k320.h b/gcc-1.40/config/xm-hp9k320.h new file mode 100644 index 0000000..0974ac8 --- /dev/null +++ b/gcc-1.40/config/xm-hp9k320.h @@ -0,0 +1,13 @@ +#define USG + +#include "xm-m68k.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) + +/* If compiling with HPUX compiler, we are probably using alloca.c, + so help it work right. */ +#ifndef __GNUC__ +#define USE_C_ALLOCA +#endif diff --git a/gcc-1.40/config/xm-i386.h b/gcc-1.40/config/xm-i386.h new file mode 100644 index 0000000..e883f47 --- /dev/null +++ b/gcc-1.40/config/xm-i386.h @@ -0,0 +1,42 @@ +/* Configuration for GNU C-compiler for Intel 80386 running Sequent Symmetry + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-i386v.h b/gcc-1.40/config/xm-i386v.h new file mode 100644 index 0000000..60d4ce9 --- /dev/null +++ b/gcc-1.40/config/xm-i386v.h @@ -0,0 +1,47 @@ +/* Configuration for GNU C-compiler for Intel 80386 running System V. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define USG + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) + +#ifdef __GNUC__ +#define alloca(n) __builtin_alloca(n) +#endif diff --git a/gcc-1.40/config/xm-i860.h b/gcc-1.40/config/xm-i860.h new file mode 100644 index 0000000..61fa8be --- /dev/null +++ b/gcc-1.40/config/xm-i860.h @@ -0,0 +1,38 @@ +/* Configuration for GNU C-compiler for Intel i860. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" diff --git a/gcc-1.40/config/xm-iris.h b/gcc-1.40/config/xm-iris.h new file mode 100644 index 0000000..fddef9e --- /dev/null +++ b/gcc-1.40/config/xm-iris.h @@ -0,0 +1,7 @@ +#include "xm-mips.h" + +#define USG + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-m68k.h b/gcc-1.40/config/xm-m68k.h new file mode 100644 index 0000000..0165b58 --- /dev/null +++ b/gcc-1.40/config/xm-m68k.h @@ -0,0 +1,43 @@ +/* Configuration for GNU C-compiler for Motorola 68000 family. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 +#define HOST_WORDS_BIG_ENDIAN + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-m88k.h b/gcc-1.40/config/xm-m88k.h new file mode 100644 index 0000000..ea98030 --- /dev/null +++ b/gcc-1.40/config/xm-m88k.h @@ -0,0 +1,37 @@ +/* Configuration for GNU C-compiler for Motorola 88000 family. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 diff --git a/gcc-1.40/config/xm-mips.h b/gcc-1.40/config/xm-mips.h new file mode 100644 index 0000000..e73e992 --- /dev/null +++ b/gcc-1.40/config/xm-mips.h @@ -0,0 +1,44 @@ +/* Configuration for GNU C-compiler for MIPS Rx000 family + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#define USE_C_ALLOCA +#endif diff --git a/gcc-1.40/config/xm-ns32k.h b/gcc-1.40/config/xm-ns32k.h new file mode 100644 index 0000000..a19dcb6 --- /dev/null +++ b/gcc-1.40/config/xm-ns32k.h @@ -0,0 +1,41 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-pyr.h b/gcc-1.40/config/xm-pyr.h new file mode 100644 index 0000000..063829a --- /dev/null +++ b/gcc-1.40/config/xm-pyr.h @@ -0,0 +1,43 @@ +/* Configuration for GNU compiler for Pyramid 90 Series. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* xm-pyr.h -- based on xm-vax.h */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-sparc.h b/gcc-1.40/config/xm-sparc.h new file mode 100644 index 0000000..84a5984 --- /dev/null +++ b/gcc-1.40/config/xm-sparc.h @@ -0,0 +1,44 @@ +/* Configuration for GNU C-compiler for Sun Sparc. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Place any machine-dependent include files here, in case we + are bootstrapping. */ +#ifndef alloca +#include "alloca.h" +#endif + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 diff --git a/gcc-1.40/config/xm-spur.h b/gcc-1.40/config/xm-spur.h new file mode 100644 index 0000000..a9db436 --- /dev/null +++ b/gcc-1.40/config/xm-spur.h @@ -0,0 +1,37 @@ +/* Configuration for GNU C-compiler for Berkeley SPUR processor. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 diff --git a/gcc-1.40/config/xm-sun386i.h b/gcc-1.40/config/xm-sun386i.h new file mode 100644 index 0000000..48ca9a0 --- /dev/null +++ b/gcc-1.40/config/xm-sun386i.h @@ -0,0 +1,48 @@ +/* Configuration for GNU C-compiler for Intel 80386 running SunOS 4.0. + Copyright (C) 1988 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define USG + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) + +#ifdef __GNUC__ +#define alloca(n) __builtin_alloca(n) +#endif + diff --git a/gcc-1.40/config/xm-tahoe.h b/gcc-1.40/config/xm-tahoe.h new file mode 100644 index 0000000..e52ebe3 --- /dev/null +++ b/gcc-1.40/config/xm-tahoe.h @@ -0,0 +1,57 @@ +/* Configuration for GNU C-compiler for Tahoe. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * File: xm-tahoe.h + * + * This port made at the University of Buffalo by Devon Bowen, + * Dale Wiles and Kevin Zachmann. + * + * Mail bugs reports or fixes to: gcc@cs.buffalo.edu + */ + + +/* This file has the same stuff the vax version does */ + +/* defines that need visibility everywhere */ + +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies */ + +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ + +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ + +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* use built in alloca if gcc compiled */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-tower.h b/gcc-1.40/config/xm-tower.h new file mode 100644 index 0000000..1dc01ef --- /dev/null +++ b/gcc-1.40/config/xm-tower.h @@ -0,0 +1,8 @@ +#include "xm-m68k.h" + +#define USG +#define HAVE_VPRINTF + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-umips.h b/gcc-1.40/config/xm-umips.h new file mode 100644 index 0000000..bed8022 --- /dev/null +++ b/gcc-1.40/config/xm-umips.h @@ -0,0 +1,44 @@ +/* Configuration for GNU C-compiler for UMIPS operating system + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Notes for compiling gcc on umips (v3.0) + * - change the -g in the CFLAGS to a -g3 or take it out all together. + * - do not define DBX_DEBUGGING_INFO in tm.h, it doesn't exist (unless + * you get one from a bsd system) + */ +#include "xm-mips.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +#define USG + +/* for the emacs version of alloca */ +#define STACK_DIRECTION -1 + +#define bcopy(a,b,c) memcpy((b),(a),(c)) +#define bzero(a,b) memset((a),0,(b)) +#define bcmp(a,b,c) memcmp((a),(b),(c)) diff --git a/gcc-1.40/config/xm-vax.h b/gcc-1.40/config/xm-vax.h new file mode 100644 index 0000000..0057ae6 --- /dev/null +++ b/gcc-1.40/config/xm-vax.h @@ -0,0 +1,42 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + diff --git a/gcc-1.40/config/xm-vaxv.h b/gcc-1.40/config/xm-vaxv.h new file mode 100644 index 0000000..d347694 --- /dev/null +++ b/gcc-1.40/config/xm-vaxv.h @@ -0,0 +1,9 @@ +/* Config file for Vax running system V. */ + +#include "xm-vax.h" + +#define USG + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gcc-1.40/config/xm-vms.h b/gcc-1.40/config/xm-vms.h new file mode 100644 index 0000000..368c167 --- /dev/null +++ b/gcc-1.40/config/xm-vms.h @@ -0,0 +1,61 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +#define SUCCESS_EXIT_CODE 1 +#define FATAL_EXIT_CODE (44 | 0x10000000) /* Failure, and no DCL message. */ + + +/* A couple of conditionals for execution machine are controlled here. */ +#ifndef VMS +#define VMS +#endif + +#ifndef __GNUC__ +/* not present, at least in VAX-11 C (VMS) v2.2 */ +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 + +#define unlink delete +#endif + +/* global const variables don't work, + so turn off const-ness to prevent trouble with insn-output.c. */ +#define const + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + |
