;;- 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, 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, 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 "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")