NetBSD/gnu/dist/gcc/config/spur/spur.md

1093 lines
31 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;- 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_INT (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_INT (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_INT (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_INT (INTVAL (operands[1]) & 255);
operands[6] = GEN_INT ((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_INT (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_INT (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_INT (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_INT (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_INT (65535));
operands[5] = force_reg (SImode, GEN_INT (-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")