From 66954a387154c75fa317f495ab0f8917d157568d Mon Sep 17 00:00:00 2001 From: Charles Hannum Date: Wed, 8 Jan 1992 11:11:21 +0000 Subject: [PATCH] entered into RCS From-SVN: r172 --- gcc/config/spur/spur.md | 1115 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1115 insertions(+) create mode 100644 gcc/config/spur/spur.md diff --git a/gcc/config/spur/spur.md b/gcc/config/spur/spur.md new file mode 100644 index 00000000000..7b869117585 --- /dev/null +++ b/gcc/config/spur/spur.md @@ -0,0 +1,1115 @@ +;;- 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 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- 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. + +;; This controls RTL generation and register allocation. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "register_operand" "rK") + (match_operand:SI 1 "nonmemory_operand" "rK")))] + "" + "* +{ + cc_status.value1 = operands[0], cc_status.value2 = operands[1]; + return \"\"; +}") + +;; 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] == CONST0_RTX (DFmode) && 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] == CONST0_RTX (DFmode) && 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: + -- 2.30.2