8sa1-gcc/gcc/config/arm/arm.md
Charles Hannum effeb5cc51 entered into RCS
From-SVN: r1497
1992-07-07 15:57:19 +00:00

1402 lines
40 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 Acorn RISC Machine for GNU compiler
;; Copyright (C) 1991 Free Software Foundation, Inc.
;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
;; and Martin Simmons (@harleqn.co.uk).
;; 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.
;; Every template must be output by arm_output_asm_insn, since this keeps
;; track of the offset of labels within the text segment. This is needed to
;; to be able to (correctly) output instructions for loading a value from a
;; function's constant pool, since different instructions are needed when the
;; constant pool is more than 4095 bytes away from the PC.
;; Addition insns.
(define_insn "adddi3"
[(set (match_operand:DI 0 "di_operand" "=r")
(plus:DI (match_operand:DI 1 "di_operand" "%r")
(match_operand:DI 2 "di_operand" "r")))]
""
"*
arm_output_asm_insn (\"adds\\t%0, %1, %2\", operands);
return (arm_output_asm_insn (\"adc\\t%R0, %R1, %R2\", operands));
")
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(plus:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "general_operand" "r,n")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"add\\t%0, %1, %2\", operands));
case 1:
return (output_add_immediate (operands));
}
")
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"adfs\\t%0, %1, %2\", operands));
")
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"adfd\\t%0, %1, %2\", operands));
")
(define_insn "subdi3"
[(set (match_operand:DI 0 "di_operand" "=r")
(minus:DI (match_operand:DI 1 "di_operand" "%r")
(match_operand:DI 2 "di_operand" "r")))]
""
"*
arm_output_asm_insn (\"subs\\t%0, %1, %2\", operands);
return (arm_output_asm_insn (\"sbc\\t%R0, %R1, %R2\", operands));
")
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,r,I")
(match_operand:SI 2 "general_operand" "r,n,r")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"sub\\t%0, %1, %2\", operands));
case 1:
operands[2] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[2]));
return (output_add_immediate (operands));
case 2:
return (arm_output_asm_insn (\"rsb\\t%0, %2, %1\", operands));
}
")
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f")
(minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
(match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"sufs\\t%0, %1, %2\", operands));
case 1:
return (arm_output_asm_insn (\"rsfs\\t%0, %2, %1\", operands));
}
")
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f,f")
(minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
(match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"sufd\\t%0, %1, %2\", operands));
case 2:
return (arm_output_asm_insn (\"rsfd\\t%0, %2, %1\", operands));
}
")
;; Multiplication insns
;; The `&' is too strict, but at least generates correct code.
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=&r")
(mult:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "register_operand" "r")))]
""
"*
if (REGNO (operands[0]) == REGNO (operands[1]))
return (arm_output_asm_insn (\"mul\\t%0, %2, %1\", operands));
else
return (arm_output_asm_insn (\"mul\\t%0, %1, %2\", operands));
")
;; Unnamed templates to match MLA instruction.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=&r")
(plus:SI
(mult:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "register_operand" "r"))
(match_operand:SI 3 "register_operand" "r")))]
""
"*
if (REGNO (operands[0]) == REGNO (operands[1]))
return (arm_output_asm_insn (\"mla\\t%0, %2, %1, %3\", operands));
else
return (arm_output_asm_insn (\"mla\\t%0, %1, %2, %3\", operands));
")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=&r")
(plus:SI
(match_operand:SI 3 "register_operand" "r")
(mult:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "register_operand" "r"))))]
""
"*
if (REGNO (operands[0]) == REGNO (operands[1]))
return (arm_output_asm_insn (\"mla\\t%0, %2, %1, %3\", operands));
else
return (arm_output_asm_insn (\"mla\\t%0, %1, %2, %3\", operands));
")
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "fpu_rhs_operand" "fG")))]
""
"*return (arm_output_asm_insn (\"mufs\\t%0, %1, %2\", operands));")
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"mufd\\t%0, %1, %2\", operands));
")
;; Division insns
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f")
(div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
(match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"dvfs\\t%0, %1, %2\", operands));
case 1:
return (arm_output_asm_insn (\"rdfs\\t%0, %2, %1\", operands));
}
")
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f,f")
(div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
(match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"dvfd\\t%0, %1, %2\", operands));
case 1:
return (arm_output_asm_insn (\"rdfd\\t%0, %2, %1\", operands));
}
")
;; Modulo insns
(define_insn "modsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mod:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"rmfs\\t%0, %1, %2\", operands));
")
(define_insn "moddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mod:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"rmfd\\t%0, %1, %2\", operands));
")
;; Boolean and,ior,xor insns
(define_insn "anddi3"
[(set (match_operand:DI 0 "di_operand" "=r")
(and:DI (match_operand:DI 1 "di_operand" "%r")
(match_operand:DI 2 "di_operand" "r")))]
""
"*
arm_output_asm_insn (\"and\\t%0, %1, %2\", operands);
return (arm_output_asm_insn (\"and\\t%R0, %R1, %R2\", operands));
")
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arm_rhs_operand" "rI")))]
""
"*
return (arm_output_asm_insn (\"and\\t%0, %1, %2\", operands));
")
(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 "arm_rhs_operand" "rI"))))]
""
"*
return (arm_output_asm_insn (\"bic\\t%0, %1, %2\", operands));
")
(define_insn "iordi3"
[(set (match_operand:DI 0 "di_operand" "=r")
(ior:DI (match_operand:DI 1 "di_operand" "%r")
(match_operand:DI 2 "di_operand" "r")))]
""
"*
arm_output_asm_insn (\"orr\\t%0, %1, %2\", operands);
return (arm_output_asm_insn (\"orr\\t%R0, %R1, %R2\", operands));
")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ior:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "nonmemory_operand" "r,n")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"orr\\t%0, %1, %2\", operands));
case 1:
return (output_multi_immediate (operands,
\"orr\\t%0, %1, %2\", \"orr\\t%0, %0, %2\",
2, INTVAL (operands[2])));
}
")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(xor:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "nonmemory_operand" "r,n")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"eor\\t%0, %1, %2\", operands));
case 1:
return (output_multi_immediate (operands,
\"eor\\t%0, %1, %2\", \"eor\\t%0, %0, %2\",
2, INTVAL (operands[2])));
}
")
;; Shift and rotation insns
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "general_operand" "rn")))]
""
"*
return (output_shifted_move (ASHIFT, operands));
")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "general_operand" "rn")))]
""
"*
return (output_shifted_move (ASHIFTRT, operands));
")
;; lshlsi3 is not defined because shift counts cannot be negative
;; An unnamed pattern is needed for expansion of zero_extend.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lshift:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "general_operand" "rn")))]
""
"*
return (output_shifted_move (LSHIFT, operands));
")
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "general_operand" "rn")))]
""
"*
return (output_shifted_move (LSHIFTRT, operands));
")
;; rotlsi3 is not defined yet to see what happens
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "general_operand" "r,n")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"mov\\t%0, %1,ror %2\", operands));
case 1:
if (INTVAL(operands[2]) > 31)
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 32);
return (arm_output_asm_insn (\"mov\\t%0, %1,ror%2\", operands));
}
")
;; Unary arithmetic insns
(define_insn "negdi2"
[(set (match_operand:DI 0 "di_operand" "=r")
(neg:DI (match_operand:DI 1 "di_operand" "r")))]
""
"*
arm_output_asm_insn (\"rsb\\t%0, %1, #0\", operands);
return (arm_output_asm_insn (\"rsc\\t%R0, %R1, #0\", operands));
")
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "register_operand" "r")))]
""
"*
return (arm_output_asm_insn (\"rsb\\t%0, %1, #0\", operands));
")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"mnfs\\t%0, %1\", operands));
")
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"mnfd\\t%0, %1\", operands));
")
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(abs:SF (match_operand:SF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"abss\\t%0, %1\", operands));
")
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"absd\\t%0, %1\", operands));
")
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"sqts\\t%0, %1\", operands));
")
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(sqrt:DF (match_operand:DF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"sqtd\\t%0, %1\", operands));
")
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "r")))]
""
"*
return (arm_output_asm_insn (\"mvn\\t%0, %1\", operands));
")
;; Fixed <--> Floating conversion insns
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float:SF (match_operand:SI 1 "register_operand" "r")))]
""
"*
return (arm_output_asm_insn (\"flts\\t%0, %1\", operands));
")
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:SI 1 "register_operand" "r")))]
""
"*
return (arm_output_asm_insn (\"fltd\\t%0, %1\", operands));
")
;; Truncation insns
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "general_operand" "=mr")
(truncate:QI (match_operand:SI 1 "register_operand" "r")))]
""
"*
if (GET_CODE (operands[0]) == MEM)
return (arm_output_asm_insn (\"strb\\t%1, %0\\t@ truncsiqi2\", operands));
else
return (arm_output_asm_insn (\"and\\t%0, %1, #255\\t@ truncsiqi2\", operands));
")
(define_insn "trunchiqi2"
[(set (match_operand:QI 0 "general_operand" "=mr")
(truncate:QI (match_operand:HI 1 "register_operand" "r")))]
""
"*
if (GET_CODE(operands[0]) == MEM)
return (arm_output_asm_insn (\"strb\\t%1, %0\\t@ trunchiqi2\", operands));
else
return (arm_output_asm_insn (\"and\\t%0, %1, #255\\t@ trunchiqi2\", operands));
")
;; Mode is changed to SI below
(define_expand "truncsihi2"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:HI 1 "register_operand" "")
(const_int 16)))
(set (match_dup 0)
(ashiftrt:SI (match_dup 0) (const_int 16)))]
""
"
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);
")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float_truncate:SF
(match_operand:DF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"mvfs\\t%0, %1\", operands));
")
;; Zero extension instructions.
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:HI 1 "register_operand" "")
(const_int 16)))
(set (match_dup 0)
(lshiftrt:SI (match_dup 0) (const_int 16)))]
""
"
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);
")
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI
(match_operand:QI 1 "register_operand" "r")))]
""
"*
return (arm_output_asm_insn (\"and\\t%0, %1, #255\\t@ zero_extendqihi2\", operands));
")
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI
(match_operand:QI 1 "nonimmediate_operand" "r,m")))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"and\\t%0, %1, #255\\t@ zero_extendqisi2\", operands));
case 1:
return (arm_output_asm_insn (\"ldrb\\t%0, %1\\t@ zero_extendqisi2\", operands));
}
")
;; Note that the ones starting from HImode come before those for QImode so
;; that a constant operand will match HImode, not QImode.
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:HI 1 "register_operand" "")
(const_int 16)))
(set (match_dup 0)
(ashiftrt:SI (match_dup 0) (const_int 16)))]
""
"
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);
")
;; XXX Is this ever used?
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:SI
(match_operand:QI 1 "register_operand" "r")))]
""
"*
arm_output_asm_insn (\"mov\\t%0, %1, lsl#24\\t@ extendqihi\", operands);
return (arm_output_asm_insn (\"mov\\t%0, %0, asr#24\", operands));
")
(define_expand "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:QI 1 "register_operand" "")
(const_int 24)))
(set (match_dup 0)
(ashiftrt:SI (match_dup 0) (const_int 24)))]
""
"
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);
")
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
""
"*
return (arm_output_asm_insn (\"mvfd\\t%0, %1\", operands));
")
;; Move insns (including loads and stores)
;; XXX Just some ideas about movti.
;;(define_expand "loadti"
;; [(set (match_operand:TI 0 "register_operand" "")
;; (mem:TI (match_operand:SI 1 "address_operand" "")))]
;; "" "")
;;(define_expand "storeti"
;; [(set (mem:TI (match_operand:TI 0 "address_operand" ""))
;; (match_operand:TI 1 "register_operand" ""))]
;; "" "")
;;(define_expand "movti"
;; [(set (match_operand:TI 0 "general_operand" "")
;; (match_operand:TI 1 "general_operand" ""))]
;; ""
;; "
;;{
;; rtx insn;
;;
;; if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
;; operands[1] = copy_to_reg (operands[1]);
;; if (GET_CODE (operands[0]) == MEM)
;; insn = gen_storeti (XEXP (operands[0], 0), operands[1]);
;; else if (GET_CODE (operands[1]) == MEM)
;; insn = gen_loadti (operands[0], XEXP (operands[1], 0));
;; else
;; FAIL;
;;
;; emit_insn (insn);
;; DONE;
;;}")
;; Recognise garbage generated above.
;;(define_insn ""
;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m")
;; (match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))]
;; ""
;; "*
;; {
;; register mem = (which_alternative < 3);
;; register char *template;
;;
;; operands[mem] = XEXP (operands[mem], 0);
;; switch (which_alternative)
;; {
;; case 0: template = \"ldmdb\\t%1!, %M0\"; break;
;; case 1: template = \"ldmia\\t%1!, %M0\"; break;
;; case 2: template = \"ldmia\\t%1, %M0\"; break;
;; case 3: template = \"stmdb\\t%0!, %M1\"; break;
;; case 4: template = \"stmia\\t%0!, %M1\"; break;
;; case 5: template = \"stmia\\t%0, %M1\"; break;
;; }
;; return (arm_output_asm_insn (template, operands));
;; }")
(define_insn "movdi"
[(set (match_operand:DI 0 "di_operand" "=r,r,r,o,r")
(match_operand:DI 1 "di_operand" "r,n,o,r,F"))]
""
"*
return (output_move_double (operands));
")
(define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=r,r,r,m")
(match_operand:SI 1 "general_operand" "r,n,m,r"))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"mov\\t%0, %1\", operands));
case 1:
return (output_mov_immediate (operands));
case 2:
if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0)))
return (arm_output_llc (operands));
else
return (arm_output_asm_insn (\"ldr\\t%0, %1\", operands));
case 3:
return (arm_output_asm_insn (\"str\\t%1, %0\", operands));
}
")
;; XXX The movhi stuff isn't as correct or as nice as it could be...
;; Subroutine to load a half word into a register from memory.
;; Operand 0 is the destination register (HImode).
;; Operand 1 is the source address (SImode).
;; Operand 2 is a temporary (SImode).
;;(define_expand "loadhi"
;; [;; load the whole word (ARM realigns it if not on word boundary)
;; (set (match_operand:SI 2 "register_operand" "")
;; (mem:SI (match_operand:SI 1 "address_operand" "")))
;; ;; quietly forget the upper 16 bits
;; (set (match_operand:HI 0 "register_operand" "")
;; (subreg:HI (match_dup 2) 0))]
;; ""
;; ""
;;)
;; Load op0 from mem:op1. Subroutine in case we're reloading and the normal
;; loadhi is not allowed.
;;(define_expand "reloadhi"
;; [(set (reg:SI 10)
;; (mem:SI (match_operand:SI 1 "address_operand" "")))
;; (set (match_operand:HI 0 "register_operand" "")
;; (subreg:HI (reg:SI 10) 0))]
;; "" "")
;; Store op0 into mem:op1. Subroutine in case we're reloading and the normal
;; storehi is not allowed.
(define_expand "restorehi"
[(set (mem:QI (match_operand:SI 1 "address_operand" ""))
(truncate:QI (match_operand:HI 0 "register_operand" "")))
(set (reg:HI 10)
(ashiftrt:HI (match_dup 0) (const_int 8)))
(set (mem:QI (plus:SI (match_dup 1) (const_int 1)))
(truncate:QI (reg:HI 10)))]
"" "")
;; Subroutine to store a half word from a register into memory.
;; Operand 0 is the source register (HImode)
;; Operand 1 is the destination address (SImode)
;; Operand 2 is a temporary (SImode).
;; Operand 3 is a temporary (SImode).
;; Operand 4 is a temporary (SImode).
;; Operand 5 is a local temporary (SImode).
(define_expand "storehi"
[;; compute the address into a register
(set (match_operand:SI 2 "register_operand" "")
(match_operand:SI 1 "address_operand" ""))
;; get the half word into a full word register
(set (match_operand:SI 3 "register_operand" "")
(match_dup 5))
;; store the low byte
(set (mem:QI (match_dup 2))
(truncate:QI (match_dup 3)))
;; extract the high byte
(set (match_operand:SI 4 "register_operand" "")
(ashiftrt:SI (match_dup 3) (const_int 8)))
;; store the high byte
(set (mem:QI (plus (match_dup 2) (const_int 1)))
(truncate:QI (match_dup 4)))]
""
"
if (GET_CODE(operands[0]) == SUBREG)
operands[5] = gen_rtx(SUBREG, SImode, SUBREG_REG(operands[0]),
SUBREG_WORD(operands[0]));
else
operands[5] = gen_rtx(SUBREG, SImode, operands[0], 0);
")
;; Subroutine to store a half word integer constant into memory.
;; Operand 0 is the constant
;; Operand 1 is the destination address (SImode)
;; Operand 2 is a temporary (SImode).
;; Operand 3 is a temporary (QImode).
;; Operand 4 is a temporary (QImode).
;; Operand 5 is a local CONST_INT.
;; Operand 6 is a local CONST_INT.
(define_expand "storeinthi"
[;; compute the address into a register
(set (match_operand:SI 2 "register_operand" "")
(match_operand:SI 1 "address_operand" ""))
;; load the low byte
(set (match_operand:QI 3 "register_operand" "")
(match_dup 5))
;; store the low byte
(set (mem:QI (match_dup 2))
(match_dup 3))
;; load the high byte
(set (match_operand:QI 4 "register_operand" "")
(match_dup 6))
;; store the high byte
(set (mem:QI (plus (match_dup 2) (const_int 1)))
(match_dup 4))]
""
"
{
int value = INTVAL(operands[0]);
operands[5] = gen_rtx(CONST_INT, VOIDmode, value & 255);
operands[6] = gen_rtx(CONST_INT, VOIDmode,(value>>8) & 255);
}
")
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
"
{
rtx insn;
if (reload_in_progress || reload_completed)
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == REG)
insn = gen_restorehi (operands[1], XEXP (operands[0], 0));
else
insn = gen_rtx (SET, VOIDmode, operands[0], operands[1]);
}
else
{
if (GET_CODE (operands[0]) == MEM)
{
if (GET_CODE (operands[1]) == MEM)
operands[1] = copy_to_reg (operands[1]);
if (GET_CODE (operands[1]) == CONST_INT)
{
insn = gen_storeinthi (operands[1], XEXP (operands[0], 0),
gen_reg_rtx (SImode),
gen_reg_rtx (QImode),
gen_reg_rtx (QImode));
}
else
{
insn = gen_storehi (operands[1], XEXP (operands[0], 0),
gen_reg_rtx (SImode),
gen_reg_rtx (SImode),
gen_reg_rtx (SImode));
}
}
#if 0
else if (GET_CODE (operands[1]) == MEM)
{
insn = gen_loadhi (operands[0], XEXP (operands[1], 0),
gen_reg_rtx (SImode));
}
#endif
else
insn = gen_rtx (SET, VOIDmode, operands[0], operands[1]);
}
emit_insn (insn);
DONE;
}")
;; Pattern to recognise insn generated default case above
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=r,r,r,m")
(match_operand:HI 1 "general_operand" "r,n,m,r"))]
""
"*
switch (which_alternative)
{
case 0: return (arm_output_asm_insn (\"mov\\t%0, %1\\t@movhi\", operands));
case 1: return (output_mov_immediate (operands));
case 2: return (arm_output_asm_insn (\"ldr\\t%0, %1\\t@movhi\", operands));
case 3: return (arm_output_asm_insn (\"str\\t%1, %0\\t@movhi\", operands));
}
")
(define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=r,r,r,m")
(match_operand:QI 1 "general_operand" "r,n,m,r"))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"mov\\t%0, %1\", operands));
case 1:
return (output_mov_immediate (operands));
case 2:
return (arm_output_asm_insn (\"ldrb\\t%0, %1\", operands));
case 3:
return (arm_output_asm_insn (\"strb\\t%1, %0\", operands));
}
")
(define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=f,f,m,f,r,r")
(match_operand:SF 1 "general_operand" "fG,m,f,r,f,r"))]
""
"*
switch (which_alternative)
{
case 0:
return (arm_output_asm_insn (\"mvfs\\t%0, %1\", operands));
case 1:
return (arm_output_asm_insn (\"ldfs\\t%0, %1\", operands));
case 2:
return (arm_output_asm_insn (\"stfs\\t%1, %0\", operands));
case 3:
arm_output_asm_insn(\"stmfd\\tsp!, {%1}\", operands);
return (arm_output_asm_insn (\"ldfs\\t%0, [sp],#4\", operands));
case 4:
arm_output_asm_insn(\"stfs\\t%1, [sp,#-4]!\", operands);
return (arm_output_asm_insn (\"ldmfd\\tsp!, {%0}\", operands));
case 5:
return (arm_output_asm_insn (\"mov\\t%0, %1\", operands));
}
")
(define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=f,f,m,f,r,r")
(match_operand:DF 1 "general_operand" "fG,m,f,r,f,r"))]
""
"*
switch (which_alternative)
{
case 0: return (arm_output_asm_insn (\"mvfd\\t%0, %1\", operands));
case 1: return (arm_output_asm_insn (\"ldfd\\t%0, %1\", operands));
case 2: return (arm_output_asm_insn (\"stfd\\t%1, %0\", operands));
case 3: return (output_mov_double_fpu_from_arm (operands));
case 4: return (output_mov_double_arm_from_fpu (operands));
case 5: return (output_move_double (operands));
}
")
;; Comparison and test insns
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "arm_rhs_operand" "rI")))]
""
"*
return (arm_output_asm_insn (\"cmp\\t%0, %1\", operands));
")
(define_insn "tstsi"
[(set (cc0) (match_operand:SI 0 "register_operand" "r"))]
""
"*
return (arm_output_asm_insn (\"cmp\\t%0, #0\", operands));
")
(define_insn ""
[(set (cc0)
(compare (match_operand:SI 0 "register_operand" "r")
(neg:SI (match_operand:SI 1 "arm_rhs_operand" "rI"))))]
""
"*
return (arm_output_asm_insn (\"cmn\\t%0, %1\", operands));
")
(define_insn "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"cmf\\t%0, %1\", operands));
")
(define_insn "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "fpu_rhs_operand" "fG")))]
""
"*
return (arm_output_asm_insn (\"cmf\\t%0, %1\", operands));
")
;; Conditional branch insns
(define_insn "beq"
[(set (pc)
(if_then_else (eq (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"beq\\t%l0\", operands));
")
(define_insn "bne"
[(set (pc)
(if_then_else (ne (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"bne\\t%l0\", operands));
")
(define_insn "bgt"
[(set (pc)
(if_then_else (gt (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"bgt\\t%l0\", operands));
")
(define_insn "ble"
[(set (pc)
(if_then_else (le (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"ble\\t%l0\", operands));
")
(define_insn "bge"
[(set (pc)
(if_then_else (ge (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"bge\\t%l0\", operands));
")
(define_insn "blt"
[(set (pc)
(if_then_else (lt (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"blt\\t%l0\", operands));
")
(define_insn "bgtu"
[(set (pc)
(if_then_else (gtu (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"bhi\\t%l0\", operands));
")
(define_insn "bleu"
[(set (pc)
(if_then_else (leu (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"bls\\t%l0\", operands));
")
(define_insn "bgeu"
[(set (pc)
(if_then_else (geu (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"bhs\\t%l0\", operands));
")
(define_insn "bltu"
[(set (pc)
(if_then_else (ltu (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return (arm_output_asm_insn (\"blo\\t%l0\", operands));
")
;; Inverted conditional branch insns
(define_insn ""
[(set (pc)
(if_then_else (eq (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"bne\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (ne (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"beq\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (gt (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"ble\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (le (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"bgt\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (ge (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"blt\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (lt (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"bge\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (gtu (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"bls\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (leu (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"bhi\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (geu (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"blo\\t%l0\", operands));
")
(define_insn ""
[(set (pc)
(if_then_else (ltu (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return (arm_output_asm_insn (\"bhs\\t%l0\", operands));
")
;; Jump and linkage insns
;; `return' is still a jump-to-epilogue...
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"*
return (arm_output_asm_insn (\"b\\t%l0\", operands));
")
(define_insn "call"
[(call (match_operand 0 "memory_operand" "m")
(match_operand 1 "general_operand" "g"))
(clobber (reg:SI 14))]
""
"*
return (output_call (operands));
")
(define_insn "call_value"
[(set (match_operand 0 "" "=rf")
(call (match_operand 1 "memory_operand" "m")
(match_operand 2 "general_operand" "g")))
(clobber (reg:SI 14))]
""
"*
return (output_call (&operands[1]));
")
;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
(define_insn ""
[(call (mem:SI (match_operand:SI 0 "" "i"))
(match_operand:SI 1 "general_operand" "g"))
(clobber (reg:SI 14))]
"GET_CODE (operands[0]) == SYMBOL_REF"
"*
return (arm_output_asm_insn (\"bl\\t%a0\", operands));
")
(define_insn ""
[(set (match_operand 0 "register_operand" "=rf")
(call (mem:SI (match_operand:SI 1 "" "i"))
(match_operand:SI 2 "general_operand" "g")))
(clobber (reg:SI 14))]
"GET_CODE(operands[1]) == SYMBOL_REF"
"*
return (arm_output_asm_insn (\"bl\\t%a1\", operands));
")
(define_insn "tablejump"
[(set (pc)
(match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"*
return (arm_output_asm_insn (\"mov\\tpc, %0\\t@ table jump, label %l1\", operands));
")
(define_insn "indirect_jump"
[(set (pc)
(match_operand:SI 0 "register_operand" "r"))]
""
"*
return (arm_output_asm_insn (\"mov\\tpc, %0\\t@ indirect jump\", operands));
")
;; Misc insns
(define_insn "nop"
[(const_int 0)]
""
"*
return (arm_output_asm_insn (\"mov\\tr0, r0\\t@ nop\", operands));
")
;; Patterns to allow combination of arithmetic, cond code and shifts
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
; (match_operator:SI 1 "shiftable_operator"
; [(match_operand:SI 2 "register_operand" "r")
; (match_operator:SI 3 "shift_operator"
; [(match_operand:SI 4 "register_operand" "r")
; (match_operand:SI 5 "nonmemory_operand" "rn")])]))]
; ""
; "*
; return (output_arithmetic_with_shift (operands, FALSE, FALSE));
; "
;)
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
; (match_operator:SI 1 "shiftable_operator"
; [(match_operator:SI 3 "shift_operator"
; [(match_operand:SI 4 "register_operand" "r")
; (match_operand:SI 5 "nonmemory_operand" "rI")])
; (match_operand:SI 2 "register_operand" "r")]))]
; ""
; "*
; return (output_arithmetic_with_shift (operands, TRUE, FALSE));
;")
;; Patterns to allow combination of arithmetic and multiplication
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
; (match_operator:SI 1 "shiftable_operator"
; [(match_operand:SI 2 "register_operand" "r")
; (mult:SI
; (match_operand:SI 3 "register_operand" "r")
; (match_operand:SI 4 "power_of_two_operand" "n"))]))]
; ""
; "*
; return (output_arithmetic_with_immediate_multiply (operands, FALSE));
;")
; Uncomment this to show combiner problem (see ../COMBINER-PROBLEM).
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
; (match_operator:SI 1 "shiftable_operator"
; [(mult:SI
; (match_operand:SI 3 "register_operand" "r")
; (match_operand:SI 4 "power_of_two_operand" "n"))
; (match_operand:SI 2 "register_operand" "r")]))]
; ""
; "*
; return (output_arithmetic_with_immediate_multiply (operands, TRUE));
;")
;; Peephole optimizations.
;; When testing a bitset smaller than 9 bits for (un)equality, a
;; shift/and/cmp/b{eq,ne} sequence can be replaced by one tst and the same
;; branch sequence.
;;(define_peephole
;; [(set (match_operand:SI 0 "register_operand" "=r")
;; (lshiftrt:SI (match_dup 0)
;; (match_operand 1 "immediate_operand" "")))
;; (set (match_dup 0)
;; (and:SI (match_dup 0)
;; (match_operand 2 "immediate_operand" "")))
;; (set (cc0) (match_dup 0))
;; (set (pc)
;; (if_then_else (ne (cc0) (const_int 0))
;; (label_ref (match_operand 3 "" ""))
;; (pc)))]
;; "dead_or_set_p (PREV_INSN (insn), operands[0])
;; && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT
;; && const_ok_for_arm (INTVAL (operands[2]) << INTVAL (operands[1]))"
;; "*
;; operands[2] = gen_rtx (CONST_INT, VOIDmode,
;; INTVAL (operands[2]) << INTVAL (operands[1]));
;; arm_output_asm_insn (\"tst\\t%0, %2\\t\\t@ ph test bitfield\", operands);
;; return (arm_output_asm_insn (\"bne\\t%l3\", operands));
;;")
;;(define_peephole
;; [(set (match_operand:SI 0 "register_operand" "=r")
;; (lshiftrt:SI (match_dup 0)
;; (match_operand 1 "immediate_operand" "")))
;; (set (match_dup 0)
;; (and:SI (match_dup 0)
;; (match_operand 2 "immediate_operand" "")))
;; (set (cc0) (match_dup 0))
;; (set (pc)
;; (if_then_else (ne (cc0) (const_int 0))
;; (pc)
;; (label_ref (match_operand 3 "" ""))))]
;; "dead_or_set_p (prev_real_insn (insn), operands[0])
;; && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT
;; && const_ok_for_arm (INTVAL (operands[2]) << INTVAL (operands[1]))"
;; "*
;; operands[2] = gen_rtx (CONST_INT, VOIDmode,
;; INTVAL (operands[2]) << INTVAL (operands[1]));
;; arm_output_asm_insn (\"tst\\t%0, %2\\t\\t@ ph test bitfield\", operands);
;; return (arm_output_asm_insn (\"beq\\t%l3\", operands));
;;")
;; This allows negative constants to be compared since GCC appears not to try
;; converting them with a NEG.
;;(define_peephole
;; [(set (match_operand:SI 2 "register_operand" "=r")
;; (match_operand:SI 1 "immediate_operand" "n"))
;; (set (cc0)
;; (compare (match_operand:SI 0 "register_operand" "r")
;; (match_dup 1)))]
;; "const_ok_for_arm (-INTVAL (operands[1]))
;; && dead_or_set_p (prev_real_insn (insn), operands[0])"
;; "*
;; operands[1] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[1]));
;; return (arm_output_asm_insn (\"cmn\\t%0, %1\\t\\t@ ph negate comparison\", operands));
;;")
;; Local variables:
;; mode:emacs-lisp
;; eval: (setq comment-start ";; ")
;; eval: (setq comment-end "")
;; eval: (setq 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: