;; GCC machine description for Matsushita MN10300
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1996-2020 Free Software Foundation, Inc.
;; Contributed by Jeff Law (law@cygnus.com).
;; This file is part of GCC.
;; GCC 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)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GCC is distributed in the hope that it will be useful,
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GCC; see the file COPYING. If not, write to
-;; the Free Software Foundation, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
;; The original PO technology requires these to be ordered by speed,
;; so that assigner will pick the fastest.
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
-;; Condition code settings.
-;; none - insn does not affect cc
-;; none_0hit - insn does not affect cc but it does modify operand 0
-;; This attribute is used to keep track of when operand 0 changes.
-;; See the description of NOTICE_UPDATE_CC for more info.
-;; set_znv - insn sets z,n,v to usable values; c is unusable.
-;; set_zn - insn sets z,n to usable values; v,c are unusable.
-;; compare - compare instruction
-;; clobber - value of cc is unknown
-(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
- (const_string "clobber"))
-
(define_constants [
- (PIC_REG 6)
- (SP_REG 9)
+ (PIC_REG 6)
+ (SP_REG 9)
+ (MDR_REG 50)
+ (CC_REG 51)
- (UNSPEC_INT_LABEL 0)
(UNSPEC_PIC 1)
(UNSPEC_GOT 2)
(UNSPEC_GOTOFF 3)
(UNSPEC_PLT 4)
+ (UNSPEC_GOTSYM_OFF 5)
+
+ (UNSPEC_EXT 6)
+ (UNSPEC_BSCH 7)
+
+ ;; This is used to encode LIW patterns.
+ (UNSPEC_LIW 8)
+ ;; This is for the low overhead loop instructions.
+ (UNSPEC_SETLB 9)
])
(include "predicates.md")
+(include "constraints.md")
+
+;; Processor type. This attribute must exactly match the processor_type
+;; enumeration in mn10300.h.
+(define_attr "cpu" "mn10300,am33,am33_2,am34"
+ (const (symbol_ref "(enum attr_cpu) mn10300_tune_cpu")))
+
+;; Used to control the "enabled" attribute on a per-instruction basis.
+(define_attr "isa" "base,am33,am33_2,am34"
+ (const_string "base"))
+
+(define_attr "enabled" ""
+ (cond [(eq_attr "isa" "base")
+ (const_int 1)
+
+ (and (eq_attr "isa" "am33")
+ (match_test "TARGET_AM33"))
+ (const_int 1)
+
+ (and (eq_attr "isa" "am33_2")
+ (match_test "TARGET_AM33_2"))
+ (const_int 1)
+
+ (and (eq_attr "isa" "am34")
+ (match_test "TARGET_AM34"))
+ (const_int 1)
+ ]
+ (const_int 0))
+)
+
+(define_mode_iterator INT [QI HI SI])
+
+\f
+;; Bundling of smaller insns into a long instruction word (LIW)
+(define_automaton "liw_bundling")
+(automata_option "ndfa")
+
+(define_cpu_unit "liw_op1_u,liw_op2_u" "liw_bundling")
+
+(define_attr "liw" "op1,op2,both,either"
+ (const_string "both"))
+;; Note: this list must match the one defined for liw_op_names[].
+(define_attr "liw_op" "add,cmp,sub,mov,and,or,xor,asr,lsr,asl,none,max"
+ (const_string "none"))
+
+(define_insn_reservation "liw_op1" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "op1"))
+ "liw_op1_u");
+(define_insn_reservation "liw_op2" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "op2"))
+ "liw_op2_u");
+(define_insn_reservation "liw_both" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "both"))
+ "liw_op1_u + liw_op2_u");
+(define_insn_reservation "liw_either" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "either"))
+ "liw_op1_u | liw_op2_u");
+\f
+;; ----------------------------------------------------------------------
+;; Pipeline description.
+;; ----------------------------------------------------------------------
+
+;; The AM33 only has a single pipeline. It has five stages (fetch,
+;; decode, execute, memory access, writeback) each of which normally
+;; takes a single CPU clock cycle.
+
+;; The timings attribute consists of two numbers, the first is the
+;; throughput, which is the number of cycles the instruction takes
+;; to execute and generate a result. The second is the latency
+;; which is the effective number of cycles the instruction takes to
+;; execute if its result is used by the following instruction. The
+;; latency is always greater than or equal to the throughput.
+;; These values were taken from the Appendix of the "MN103E Series
+;; Instruction Manual" and the timings for the AM34.
+
+;; Note - it would be nice to use strings rather than integers for
+;; the possible values of this attribute, so that we can have the
+;; gcc build mechanism check for values that are not supported by
+;; the reservations below. But this will not work because the code
+;; in mn10300_adjust_sched_cost() needs integers not strings.
+
+(define_attr "timings" "" (const_int 11))
+
+(define_automaton "pipelining")
+(define_cpu_unit "throughput" "pipelining")
+
+(define_insn_reservation "throughput__1_latency__1" 1
+ (eq_attr "timings" "11") "throughput")
+(define_insn_reservation "throughput__1_latency__2" 2
+ (eq_attr "timings" "12") "throughput,nothing")
+(define_insn_reservation "throughput__1_latency__3" 3
+ (eq_attr "timings" "13") "throughput,nothing*2")
+(define_insn_reservation "throughput__1_latency__4" 4
+ (eq_attr "timings" "14") "throughput,nothing*3")
+(define_insn_reservation "throughput__2_latency__2" 2
+ (eq_attr "timings" "22") "throughput*2")
+(define_insn_reservation "throughput__2_latency__3" 3
+ (eq_attr "timings" "23") "throughput*2,nothing")
+(define_insn_reservation "throughput__2_latency__4" 4
+ (eq_attr "timings" "24") "throughput*2,nothing*2")
+(define_insn_reservation "throughput__2_latency__5" 5
+ (eq_attr "timings" "25") "throughput*2,nothing*3")
+(define_insn_reservation "throughput__3_latency__3" 3
+ (eq_attr "timings" "33") "throughput*3")
+(define_insn_reservation "throughput__3_latency__7" 7
+ (eq_attr "timings" "37") "throughput*3,nothing*4")
+(define_insn_reservation "throughput__4_latency__4" 4
+ (eq_attr "timings" "44") "throughput*4")
+(define_insn_reservation "throughput__4_latency__7" 7
+ (eq_attr "timings" "47") "throughput*4,nothing*3")
+(define_insn_reservation "throughput__4_latency__8" 8
+ (eq_attr "timings" "48") "throughput*4,nothing*4")
+(define_insn_reservation "throughput__5_latency__5" 5
+ (eq_attr "timings" "55") "throughput*5")
+(define_insn_reservation "throughput__6_latency__6" 6
+ (eq_attr "timings" "66") "throughput*6")
+(define_insn_reservation "throughput__7_latency__7" 7
+ (eq_attr "timings" "77") "throughput*7")
+(define_insn_reservation "throughput__7_latency__8" 8
+ (eq_attr "timings" "78") "throughput*7,nothing")
+(define_insn_reservation "throughput__8_latency__8" 8
+ (eq_attr "timings" "88") "throughput*8")
+(define_insn_reservation "throughput__9_latency__9" 9
+ (eq_attr "timings" "99") "throughput*9")
+(define_insn_reservation "throughput__8_latency_14" 14
+ (eq_attr "timings" "814") "throughput*8,nothing*6")
+(define_insn_reservation "throughput__9_latency_10" 10
+ (eq_attr "timings" "910") "throughput*9,nothing")
+(define_insn_reservation "throughput_10_latency_10" 10
+ (eq_attr "timings" "1010") "throughput*10")
+(define_insn_reservation "throughput_12_latency_16" 16
+ (eq_attr "timings" "1216") "throughput*12,nothing*4")
+(define_insn_reservation "throughput_13_latency_13" 13
+ (eq_attr "timings" "1313") "throughput*13")
+(define_insn_reservation "throughput_14_latency_14" 14
+ (eq_attr "timings" "1414") "throughput*14")
+(define_insn_reservation "throughput_13_latency_17" 17
+ (eq_attr "timings" "1317") "throughput*13,nothing*4")
+(define_insn_reservation "throughput_23_latency_27" 27
+ (eq_attr "timings" "2327") "throughput*23,nothing*4")
+(define_insn_reservation "throughput_25_latency_31" 31
+ (eq_attr "timings" "2531") "throughput*25,nothing*6")
+(define_insn_reservation "throughput_38_latency_39" 39
+ (eq_attr "timings" "3839") "throughput*38,nothing")
+(define_insn_reservation "throughput_39_latency_40" 40
+ (eq_attr "timings" "3940") "throughput*39,nothing")
+(define_insn_reservation "throughput_40_latency_40" 40
+ (eq_attr "timings" "4040") "throughput*40")
+(define_insn_reservation "throughput_41_latency_42" 42
+ (eq_attr "timings" "4142") "throughput*41,nothing")
+(define_insn_reservation "throughput_42_latency_43" 44
+ (eq_attr "timings" "4243") "throughput*42,nothing")
+(define_insn_reservation "throughput_43_latency_44" 44
+ (eq_attr "timings" "4344") "throughput*43,nothing")
+(define_insn_reservation "throughput_45_latency_46" 46
+ (eq_attr "timings" "4546") "throughput*45,nothing")
+(define_insn_reservation "throughput_47_latency_53" 53
+ (eq_attr "timings" "4753") "throughput*47,nothing*6")
+
+;; Note - the conflict between memory load/store instructions
+;; and floating point instructions described in section 1-7-4
+;; of Chapter 3 of the MN103E Series Instruction Manual is
+;; handled by the mn10300_adjust_sched_cost function.
\f
;; ----------------------------------------------------------------------
;; MOVE INSTRUCTIONS
;; movqi
(define_expand "movqi"
- [(set (match_operand:QI 0 "general_operand" "")
- (match_operand:QI 1 "general_operand" ""))]
+ [(set (match_operand:QI 0 "nonimmediate_operand")
+ (match_operand:QI 1 "general_operand"))]
""
- "
{
- /* One of the ops has to be in a register */
+ /* One of the ops has to be in a register. */
if (!register_operand (operand0, QImode)
&& !register_operand (operand1, QImode))
- operands[1] = copy_to_mode_reg (QImode, operand1);
-}")
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a")
- (match_operand:QI 1 "general_operand" "0,I,d*xai,m,d*xa,d*xa*f,*f"))]
- "TARGET_AM33
- && (register_operand (operands[0], QImode)
- || register_operand (operands[1], QImode))"
- "*
+ operands[1] = force_reg (QImode, operand1);
+})
+
+(define_insn "*movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m,*z,d")
+ (match_operand:QI 1 "general_operand" " 0,D*r, i,m,D,d,*z"))]
+ "(register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode))"
{
switch (which_alternative)
{
case 0:
- return \"nop\";
+ return "";
case 1:
- return \"clr %0\";
case 2:
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- rtx xoperands[2];
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- output_asm_insn (\"mov %1,%0\", xoperands);
- return \"\";
- }
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
- && GET_CODE (operands[1]) == CONST_INT)
- {
- HOST_WIDE_INT val = INTVAL (operands[1]);
-
- if (((val & 0x80) && ! (val & 0xffffff00))
- || ((val & 0x800000) && ! (val & 0xff000000)))
- return \"movu %1,%0\";
- }
- return \"mov %1,%0\";
- case 3:
- case 4:
- return \"movbu %1,%0\";
case 5:
case 6:
- return \"fmov %1,%0\";
- default:
- abort ();
- }
-}"
- [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d*a,d,m")
- (match_operand:QI 1 "general_operand" "0,I,dai,m,d"))]
- "register_operand (operands[0], QImode)
- || register_operand (operands[1], QImode)"
- "*
-{
- switch (which_alternative)
- {
- case 0:
- return \"nop\";
- case 1:
- return \"clr %0\";
- case 2:
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- rtx xoperands[2];
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- output_asm_insn (\"mov %1,%0\", xoperands);
- return \"\";
- }
-
- return \"mov %1,%0\";
+ return "mov %1,%0";
case 3:
case 4:
- return \"movbu %1,%0\";
+ return "movbu %1,%0";
default:
- abort ();
+ gcc_unreachable ();
}
-}"
- [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")])
+}
+ [(set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 11)
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (const_int 11)
+ (const_int 11)
+ ])]
+)
;; movhi
(define_expand "movhi"
- [(set (match_operand:HI 0 "general_operand" "")
- (match_operand:HI 1 "general_operand" ""))]
+ [(set (match_operand:HI 0 "nonimmediate_operand")
+ (match_operand:HI 1 "general_operand"))]
""
- "
{
- /* One of the ops has to be in a register */
+ /* One of the ops has to be in a register. */
if (!register_operand (operand1, HImode)
&& !register_operand (operand0, HImode))
- operands[1] = copy_to_mode_reg (HImode, operand1);
-}")
-
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a")
- (match_operand:HI 1 "general_operand" "0,I,d*x*ai,m,d*x*a,d*x*a*f,*f"))]
- "TARGET_AM33
- && (register_operand (operands[0], HImode)
- || register_operand (operands[1], HImode))"
- "*
+ operands[1] = force_reg (HImode, operand1);
+})
+
+(define_insn "*movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m,*z,d")
+ (match_operand:HI 1 "general_operand" " 0, i,D*r,m,D,d,*z"))]
+ "(register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode))"
{
switch (which_alternative)
{
case 0:
- return \"nop\";
+ return "";
case 1:
- return \"clr %0\";
- case 2:
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- rtx xoperands[2];
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- output_asm_insn (\"mov %1,%0\", xoperands);
- return \"\";
- }
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
- && GET_CODE (operands[1]) == CONST_INT)
- {
- HOST_WIDE_INT val = INTVAL (operands[1]);
-
- if (((val & 0x80) && ! (val & 0xffffff00))
- || ((val & 0x800000) && ! (val & 0xff000000)))
- return \"movu %1,%0\";
- }
- return \"mov %1,%0\";
- case 3:
- case 4:
- return \"movhu %1,%0\";
+ /* Note that "MOV imm8,An" is already zero-extending, and is 2 bytes.
+ We have "MOV imm16,Dn" at 3 bytes. The only win for the 4 byte
+ movu is for an 8-bit unsigned move into Rn. */
+ if (TARGET_AM33
+ && CONST_INT_P (operands[1])
+ && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff)
+ && REGNO_EXTENDED_P (REGNO (operands[0]), 1))
+ return "movu %1,%0";
+ /* FALLTHRU */
case 5:
case 6:
- return \"fmov %1,%0\";
- default:
- abort ();
- }
-}"
- [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
-
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d*a,d,m")
- (match_operand:HI 1 "general_operand" "0,I,dai,m,d"))]
- "register_operand (operands[0], HImode)
- || register_operand (operands[1], HImode)"
- "*
-{
- switch (which_alternative)
- {
- case 0:
- return \"nop\";
- case 1:
- return \"clr %0\";
case 2:
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- rtx xoperands[2];
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- output_asm_insn (\"mov %1,%0\", xoperands);
- return \"\";
- }
- return \"mov %1,%0\";
+ return "mov %1,%0";
case 3:
case 4:
- return \"movhu %1,%0\";
+ return "movhu %1,%0";
default:
- abort ();
+ gcc_unreachable ();
}
-}"
- [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")])
+}
+ [(set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ ])]
+)
;; movsi and helpers
;; We use this to handle addition of two values when one operand is the
;; stack pointer and the other is a memory reference of some kind. Reload
;; does not handle them correctly without this expander.
-(define_expand "reload_insi"
- [(set (match_operand:SI 0 "register_operand" "=a")
- (match_operand:SI 1 "impossible_plus_operand" ""))
- (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+(define_expand "reload_plus_sp_const"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand:SI 1 "impossible_plus_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&A"))]
""
- "
{
- if (XEXP (operands[1], 0) == stack_pointer_rtx)
+ rtx dest, scratch, other;
+
+ dest = operands[0];
+ scratch = operands[2];
+
+ other = XEXP (operands[1], 1);
+ if (other == stack_pointer_rtx)
+ other = XEXP (operands[1], 0);
+
+ if (true_regnum (other) == true_regnum (dest))
{
- if (GET_CODE (XEXP (operands[1], 1)) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1)))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1))))))
- emit_move_insn (operands[2],
- gen_rtx_ZERO_EXTEND
- (GET_MODE (XEXP (operands[1], 1)),
- SUBREG_REG (XEXP (operands[1], 1))));
- else
- emit_move_insn (operands[2], XEXP (operands[1], 1));
- emit_move_insn (operands[0], XEXP (operands[1], 0));
+ gcc_assert (true_regnum (scratch) != true_regnum (dest));
+ emit_move_insn (scratch, stack_pointer_rtx);
+ emit_insn (gen_addsi3 (dest, dest, scratch));
+ }
+ else if (TARGET_AM33 || REGNO_REG_CLASS (true_regnum (dest)) == ADDRESS_REGS)
+ {
+ emit_move_insn (dest, stack_pointer_rtx);
+ if (other == stack_pointer_rtx)
+ emit_insn (gen_addsi3 (dest, dest, dest));
+ else if (other != const0_rtx)
+ emit_insn (gen_addsi3 (dest, dest, other));
}
else
{
- if (GET_CODE (XEXP (operands[1], 0)) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0)))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0))))))
- emit_move_insn (operands[2],
- gen_rtx_ZERO_EXTEND
- (GET_MODE (XEXP (operands[1], 0)),
- SUBREG_REG (XEXP (operands[1], 0))));
+ emit_move_insn (scratch, stack_pointer_rtx);
+ if (other == stack_pointer_rtx)
+ {
+ emit_move_insn (dest, scratch);
+ emit_insn (gen_addsi3 (dest, dest, dest));
+ }
+ else if (other != const0_rtx)
+ {
+ emit_move_insn (dest, other);
+ emit_insn (gen_addsi3 (dest, dest, scratch));
+ }
else
- emit_move_insn (operands[2], XEXP (operands[1], 0));
- emit_move_insn (operands[0], XEXP (operands[1], 1));
+ emit_move_insn (dest, scratch);
}
- emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
DONE;
-}")
-
-(define_insn "pop_pic_reg"
- [(set (reg:SI PIC_REG)
- (mem:SI (post_inc:SI (reg:SI SP_REG))))]
- "reload_completed"
- "movm (sp),[a2]")
+})
(define_expand "movsi"
- [(set (match_operand:SI 0 "general_operand" "")
- (match_operand:SI 1 "general_operand" ""))]
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "general_operand"))]
""
- "
{
- /* One of the ops has to be in a register */
+ /* One of the ops has to be in a register. */
if (!register_operand (operand1, SImode)
&& !register_operand (operand0, SImode))
- operands[1] = copy_to_mode_reg (SImode, operand1);
+ operands[1] = force_reg (SImode, operand1);
if (flag_pic)
{
rtx temp;
if (SYMBOLIC_CONST_P (operands[1]))
{
- if (GET_CODE (operands[0]) == MEM)
+ if (MEM_P (operands[0]))
operands[1] = force_reg (Pmode, operands[1]);
else
{
- temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
- operands[1] = legitimize_pic_address (operands[1], temp);
+ temp = (!can_create_pseudo_p ()
+ ? operands[0]
+ : gen_reg_rtx (Pmode));
+ operands[1] = mn10300_legitimize_pic_address (operands[1], temp);
}
}
else if (GET_CODE (operands[1]) == CONST
&& GET_CODE (XEXP (operands[1], 0)) == PLUS
&& SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
{
- temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
- temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
- temp);
+ temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
+ temp = mn10300_legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
+ temp);
operands[1] = expand_binop (SImode, add_optab, temp,
XEXP (XEXP (operands[1], 0), 1),
- no_new_pseudos ? temp
- : gen_reg_rtx (Pmode),
+ (!can_create_pseudo_p ()
+ ? temp
+ : gen_reg_rtx (Pmode)),
0, OPTAB_LIB_WIDEN);
}
}
-}")
+})
-(define_insn ""
+(define_insn "*movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand"
- "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,!*y,*f,*f,dxaQ")
+ "=r,r,r,r,m,r, A,*y,*y,*z,*d")
(match_operand:SI 1 "general_operand"
- "0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,!*y,axR,0,dxaQi*f,*f"))]
+ " 0,O,i,r,r,m,*y, A, i,*d,*z"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
- "*
{
switch (which_alternative)
{
case 0:
- case 1:
- return \"nop\";
- case 2:
- return \"clr %0\";
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- rtx xoperands[2];
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- output_asm_insn (\"mov %1,%0\", xoperands);
- return \"\";
- }
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
- && GET_CODE (operands[1]) == CONST_INT)
+ return "";
+ case 1: /* imm-reg. */
+ case 2:
+ /* See movhi for a discussion of sizes for 8-bit movu. Note that the
+ 24-bit movu is 6 bytes, which is the same size as the full 32-bit
+ mov form for An and Dn. So again movu is only a win for Rn. */
+ if (TARGET_AM33
+ && CONST_INT_P (operands[1])
+ && REGNO_EXTENDED_P (REGNO (operands[0]), 1))
{
HOST_WIDE_INT val = INTVAL (operands[1]);
-
- if (((val & 0x80) && ! (val & 0xffffff00))
- || ((val & 0x800000) && ! (val & 0xff000000)))
- return \"movu %1,%0\";
+ if (IN_RANGE (val, 0x80, 0xff)
+ || IN_RANGE (val, 0x800000, 0xffffff))
+ return "movu %1,%0";
}
- return \"mov %1,%0\";
- case 14:
- return \"nop\";
- case 15:
- case 16:
- return \"fmov %1,%0\";
+ /* FALLTHRU */
+ case 3: /* reg-reg */
+ case 4: /* reg-mem */
+ case 5: /* mem-reg */
+ case 6: /* sp-reg */
+ case 7: /* reg-sp */
+ case 8: /* imm-sp */
+ case 9: /* reg-mdr */
+ case 10: /* mdr-reg */
+ return "mov %1,%0";
default:
- abort ();
+ gcc_unreachable ();
}
-}"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none,none_0hit,none_0hit")])
+}
+ [(set_attr "isa" "*,*,*,*,*,*,*,*,am33,*,*")
+ (set_attr "liw" "*,either,*,either,*,*,*,*,*,*,*")
+ (set_attr "liw_op" "mov")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 22)
+ (const_int 22)
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)
+ (const_int 11)
+ (const_int 11)
+ ])]
+)
(define_expand "movsf"
- [(set (match_operand:SF 0 "general_operand" "")
- (match_operand:SF 1 "general_operand" ""))]
- ""
- "
+ [(set (match_operand:SF 0 "nonimmediate_operand")
+ (match_operand:SF 1 "general_operand"))]
+ "TARGET_AM33_2"
{
- /* One of the ops has to be in a register */
+ /* One of the ops has to be in a register. */
if (!register_operand (operand1, SFmode)
&& !register_operand (operand0, SFmode))
- operands[1] = copy_to_mode_reg (SFmode, operand1);
-}")
-
-(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,dx,ax,dx,a,f,dxaQ,daxm,dax")
- (match_operand:SF 1 "general_operand" "0,0,0,G,G,fdxaQF,f,dax,daxFm"))]
- "register_operand (operands[0], SFmode)
- || register_operand (operands[1], SFmode)"
- "*
+ operands[1] = force_reg (SFmode, operand1);
+})
+
+(define_insn "*movsf_internal"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q,z,d")
+ (match_operand:SF 1 "general_operand" " 0,F,F,r,f,f,r,m,r,Q,f,d,z"))]
+ "TARGET_AM33_2
+ && (register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode))"
{
switch (which_alternative)
{
case 0:
+ return "";
case 1:
- case 2:
- return \"nop\";
case 3:
- return \"clr %0\";
- /* case 4: below */
- case 5:
- case 6:
- return \"fmov %1, %0\";
- case 4:
case 7:
case 8:
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
- && GET_CODE (operands[1]) == CONST_INT)
- {
- HOST_WIDE_INT val = INTVAL (operands[1]);
-
- if (((val & 0x80) && ! (val & 0xffffff00))
- || ((val & 0x800000) && ! (val & 0xff000000)))
- return \"movu %1,%0\";
- }
- return \"mov %1,%0\";
+ case 11:
+ case 12:
+ return "mov %1,%0";
+ case 2:
+ case 4:
+ case 5:
+ case 6:
+ case 9:
+ case 10:
+ return "fmov %1,%0";
default:
- abort ();
+ gcc_unreachable ();
}
-}"
- [(set_attr "cc" "none,none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+}
+ [(set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 22)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 47) (const_int 25))
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 22)
+ (const_int 22)
+ ])]
+)
+
+;; If the flags register is not live, generate CLR instead of MOV 0.
+;; For MN103, this is only legal for DATA_REGS; for AM33 this is legal
+;; but not a win for ADDRESS_REGS.
+(define_peephole2
+ [(set (match_operand:INT 0 "register_operand" "") (const_int 0))]
+ "peep2_regno_dead_p (0, CC_REG)
+ && (REGNO_DATA_P (REGNO (operands[0]), 1)
+ || REGNO_EXTENDED_P (REGNO (operands[0]), 1))"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_insn "*mov<mode>_clr"
+ [(set (match_operand:INT 0 "register_operand" "=D")
+ (const_int 0))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "clr %0"
+)
+\f
+;; ----------------------------------------------------------------------
+;; ADD INSTRUCTIONS
+;; ----------------------------------------------------------------------
-(define_expand "movdi"
- [(set (match_operand:DI 0 "general_operand" "")
- (match_operand:DI 1 "general_operand" ""))]
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,!*y,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,O,i, i, r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ { return mn10300_output_add (operands, false); }
+ [(set_attr "timings" "11,11,11,11,22")
+ (set_attr "liw" "either,either,*,*,*")
+ (set_attr "liw_op" "add")]
+)
+
+;; Note that ADD IMM,SP does not set the flags, so omit that here.
+(define_insn "*addsi3_flags"
+ [(set (reg CC_REG)
+ (compare (plus:SI (match_operand:SI 1 "register_operand" "%0, r")
+ (match_operand:SI 2 "nonmemory_operand" "ri, r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r,!r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+ { return mn10300_output_add (operands, true); }
+ [(set_attr "timings" "11,22")]
+)
+
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+ [(parallel [(set (reg:CCZNC CC_REG)
+ (compare:CCZNC (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand")
+ (plus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")))])]
+ ""
+)
+
+(define_insn "addc_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r,r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (reg:CC CC_REG) (const_int 0))
+ (match_operand:SI 1 "register_operand" "%0,0,r"))
+ (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r")))
+ (clobber (reg:CC CC_REG))]
+ "reload_completed"
+ "@
+ addc %2,%0
+ addc %2,%0
+ addc %2,%1,%0"
+ [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "nonmemory_operand" "")))]
""
- "
{
- /* One of the ops has to be in a register */
- if (!register_operand (operand1, DImode)
- && !register_operand (operand0, DImode))
- operands[1] = copy_to_mode_reg (DImode, operand1);
-}")
-
-(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand"
- "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,*f,*f,*f,dxa,*f,Q")
- (match_operand:DI 1 "general_operand"
- "0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim,0,*f,dxai,*f,Q,*f"))]
- "register_operand (operands[0], DImode)
- || register_operand (operands[1], DImode)"
- "*
+ rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+ op0l = gen_lowpart (SImode, operands[0]);
+ op1l = gen_lowpart (SImode, operands[1]);
+ op2l = gen_lowpart (SImode, operands[2]);
+ op0h = gen_highpart (SImode, operands[0]);
+ op1h = gen_highpart (SImode, operands[1]);
+ op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+ if (!reg_or_am33_const_operand (op2h, SImode))
+ op2h = force_reg (SImode, op2h);
+
+ emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+ DONE;
+})
+
+;; Note that reload only supports one commutative operand. Thus we cannot
+;; auto-swap both the high and low outputs with their matching constraints.
+;; For MN103, we're strapped for registers but thankfully the alternatives
+;; are few. For AM33, it becomes much easier to not represent the early
+;; clobber and 6 permutations of immediate and three-operand adds, but
+;; instead allocate a scratch register and do the expansion by hand.
+
+(define_insn_and_split "adddi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r, r, r")
+ (plus:SI (match_operand:SI 2 "register_operand" "%0, 0, r")
+ (match_operand:SI 3 "nonmemory_operand" "ri,ri,ri")))
+ (set (match_operand:SI 1 "register_operand" "=D, D, r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+ (match_operand:SI 4 "register_operand" " 1, D, r"))
+ (match_operand:SI 5 "reg_or_am33_const_operand" " D, 1,ri")))
+ (clobber (match_scratch:SI 6 "=X, X,&r"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
{
- long val[2];
- REAL_VALUE_TYPE rv;
+ rtx op0l = operands[0];
+ rtx op0h = operands[1];
+ rtx op1l = operands[2];
+ rtx op2l = operands[3];
+ rtx op1h = operands[4];
+ rtx op2h = operands[5];
+ rtx scratch = operands[6];
+ rtx x;
+
+ if (reg_overlap_mentioned_p (op0l, op1h))
+ {
+ emit_move_insn (scratch, op0l);
+ op1h = scratch;
+ if (reg_overlap_mentioned_p (op0l, op2h))
+ op2h = scratch;
+ }
+ else if (reg_overlap_mentioned_p (op0l, op2h))
+ {
+ emit_move_insn (scratch, op0l);
+ op2h = scratch;
+ }
- switch (which_alternative)
+ if (rtx_equal_p (op0l, op1l))
+ ;
+ else if (rtx_equal_p (op0l, op2l))
+ x = op1l, op1l = op2l, op2l = x;
+ else
{
- case 0:
- case 1:
- return \"nop\";
-
- case 2:
- return \"clr %L0\;clr %H0\";
-
- case 3:
- if (rtx_equal_p (operands[0], operands[1]))
- return \"sub %L1,%L0\;mov %L0,%H0\";
- else
- return \"mov %1,%L0\;mov %L0,%H0\";
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- if (GET_CODE (operands[1]) == CONST_INT)
- {
- rtx low, high;
- split_double (operands[1], &low, &high);
- val[0] = INTVAL (low);
- val[1] = INTVAL (high);
- }
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- if (GET_MODE (operands[1]) == DFmode)
- {
- REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
- }
- else if (GET_MODE (operands[1]) == VOIDmode
- || GET_MODE (operands[1]) == DImode)
- {
- val[0] = CONST_DOUBLE_LOW (operands[1]);
- val[1] = CONST_DOUBLE_HIGH (operands[1]);
- }
- }
-
- if (GET_CODE (operands[1]) == MEM
- && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
- {
- rtx temp = operands[0];
-
- while (GET_CODE (temp) == SUBREG)
- temp = SUBREG_REG (temp);
-
- if (GET_CODE (temp) != REG)
- abort ();
-
- if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
- XEXP (operands[1], 0)))
- return \"mov %H1,%H0\;mov %L1,%L0\";
- else
- return \"mov %L1,%L0\;mov %H1,%H0\";
-
- }
- else if (GET_CODE (operands[1]) == MEM
- && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
- && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
- {
- rtx xoperands[2];
-
- xoperands[0] = operands[0];
- xoperands[1] = XEXP (operands[1], 0);
-
- output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
- xoperands);
- return \"\";
- }
- else
- {
- if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[0] == 0)
- {
- if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %L0\", operands);
- else
- output_asm_insn (\"mov %L1,%L0\", operands);
- }
- else if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && (REGNO_REG_CLASS (true_regnum (operands[0]))
- == EXTENDED_REGS)
- && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
- || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
- output_asm_insn (\"movu %L1,%L0\", operands);
- else
- output_asm_insn (\"mov %L1,%L0\", operands);
-
- if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[1] == 0)
- {
- if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %H0\", operands);
- else
- output_asm_insn (\"mov %H1,%H0\", operands);
- }
- else if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[0] == val[1])
- output_asm_insn (\"mov %L0,%H0\", operands);
- else if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && (REGNO_REG_CLASS (true_regnum (operands[0]))
- == EXTENDED_REGS)
- && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
- || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
- output_asm_insn (\"movu %H1,%H0\", operands);
- else
- output_asm_insn (\"mov %H1,%H0\", operands);
- return \"\";
- }
- case 12:
- return \"nop\";
- case 13:
- case 14:
- case 15:
- return \"fmov %L1, %L0\;fmov %H1, %H0\";
- case 16:
- if (GET_CODE (operands[1]) == MEM
- && GET_CODE (XEXP (operands[1], 0)) == CONST_INT
- && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
- return \"fmov %D1, %D0\";
- else
- return \"fmov %L1, %L0\;fmov %H1, %H0\";
- case 17:
- if (GET_CODE (operands[0]) == MEM
- && GET_CODE (XEXP (operands[0], 0)) == CONST_INT
- && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
- return \"fmov %D1, %D0\";
- else
- return \"fmov %L1, %L0\;fmov %H1, %H0\";
- default:
- abort ();
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2l))
+ {
+ emit_move_insn (op0l, op2l);
+ op2l = op1l;
+ op1l = op0l;
+ }
}
-}"
- [(set (attr "cc")
- (cond
- [
- (ior (lt (symbol_ref "which_alternative") (const_int 2))
- (eq (symbol_ref "which_alternative") (const_int 12))
- ) (const_string "none")
- (eq (symbol_ref "which_alternative") (const_int 2)
- ) (const_string "clobber")
- (eq (symbol_ref "which_alternative") (const_int 3)
- ) (if_then_else
- (ne (symbol_ref "rtx_equal_p (operands[0], operands[1])")
- (const_int 0)) (const_string "clobber")
- (const_string "none_0hit"))
- (ior (eq (symbol_ref "which_alternative") (const_int 8))
- (eq (symbol_ref "which_alternative") (const_int 9))
- ) (if_then_else
- (ne (symbol_ref "mn10300_wide_const_load_uses_clr
- (operands)")
- (const_int 0)) (const_string "clobber")
- (const_string "none_0hit"))
- ] (const_string "none_0hit")))])
-
-(define_expand "movdf"
- [(set (match_operand:DF 0 "general_operand" "")
- (match_operand:DF 1 "general_operand" ""))]
- ""
- "
-{
- /* One of the ops has to be in a register */
- if (!register_operand (operand1, DFmode)
- && !register_operand (operand0, DFmode))
- operands[1] = copy_to_mode_reg (DFmode, operand1);
-}")
-
-(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand"
- "=f,dx,ax,dx,f,f,dxa,f,Q,a,dxm,dxm,axm,axm,dx,dx,ax,ax")
- (match_operand:DF 1 "general_operand"
- "0,0,0,G,f,dxaF,f,Q,f,G,dx,ax,dx,ax,dxFm,axFm,dxFm,axFm"))]
- "register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)"
- "*
-{
- long val[2];
- REAL_VALUE_TYPE rv;
+ emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
- switch (which_alternative)
+ if (rtx_equal_p (op0h, op1h))
+ ;
+ else if (rtx_equal_p (op0h, op2h))
+ x = op1h, op1h = op2h, op2h = x;
+ else
{
- case 0:
- case 1:
- case 2:
- return \"nop\";
-
- case 3:
- return \"clr %L0\;clr %H0\";
-
- case 4:
- case 5:
- case 6:
- return \"fmov %L1, %L0\;fmov %H1, %H0\";
-
- case 7:
- if (GET_CODE (operands[1]) == MEM
- && GET_CODE (XEXP (operands[1], 0)) == CONST_INT
- && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
- return \"fmov %D1, %D0\";
- else
- return \"fmov %L1, %L0\;fmov %H1, %H0\";
-
- case 8:
- if (GET_CODE (operands[0]) == MEM
- && GET_CODE (XEXP (operands[0], 0)) == CONST_INT
- && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
- return \"fmov %D1, %D0\";
- else
- return \"fmov %L1, %L0\;fmov %H1, %H0\";
-
- case 9:
- if (rtx_equal_p (operands[0], operands[1]))
- return \"sub %L1,%L0\;mov %L0,%H0\";
- else
- return \"mov %1,%L0\;mov %L0,%H0\";
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- if (GET_CODE (operands[1]) == CONST_INT)
- {
- rtx low, high;
- split_double (operands[1], &low, &high);
- val[0] = INTVAL (low);
- val[1] = INTVAL (high);
- }
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- if (GET_MODE (operands[1]) == DFmode)
- {
- REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
- }
- else if (GET_MODE (operands[1]) == VOIDmode
- || GET_MODE (operands[1]) == DImode)
- {
- val[0] = CONST_DOUBLE_LOW (operands[1]);
- val[1] = CONST_DOUBLE_HIGH (operands[1]);
- }
- }
-
- if (GET_CODE (operands[1]) == MEM
- && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
- {
- rtx temp = operands[0];
-
- while (GET_CODE (temp) == SUBREG)
- temp = SUBREG_REG (temp);
-
- if (GET_CODE (temp) != REG)
- abort ();
-
- if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
- XEXP (operands[1], 0)))
- return \"mov %H1,%H0\;mov %L1,%L0\";
- else
- return \"mov %L1,%L0\;mov %H1,%H0\";
-
- }
- else if (GET_CODE (operands[1]) == MEM
- && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
- && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
- {
- rtx xoperands[2];
-
- xoperands[0] = operands[0];
- xoperands[1] = XEXP (operands[1], 0);
-
- output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
- xoperands);
- return \"\";
- }
- else
- {
- if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[0] == 0)
- {
- if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %L0\", operands);
- else
- output_asm_insn (\"mov %L1,%L0\", operands);
- }
- else if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && (REGNO_REG_CLASS (true_regnum (operands[0]))
- == EXTENDED_REGS)
- && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
- || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
- output_asm_insn (\"movu %L1,%L0\", operands);
- else
- output_asm_insn (\"mov %L1,%L0\", operands);
-
- if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[1] == 0)
- {
- if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %H0\", operands);
- else
- output_asm_insn (\"mov %H1,%H0\", operands);
- }
- else if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[0] == val[1])
- output_asm_insn (\"mov %L0,%H0\", operands);
- else if ((GET_CODE (operands[1]) == CONST_INT
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- && (REGNO_REG_CLASS (true_regnum (operands[0]))
- == EXTENDED_REGS)
- && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
- || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
- output_asm_insn (\"movu %H1,%H0\", operands);
- else
- output_asm_insn (\"mov %H1,%H0\", operands);
- return \"\";
- }
- default:
- abort ();
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2h))
+ {
+ emit_move_insn (op0h, op2h);
+ op2h = op1h;
+ op1h = op0h;
+ }
}
-}"
- [(set (attr "cc")
- (cond
- [
- (lt (symbol_ref "which_alternative") (const_int 3)
- ) (const_string "none")
- (eq (symbol_ref "which_alternative") (const_int 3)
- ) (const_string "clobber")
- (eq (symbol_ref "which_alternative") (const_int 9)
- ) (if_then_else
- (ne (symbol_ref "rtx_equal_p (operands[0], operands[1])")
- (const_int 0)) (const_string "clobber")
- (const_string "none_0hit"))
- (ior (eq (symbol_ref "which_alternative") (const_int 14))
- (eq (symbol_ref "which_alternative") (const_int 15))
- ) (if_then_else
- (ne (symbol_ref "mn10300_wide_const_load_uses_clr
- (operands)")
- (const_int 0)) (const_string "clobber")
- (const_string "none_0hit"))
- ] (const_string "none_0hit")))])
+ emit_insn (gen_addc_internal (op0h, op1h, op2h));
+ DONE;
+}
+ [(set_attr "isa" "*,*,am33")]
+)
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word add is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*adddi3_degenerate"
+ [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+ (match_operand:SI 2 "nonmemory_operand" " 0, 0"))
+ (set (match_operand:SI 1 "register_operand" "=r , r")
+ (plus:SI (match_operand:SI 3 "register_operand" "%1 , r")
+ (match_operand:SI 4 "nonmemory_operand" "ri, r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ ""
+ [(const_int 0)]
+{
+ rtx scratch = NULL_RTX;
+ if (!rtx_equal_p (operands[0], operands[2]))
+ {
+ if (reg_overlap_mentioned_p (operands[0], operands[3])
+ || reg_overlap_mentioned_p (operands[0], operands[4]))
+ {
+ scratch = gen_reg_rtx (SImode);
+ emit_move_insn (scratch, operands[2]);
+ }
+ else
+ emit_move_insn (operands[0], operands[2]);
+ }
+ emit_insn (gen_addsi3 (operands[1], operands[3], operands[4]));
+ if (scratch)
+ emit_move_insn (operands[0], scratch);
+ DONE;
+})
-\f
;; ----------------------------------------------------------------------
-;; TEST INSTRUCTIONS
+;; SUBTRACT INSTRUCTIONS
;; ----------------------------------------------------------------------
-;; Go ahead and define tstsi so we can eliminate redundant tst insns
-;; when we start trying to optimize this port.
-(define_insn "tstsi"
- [(set (cc0) (match_operand:SI 0 "register_operand" "dax"))]
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,O,i,r")))
+ (clobber (reg:CC CC_REG))]
""
- "* return output_tst (operands[0], insn);"
- [(set_attr "cc" "set_znv")])
-
-(define_insn ""
- [(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "dx,!a")))]
- "TARGET_AM33"
- "* return output_tst (operands[0], insn);"
- [(set_attr "cc" "set_znv")])
+ "@
+ sub %2,%0
+ sub %2,%0
+ sub %2,%0
+ sub %2,%1,%0"
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "either,either,*,*")
+ (set_attr "liw_op" "sub")
+ (set_attr "timings" "11,11,11,22")]
+)
+
+(define_insn "*subsi3_flags"
+ [(set (reg CC_REG)
+ (compare (minus:SI (match_operand:SI 1 "register_operand" "0, r")
+ (match_operand:SI 2 "nonmemory_operand" "ri,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r, r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+ "@
+ sub %2,%0
+ sub %2,%1,%0"
+ [(set_attr "isa" "*,am33")
+ (set_attr "timings" "11,22")]
+)
+
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+ [(parallel [(set (reg:CCZNC CC_REG)
+ (compare:CCZNC (minus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand")
+ (minus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")))])]
+ ""
+)
+
+(define_insn "subc_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r,r")
+ (minus:SI
+ (minus:SI (match_operand:SI 1 "register_operand" " 0,0,r")
+ (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r"))
+ (geu:SI (reg:CC CC_REG) (const_int 0))))
+ (clobber (reg:CC CC_REG))]
+ "reload_completed"
+ "@
+ subc %2,%0
+ subc %2,%0
+ subc %2,%1,%0"
+ [(set_attr "isa" "*,am33,am33")]
+)
-(define_insn ""
- [(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "dx")))]
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "nonmemory_operand" "")))]
""
- "* return output_tst (operands[0], insn);"
- [(set_attr "cc" "set_znv")])
+{
+ rtx op0l, op0h, op1l, op1h, op2l, op2h;
-(define_insn ""
- [(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "dx,!a")))]
- "TARGET_AM33"
- "* return output_tst (operands[0], insn);"
- [(set_attr "cc" "set_znv")])
+ op0l = gen_lowpart (SImode, operands[0]);
+ op1l = gen_lowpart (SImode, operands[1]);
+ op2l = gen_lowpart (SImode, operands[2]);
+ op0h = gen_highpart (SImode, operands[0]);
+ op1h = gen_highpart (SImode, operands[1]);
+ op2h = gen_highpart_mode (SImode, DImode, operands[2]);
-(define_insn ""
- [(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "dx")))]
- ""
- "* return output_tst (operands[0], insn);"
- [(set_attr "cc" "set_znv")])
-
-;; Ordinarily, the cmp instruction will set the Z bit of cc0 to 1 if
-;; its operands hold equal values, but the operands of a cmp
-;; instruction must be distinct registers. In the case where we'd
-;; like to compare a register to itself, we can achieve this effect
-;; with a btst 0,d0 instead. (This will not alter the contents of d0
-;; but will have the proper effect on cc0. Using d0 is arbitrary; any
-;; data register would work.)
-
-;; Even though the first alternative would be preferable if it can
-;; possibly match, reload must not be given the opportunity to attempt
-;; to use it. It assumes that such matches can only occur when one of
-;; the operands is used for input and the other for output. Since
-;; this is not the case, it abort()s. Indeed, such a reload cannot be
-;; possibly satisfied, so just mark the alternative with a `!', so
-;; that it is not considered by reload.
+ if (!reg_or_am33_const_operand (op2h, SImode))
+ op2h = force_reg (SImode, op2h);
-(define_insn "cmpsi"
- [(set (cc0)
- (compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax")
- (match_operand:SI 1 "nonmemory_operand" "*0,daxi")))]
+ emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op1h, op2l, op2h));
+ DONE;
+})
+
+;; As with adddi3, the use of the scratch register helps reduce the
+;; number of permutations for AM33.
+;; ??? The early clobber on op0 avoids a reload bug wherein both output
+;; registers are set the same. Consider negate, where both op2 and op3
+;; are 0, are csed to the same input register, and reload fails to undo
+;; the cse when satisfying the matching constraints.
+
+(define_insn_and_split "subdi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=&r, r")
+ (minus:SI
+ (match_operand:SI 2 "register_operand" " 0, r")
+ (match_operand:SI 4 "nonmemory_operand" " ri,ri")))
+ (set (match_operand:SI 1 "register_operand" "=D , r")
+ (minus:SI
+ (minus:SI
+ (match_operand:SI 3 "register_operand" " 1, r")
+ (match_operand:SI 5 "reg_or_am33_const_operand" " D,ri"))
+ (ltu:SI (match_dup 2) (match_dup 4))))
+ (clobber (match_scratch:SI 6 "=X ,&r"))
+ (clobber (reg:CC CC_REG))]
""
- "@
- btst 0,d0
- cmp %1,%0"
- [(set_attr "cc" "compare,compare")])
-
-(define_insn "cmpsf"
- [(set (cc0)
- (compare (match_operand:SF 0 "register_operand" "f,f")
- (match_operand:SF 1 "nonmemory_operand" "f,F")))]
- "TARGET_AM33_2"
- "fcmp %1,%0"
- [(set_attr "cc" "compare,compare")])
-\f
-;; ----------------------------------------------------------------------
-;; ADD INSTRUCTIONS
-;; ----------------------------------------------------------------------
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ rtx op0l = operands[0];
+ rtx op0h = operands[1];
+ rtx op1l = operands[2];
+ rtx op1h = operands[3];
+ rtx op2l = operands[4];
+ rtx op2h = operands[5];
+ rtx scratch = operands[6];
+
+ if (reg_overlap_mentioned_p (op0l, op1h))
+ {
+ emit_move_insn (scratch, op0l);
+ op1h = scratch;
+ if (reg_overlap_mentioned_p (op0l, op2h))
+ op2h = scratch;
+ }
+ else if (reg_overlap_mentioned_p (op0l, op2h))
+ {
+ emit_move_insn (scratch, op0l);
+ op2h = scratch;
+ }
-(define_expand "addsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (plus:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
- ""
- "")
+ if (!rtx_equal_p (op0l, op1l))
+ {
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2l))
+ {
+ emit_move_insn (op0l, op1l);
+ op1l = op0l;
+ }
+ }
+ emit_insn (gen_subsi3_flags (op0l, op1l, op2l));
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,a,x,a,dax,!*y,!dax")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,dax")
- (match_operand:SI 2 "nonmemory_operand" "J,J,L,L,daxi,i,dax")))]
- "TARGET_AM33"
- "*
-{
- switch (which_alternative)
+ if (!rtx_equal_p (op0h, op1h))
{
- case 0:
- case 1:
- return \"inc %0\";
- case 2:
- case 3:
- return \"inc4 %0\";
- case 4:
- case 5:
- return \"add %2,%0\";
- case 6:
- {
- enum reg_class src1_class, src2_class, dst_class;
-
- src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
- src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
- dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
- /* I'm not sure if this can happen or not. Might as well be prepared
- and generate the best possible code if it does happen. */
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- return \"add %2,%0\";
- if (true_regnum (operands[0]) == true_regnum (operands[2]))
- return \"add %1,%0\";
-
- /* Catch cases where no extended register was used. These should be
- handled just like the mn10300. */
- if (src1_class != EXTENDED_REGS
- && src2_class != EXTENDED_REGS
- && dst_class != EXTENDED_REGS)
- {
- /* We have to copy one of the sources into the destination, then
- add the other source to the destination.
-
- Carefully select which source to copy to the destination; a naive
- implementation will waste a byte when the source classes are
- different and the destination is an address register. Selecting
- the lowest cost register copy will optimize this sequence. */
- if (REGNO_REG_CLASS (true_regnum (operands[1]))
- == REGNO_REG_CLASS (true_regnum (operands[0])))
- return \"mov %1,%0\;add %2,%0\";
- return \"mov %2,%0\;add %1,%0\";
- }
-
- /* At least one register is an extended register. */
-
- /* The three operand add instruction on the am33 is a win iff the
- output register is an extended register, or if both source
- registers are extended registers. */
- if (dst_class == EXTENDED_REGS
- || src1_class == src2_class)
- return \"add %2,%1,%0\";
-
- /* It is better to copy one of the sources to the destination, then
- perform a 2 address add. The destination in this case must be
- an address or data register and one of the sources must be an
- extended register and the remaining source must not be an extended
- register.
-
- The best code for this case is to copy the extended reg to the
- destination, then emit a two address add. */
- if (src1_class == EXTENDED_REGS)
- return \"mov %1,%0\;add %2,%0\";
- return \"mov %2,%0\;add %1,%0\";
- }
- default:
- abort ();
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2h))
+ {
+ emit_move_insn (op0h, op1h);
+ op1h = op0h;
+ }
}
-}"
- [(set_attr "cc" "set_zn,none_0hit,set_zn,none_0hit,set_zn,none_0hit,set_zn")])
+ emit_insn (gen_subc_internal (op0h, op1h, op2h));
+ DONE;
+}
+ [(set_attr "isa" "*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word sub is zero, and thus
+;; no carry is generated into the high-part.
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,a,a,dax,!*y,!dax")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,dax")
- (match_operand:SI 2 "nonmemory_operand" "J,J,L,daxi,i,dax")))]
+(define_insn_and_split "*subdi3_degenerate"
+ [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+ (match_operand:SI 2 "nonmemory_operand" " 0, 0"))
+ (set (match_operand:SI 1 "register_operand" "=r , r")
+ (minus:SI (match_operand:SI 3 "register_operand" " 1, r")
+ (match_operand:SI 4 "nonmemory_operand" " ri, r")))
+ (clobber (reg:CC CC_REG))]
""
- "*
+ "#"
+ ""
+ [(const_int 0)]
{
- switch (which_alternative)
+ rtx scratch = NULL_RTX;
+ if (!rtx_equal_p (operands[0], operands[2]))
{
- case 0:
- case 1:
- return \"inc %0\";
- case 2:
- return \"inc4 %0\";
- case 3:
- case 4:
- return \"add %2,%0\";
- case 5:
- /* I'm not sure if this can happen or not. Might as well be prepared
- and generate the best possible code if it does happen. */
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- return \"add %2,%0\";
- if (true_regnum (operands[0]) == true_regnum (operands[2]))
- return \"add %1,%0\";
-
- /* We have to copy one of the sources into the destination, then add
- the other source to the destination.
-
- Carefully select which source to copy to the destination; a naive
- implementation will waste a byte when the source classes are different
- and the destination is an address register. Selecting the lowest
- cost register copy will optimize this sequence. */
- if (REGNO_REG_CLASS (true_regnum (operands[1]))
- == REGNO_REG_CLASS (true_regnum (operands[0])))
- return \"mov %1,%0\;add %2,%0\";
- return \"mov %2,%0\;add %1,%0\";
- default:
- abort ();
+ gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+ if (reg_overlap_mentioned_p (operands[0], operands[3])
+ || reg_overlap_mentioned_p (operands[0], operands[4]))
+ {
+ scratch = gen_reg_rtx (SImode);
+ emit_move_insn (scratch, operands[2]);
+ }
+ else
+ emit_move_insn (operands[0], operands[2]);
}
-}"
- [(set_attr "cc" "set_zn,none_0hit,none_0hit,set_zn,none_0hit,set_zn")])
-
-;; ----------------------------------------------------------------------
-;; SUBTRACT INSTRUCTIONS
-;; ----------------------------------------------------------------------
+ emit_insn (gen_subsi3 (operands[1], operands[3], operands[4]));
+ if (scratch)
+ emit_move_insn (operands[0], scratch);
+ DONE;
+})
-(define_expand "subsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (minus:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
+(define_insn_and_split "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,&r")
+ (neg:SI (match_operand:SI 1 "register_operand" " 0, r")))
+ (clobber (reg:CC CC_REG))]
""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dax,!dax")
- (minus:SI (match_operand:SI 1 "register_operand" "0,dax")
- (match_operand:SI 2 "nonmemory_operand" "daxi,dax")))]
- "TARGET_AM33"
- "*
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
{
+ /* Recall that twos-compliment is ones-compliment plus one. When
+ allocated in DATA_REGS this is 2+1 bytes; otherwise (for am33)
+ this is 3+3 bytes.
+
+ For AM33, it would have been possible to load zero and use the
+ three-address subtract to have a total size of 3+4*N bytes for
+ multiple negations, plus increased throughput. Not attempted here. */
+
if (true_regnum (operands[0]) == true_regnum (operands[1]))
- return \"sub %2,%0\";
+ {
+ emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+ emit_insn (gen_addsi3 (operands[0], operands[0], const1_rtx));
+ }
else
{
- enum reg_class src1_class, src2_class, dst_class;
-
- src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
- src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
- dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
- /* If no extended registers are used, then the best way to handle
- this is to copy the first source operand into the destination
- and emit a two address subtraction. */
- if (src1_class != EXTENDED_REGS
- && src2_class != EXTENDED_REGS
- && dst_class != EXTENDED_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;sub %2,%0\";
- return \"sub %2,%1,%0\";
+ emit_move_insn (operands[0], const0_rtx);
+ emit_insn (gen_subsi3 (operands[0], operands[0], operands[1]));
}
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dax")
- (minus:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "daxi")))]
- ""
- "sub %2,%0"
- [(set_attr "cc" "set_zn")])
-
-(define_expand "negsi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (neg:SI (match_operand:SI 1 "register_operand" "")))]
- ""
- "
-{
- rtx target = gen_reg_rtx (SImode);
-
- emit_move_insn (target, const0_rtx);
- emit_insn (gen_subsi3 (target, target, operands[1]));
- emit_move_insn (operands[0], target);
DONE;
-}")
+})
;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_insn "mulsidi3"
- [(set (match_operand:DI 0 "register_operand" "=dax")
- (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "dax"))
- (sign_extend:DI (match_operand:SI 2 "register_operand" "dax"))))]
- "TARGET_AM33"
- "mul %1,%2,%H0,%L0"
- [(set_attr "cc" "set_zn")])
+;; ??? Note that AM33 has a third multiply variant that puts the high part
+;; into the MDRQ register, however this variant also constrains the inputs
+;; to be in DATA_REGS and thus isn't as helpful as it might be considering
+;; the existence of the 4-operand multiply. Nor is there a set of divide
+;; insns that use MDRQ. Given that there is an IMM->MDRQ insn, this would
+;; have been very handy for starting udivmodsi4...
-(define_insn "umulsidi3"
- [(set (match_operand:DI 0 "register_operand" "=dax")
- (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "dax"))
- (zero_extend:DI (match_operand:SI 2 "register_operand" "dax"))))]
- "TARGET_AM33"
- "mulu %1,%2,%H0,%L0"
- [(set_attr "cc" "set_zn")])
-
-(define_expand "mulsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (mult:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "register_operand" "")))]
+(define_expand "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" ""))))]
""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (mult:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "dx,daxi")))]
- "TARGET_AM33"
- "*
{
- if (TARGET_MULT_BUG)
- return \"nop\;nop\;mul %2,%0\";
- else
- return \"mul %2,%0\";
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (mult:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "dx")))]
+ emit_insn (gen_mulsidi3_internal (gen_lowpart (SImode, operands[0]),
+ gen_highpart (SImode, operands[0]),
+ operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "mulsidi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
+ (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+ (match_operand:SI 3 "register_operand" " D,r")))
+ (set (match_operand:SI 1 "register_operand" "=z,r")
+ (truncate:SI
+ (ashiftrt:DI
+ (mult:DI (sign_extend:DI (match_dup 2))
+ (sign_extend:DI (match_dup 3)))
+ (const_int 32))))
+ (clobber (reg:CC CC_REG))]
""
- "*
{
- if (TARGET_MULT_BUG)
- return \"nop\;nop\;mul %2,%0\";
+ if (which_alternative == 1)
+ return "mul %2,%3,%1,%0";
+ else if (TARGET_MULT_BUG)
+ return "nop\;nop\;mul %3,%0";
else
- return \"mul %2,%0\";
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn "udivmodsi4"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx")
- (udiv:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "dx")))
- (set (match_operand:SI 3 "nonimmediate_operand" "=&d")
- (umod:SI (match_dup 1) (match_dup 2)))]
+ return "mul %3,%0";
+}
+ [(set_attr "isa" "*,am33")
+ (set (attr "timings")
+ (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+)
+
+(define_expand "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))
+ (clobber (reg:CC CC_REG))]
""
- "*
{
- output_asm_insn (\"sub %3,%3\;mov %3,mdr\", operands);
-
- if (find_reg_note (insn, REG_UNUSED, operands[3]))
- return \"divu %2,%0\";
- else
- return \"divu %2,%0\;mov mdr,%3\";
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn "divmodsi4"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx")
- (div:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "dx")))
- (set (match_operand:SI 3 "nonimmediate_operand" "=d")
- (mod:SI (match_dup 1) (match_dup 2)))]
+ emit_insn (gen_umulsidi3_internal (gen_lowpart (SImode, operands[0]),
+ gen_highpart (SImode, operands[0]),
+ operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "umulsidi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
+ (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+ (match_operand:SI 3 "register_operand" " D,r")))
+ (set (match_operand:SI 1 "register_operand" "=z,r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI (match_dup 2))
+ (zero_extend:DI (match_dup 3)))
+ (const_int 32))))
+ (clobber (reg:CC CC_REG))]
""
- "*
{
- if (find_reg_note (insn, REG_UNUSED, operands[3]))
- return \"ext %0\;div %2,%0\";
+ if (which_alternative == 1)
+ return "mulu %2,%3,%1,%0";
+ else if (TARGET_MULT_BUG)
+ return "nop\;nop\;mulu %3,%0";
else
- return \"ext %0\;div %2,%0\;mov mdr,%3\";
-}"
- [(set_attr "cc" "set_zn")])
-
-\f
-;; ----------------------------------------------------------------------
-;; AND INSTRUCTIONS
-;; ----------------------------------------------------------------------
+ return "mulu %3,%0";
+}
+ [(set_attr "isa" "*,am33")
+ (set (attr "timings")
+ (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+)
-(define_expand "andsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (and:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
+(define_expand "mulsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (mult:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "reg_or_am33_const_operand")))
+ (clobber (match_scratch:SI 3))
+ (clobber (reg:CC CC_REG))])]
""
- "")
+)
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0,dax")
- (match_operand:SI 2 "nonmemory_operand" "N,dxi,dax")))]
- "TARGET_AM33"
- "*
-{
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff)
- return \"extbu %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff)
- return \"exthu %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fffffff)
- return \"add %0,%0\;lsr 1,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x3fffffff)
- return \"asl2 %0\;lsr 2,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x1fffffff)
- return \"add %0,%0\;asl2 %0\;lsr 3,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x0fffffff)
- return \"asl2 %0\;asl2 %0\;lsr 4,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffe)
- return \"lsr 1,%0\;add %0,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffc)
- return \"lsr 2,%0\;asl2 %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff8)
- return \"lsr 3,%0\;add %0,%0\;asl2 %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff0)
- return \"lsr 4,%0\;asl2 %0\;asl2 %0\";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2])
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
- return \"mov %1,%0\;and %2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"and %1,%2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[0])
- && true_regnum (operands[2]) == true_regnum (operands[0]))
- return \"and %1,%0\";
- return \"and %2,%0\";
-}"
- [(set (attr "cc")
- (cond
- [
- (eq (symbol_ref "which_alternative") (const_int 0)
- ) (const_string "none_0hit")
- (ne (symbol_ref "GET_CODE (operands[2]) == CONST_INT
- && (INTVAL (operands[2]) == 0x7fffffff
- || INTVAL (operands[2]) == 0x3fffffff
- || INTVAL (operands[2]) == 0x1fffffff
- || INTVAL (operands[2]) == 0x0fffffff
- || INTVAL (operands[2]) == 0xfffffffe
- || INTVAL (operands[2]) == 0xfffffffc
- || INTVAL (operands[2]) == 0xfffffff8
- || INTVAL (operands[2]) == 0xfffffff0)")
- (const_int 0)) (const_string "set_zn")
- ] (const_string "set_znv")))])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,dx")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "N,dxi")))]
+(define_insn "*mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D, r,r")
+ (mult:SI (match_operand:SI 2 "register_operand" "%0, 0,r")
+ (match_operand:SI 3 "reg_or_am33_const_operand" " D,ri,r")))
+ (clobber (match_scratch:SI 1 "=z, z,r"))
+ (clobber (reg:CC CC_REG))]
""
- "*
{
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff)
- return \"extbu %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff)
- return \"exthu %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fffffff)
- return \"add %0,%0\;lsr 1,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x3fffffff)
- return \"asl2 %0\;lsr 2,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x1fffffff)
- return \"add %0,%0\;asl2 %0\;lsr 3,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x0fffffff)
- return \"asl2 %0\;asl2 %0\;lsr 4,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffe)
- return \"lsr 1,%0\;add %0,%0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffc)
- return \"lsr 2,%0\;asl2 %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff8)
- return \"lsr 3,%0\;add %0,%0\;asl2 %0\";
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff0)
- return \"lsr 4,%0\;asl2 %0\;asl2 %0\";
- return \"and %2,%0\";
-}"
- [(set (attr "cc")
- (cond
- [
- (eq (symbol_ref "which_alternative") (const_int 0)
- ) (const_string "none_0hit")
- ;; Shifts don't set the V flag, but bitwise operations clear
- ;; it (which correctly reflects the absence of overflow in a
- ;; compare-with-zero that might follow). As for the
- ;; 0xfffffffe case, the add may overflow, so we can't use the
- ;; V flag.
- (ne (symbol_ref "GET_CODE (operands[2]) == CONST_INT
- && (INTVAL (operands[2]) == 0x7fffffff
- || INTVAL (operands[2]) == 0x3fffffff
- || INTVAL (operands[2]) == 0x1fffffff
- || INTVAL (operands[2]) == 0x0fffffff
- || INTVAL (operands[2]) == 0xfffffffe
- || INTVAL (operands[2]) == 0xfffffffc
- || INTVAL (operands[2]) == 0xfffffff8
- || INTVAL (operands[2]) == 0xfffffff0)")
- (const_int 0)) (const_string "set_zn")
- ] (const_string "set_znv")))])
-
-;; ----------------------------------------------------------------------
-;; OR INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(define_expand "iorsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (ior:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,dax")
- (match_operand:SI 2 "nonmemory_operand" "dxi,dax")))]
- "TARGET_AM33"
- "*
-{
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2])
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
- return \"mov %1,%0\;or %2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"or %1,%2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[0])
- && true_regnum (operands[2]) == true_regnum (operands[0]))
- return \"or %1,%0\";
- return \"or %2,%0\";
-}"
- [(set_attr "cc" "set_znv")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (ior:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "nonmemory_operand" "dxi")))]
- ""
- "or %2,%0"
- [(set_attr "cc" "set_znv")])
-
-;; ----------------------------------------------------------------------
-;; XOR INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(define_expand "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (xor:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
+ if (which_alternative == 2)
+ return "mul %2,%3,%1,%0";
+ else if (TARGET_MULT_BUG)
+ return "nop\;nop\;mul %3,%0";
+ else
+ return "mul %3,%0";
+}
+ [(set_attr "isa" "*,am33,am33")
+ (set (attr "timings")
+ (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+)
+
+(define_expand "udivmodsi4"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (udiv:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "register_operand")))
+ (set (match_operand:SI 3 "register_operand")
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (use (const_int 0))
+ (clobber (reg:CC CC_REG))])]
+ ""
+)
+
+;; Note the trick to get reload to put the zero into the MDR register,
+;; rather than exposing the load early and letting CSE or someone try
+;; to share the zeros between division insns. Which tends to result
+;; in sequences like 0->r0->d0->mdr.
+
+(define_insn "*udivmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (udiv:SI (match_operand:SI 2 "register_operand" " 0")
+ (match_operand:SI 3 "register_operand" " D")))
+ (set (match_operand:SI 1 "register_operand" "=z")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "nonmemory_operand" " 1"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "divu %3,%0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 3839) (const_int 4243)))]
+)
+
+(define_expand "divmodsi4"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (div:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (match_operand:SI 3 "register_operand" "")
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (use (match_dup 4))
+ (clobber (reg:CC CC_REG))])]
""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (xor:SI (match_operand:SI 1 "register_operand" "%0,dax")
- (match_operand:SI 2 "nonmemory_operand" "dxi,dax")))]
- "TARGET_AM33"
- "*
{
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2])
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
- return \"mov %1,%0\;xor %2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"xor %1,%2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[0])
- && true_regnum (operands[2]) == true_regnum (operands[0]))
- return \"xor %1,%0\";
- return \"xor %2,%0\";
-}"
- [(set_attr "cc" "set_znv")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (xor:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "nonmemory_operand" "dxi")))]
- ""
- "xor %2,%0"
- [(set_attr "cc" "set_znv")])
+ operands[4] = gen_reg_rtx (SImode);
+ emit_insn (gen_ext_internal (operands[4], operands[1]));
+})
+
+;; ??? Ideally we'd represent this via shift, but it seems like adding a
+;; special-case pattern for (ashiftrt x 31) is just as likely to result
+;; in poor register allocation choices.
+(define_insn "ext_internal"
+ [(set (match_operand:SI 0 "register_operand" "=z")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "D")] UNSPEC_EXT))]
+ ""
+ "ext %1"
+)
+
+(define_insn "*divmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (div:SI (match_operand:SI 2 "register_operand" " 0")
+ (match_operand:SI 3 "register_operand" " D")))
+ (set (match_operand:SI 1 "register_operand" "=z")
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "register_operand" " 1"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "div %3,%0";
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 3839) (const_int 4243)))]
+)
+\f
;; ----------------------------------------------------------------------
-;; NOT INSTRUCTIONS
+;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "one_cmplsi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (not:SI (match_operand:SI 1 "register_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (not:SI (match_operand:SI 1 "register_operand" "0,0")))]
- "TARGET_AM33"
- "not %0"
- [(set_attr "cc" "set_znv")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (not:SI (match_operand:SI 1 "register_operand" "0")))]
- ""
- "not %0"
- [(set_attr "cc" "set_znv")])
-\f
-;; -----------------------------------------------------------------
-;; BIT FIELDS
-;; -----------------------------------------------------------------
-
-
-;; These set/clear memory in byte sized chunks.
-;;
-;; They are no smaller/faster than loading the value into a register
-;; and storing the register, but they don't need a scratch register
-;; which may allow for better code generation.
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=R,d") (const_int 0))]
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
""
"@
- bclr 255,%A0
- clr %0"
- [(set_attr "cc" "clobber")])
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=R,d") (const_int -1))]
- ""
- "@
- bset 255,%A0
- mov -1,%0"
- [(set_attr "cc" "clobber,none_0hit")])
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
- (subreg:QI
- (and:SI (subreg:SI (match_dup 0) 0)
- (match_operand:SI 1 "const_int_operand" "i,i")) 0))]
- ""
- "@
- bclr %N1,%A0
- and %1,%0"
- [(set_attr "cc" "clobber,set_znv")])
-
-(define_insn ""
- [(set (match_operand:QI 0 "memory_operand" "=R,T")
- (and:QI
- (match_dup 0)
- (not:QI (match_operand:QI 1 "nonmemory_operand" "i,d"))))]
- ""
- "@
- bclr %U1,%A0
- bclr %1,%0"
- [(set_attr "cc" "clobber,clobber")])
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
- (subreg:QI
- (ior:SI (subreg:SI (match_dup 0) 0)
- (match_operand:SI 1 "const_int_operand" "i,i")) 0))]
- ""
- "@
- bset %U1,%A0
- or %1,%0"
- [(set_attr "cc" "clobber,set_znv")])
-
-(define_expand "iorqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "")
- (ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=R,T,r")
- (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
- ;; This constraint should really be nonmemory_operand,
- ;; but making it general_operand, along with the
- ;; condition that not both input operands are MEMs, it
- ;; here helps combine do a better job.
- (match_operand:QI 2 "general_operand" "i,d,ir")))]
- "TARGET_AM33 &&
- (GET_CODE (operands[2]) != MEM || GET_CODE (operands[1]) != MEM)"
- "@
- bset %U2,%A0
- bset %2,%0
- or %2,%0"
- [(set_attr "cc" "clobber,clobber,set_znv")])
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=R,T,d")
- (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
- ;; This constraint should really be nonmemory_operand,
- ;; but making it general_operand, along with the
- ;; condition that not both input operands are MEMs, it
- ;; here helps combine do a better job.
- (match_operand:QI 2 "general_operand" "i,d,id")))]
- "GET_CODE (operands[2]) != MEM || GET_CODE (operands[1]) != MEM"
+ and %2,%0
+ and %2,%0
+ and %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "and")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*andsi3_flags"
+ [(set (reg CC_REG)
+ (compare (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (and:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
"@
- bset %U2,%A0
- bset %2,%0
- or %2,%0"
- [(set_attr "cc" "clobber,clobber,set_znv")])
-
-(define_insn ""
- [(set (cc0)
- (zero_extract:SI (match_operand:SI 0 "register_operand" "dx")
- (match_operand 1 "const_int_operand" "")
- (match_operand 2 "const_int_operand" "")))]
- ""
- "*
-{
- int len = INTVAL (operands[1]);
- int bit = INTVAL (operands[2]);
- int mask = 0;
- rtx xoperands[2];
-
- while (len > 0)
- {
- mask |= (1 << bit);
- bit++;
- len--;
- }
-
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
- output_asm_insn (\"btst %1,%0\", xoperands);
- return \"\";
-}"
- [(set_attr "cc" "clobber")])
-
-(define_insn ""
- [(set (cc0)
- (zero_extract:SI (match_operand:QI 0 "general_operand" "R,dx")
- (match_operand 1 "const_int_operand" "")
- (match_operand 2 "const_int_operand" "")))]
- "mask_ok_for_mem_btst (INTVAL (operands[1]), INTVAL (operands[2]))"
- "*
+ and %2,%0
+ and %2,%0
+ and %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+;; Make sure we generate extensions instead of ANDs.
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 255)))
+ (clobber (reg:CC CC_REG))])]
+ ""
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ { operands[1] = gen_lowpart (QImode, operands[1]); }
+)
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 65535)))
+ (clobber (reg:CC CC_REG))])]
+ ""
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ { operands[1] = gen_lowpart (HImode, operands[1]); }
+)
+
+;; Split AND by an appropriate constant into two shifts. Recall that
+;; operations with a full 32-bit immediate require an extra cycle, so
+;; this is a size optimization with no speed penalty. This only applies
+;; do DATA_REGS; the shift insns that AM33 adds are too large for a win.
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_dup 0)
+ (match_operand:SI 1 "const_int_operand" "")))
+ (clobber (reg:CC CC_REG))])]
+ "reload_completed
+ && REGNO_DATA_P (true_regnum (operands[0]), 1)
+ && mn10300_split_and_operand_count (operands[1]) != 0"
+ [(const_int 0)]
{
- int len = INTVAL (operands[1]);
- int bit = INTVAL (operands[2]);
- int mask = 0;
- rtx xoperands[2];
-
- while (len > 0)
+ int count = mn10300_split_and_operand_count (operands[1]);
+ if (count > 0)
{
- mask |= (1 << bit);
- bit++;
- len--;
+ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (count)));
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (count)));
}
-
- /* If the source operand is not a reg (i.e. it is memory), then extract the
- bits from mask that we actually want to test. Note that the mask will
- never cross a byte boundary. */
- if (!REG_P (operands[0]))
+ else
{
- if (mask & 0xff)
- mask = mask & 0xff;
- else if (mask & 0xff00)
- mask = (mask >> 8) & 0xff;
- else if (mask & 0xff0000)
- mask = (mask >> 16) & 0xff;
- else if (mask & 0xff000000)
- mask = (mask >> 24) & 0xff;
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (-count)));
+ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (-count)));
}
-
- xoperands[0] = operands[0];
- xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
- if (GET_CODE (operands[0]) == REG)
- output_asm_insn (\"btst %1,%0\", xoperands);
- else
- output_asm_insn (\"btst %U1,%A0\", xoperands);
- return \"\";
-}"
- [(set_attr "cc" "clobber")])
-
-(define_insn ""
- [(set (cc0) (and:SI (match_operand:SI 0 "register_operand" "dx")
- (match_operand:SI 1 "const_int_operand" "")))]
- ""
- "btst %1,%0"
- [(set_attr "cc" "clobber")])
+ DONE;
+})
+
+;; ----------------------------------------------------------------------
+;; OR INSTRUCTIONS
+;; ----------------------------------------------------------------------
-(define_insn ""
- [(set (cc0)
- (and:SI
- (subreg:SI (match_operand:QI 0 "general_operand" "R,dx") 0)
- (match_operand:SI 1 "const_8bit_operand" "")))]
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
""
"@
- btst %U1,%A0
- btst %1,%0"
- [(set_attr "cc" "clobber")])
+ or %2,%0
+ or %2,%0
+ or %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "or")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*iorsi3_flags"
+ [(set (reg CC_REG)
+ (compare (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (ior:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ or %2,%0
+ or %2,%0
+ or %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
-\f
;; ----------------------------------------------------------------------
-;; JUMP INSTRUCTIONS
+;; XOR INSTRUCTIONS
;; ----------------------------------------------------------------------
-;; Conditional jump instructions
-
-(define_expand "ble"
- [(set (pc)
- (if_then_else (le (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bleu"
- [(set (pc)
- (if_then_else (leu (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
""
- "")
+ "@
+ xor %2,%0
+ xor %2,%0
+ xor %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "xor")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*xorsi3_flags"
+ [(set (reg CC_REG)
+ (compare (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (xor:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ xor %2,%0
+ xor %2,%0
+ xor %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
-(define_expand "bge"
- [(set (pc)
- (if_then_else (ge (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
+;; ----------------------------------------------------------------------
+;; NOT INSTRUCTIONS
+;; ----------------------------------------------------------------------
-(define_expand "bgeu"
- [(set (pc)
- (if_then_else (geu (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (not:SI (match_operand:SI 1 "register_operand" " 0")))
+ (clobber (reg:CC CC_REG))]
""
- "")
+ "not %0"
+)
+
+(define_insn "*one_cmplsi2_flags"
+ [(set (reg CC_REG)
+ (compare (not:SI (match_operand:SI 1 "register_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=D")
+ (not:SI (match_dup 1)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "not %0"
+)
+\f
+;; ----------------------------------------------------------------------
+;; COMPARE AND BRANCH INSTRUCTIONS
+;; ----------------------------------------------------------------------
-(define_expand "blt"
+;; We expand the comparison into a single insn so that it will not be split
+;; up by reload.
+(define_expand "cbranchsi4"
[(set (pc)
- (if_then_else (lt (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
""
- "")
-
-(define_expand "bltu"
- [(set (pc)
- (if_then_else (ltu (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
""
- "")
+)
-(define_expand "bgt"
+(define_insn_and_split "*cbranchsi4_cmp"
[(set (pc)
- (if_then_else (gt (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
+ (if_then_else (match_operator 3 "ordered_comparison_operator"
+ [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "nonmemory_operand" "ri")])
+ (match_operand 2 "label_ref_operand" "")
(pc)))]
""
- "")
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ mn10300_split_cbranch (CCmode, operands[3], operands[2]);
+ DONE;
+})
-(define_expand "bgtu"
+(define_insn "cmpsi"
+ [(set (reg CC_REG)
+ (compare (match_operand:SI 0 "register_operand" "r,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
+ "reload_completed"
+{
+ /* The operands of CMP must be distinct registers. In the case where
+ we've failed to optimize the comparison of a register to itself, we
+ must use another method to set the Z flag. We can achieve this
+ effect with a BTST 0,D0. This will not alter the contents of D0;
+ the use of d0 is arbitrary; any data register would work. */
+ if (rtx_equal_p (operands[0], operands[1]))
+ return "btst 0,d0";
+ else
+ return "cmp %1,%0";
+}
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
+ (set_attr "liw" "either,either,*")
+ (set_attr "liw_op" "cmp")]
+)
+
+(define_insn "*integer_conditional_branch"
[(set (pc)
- (if_then_else (gtu (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand 2 "int_mode_flags" "")
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
(pc)))]
- ""
- "")
+ "reload_completed"
+ "b%b0 %1"
+)
-(define_expand "beq"
+(define_insn_and_split "*cbranchsi4_btst"
[(set (pc)
- (if_then_else (eq (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
+ (if_then_else
+ (match_operator 3 "CCZN_comparison_operator"
+ [(and:SI (match_operand:SI 0 "register_operand" "D")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ (const_int 0)])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
""
- "")
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ mn10300_split_cbranch (CCZNmode, operands[3], operands[2]);
+ DONE;
+})
+
+(define_insn "*btstsi"
+ [(set (reg:CCZN CC_REG)
+ (compare:CCZN
+ (and:SI (match_operand:SI 0 "register_operand" "D")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ (const_int 0)))]
+ "reload_completed"
+ "btst %1,%0"
+)
-(define_expand "bne"
+(define_expand "cbranchsf4"
[(set (pc)
- (if_then_else (ne (cc0)
- (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "nonmemory_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "TARGET_AM33_2"
""
- "")
+)
-(define_insn ""
+(define_insn_and_split "*cbranchsf4_cmp"
[(set (pc)
- (if_then_else (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "*
+ (if_then_else (match_operator 3 "ordered_comparison_operator"
+ [(match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "nonmemory_operand" "fF")])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))
+ ]
+ "TARGET_AM33_2"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
{
- if (cc_status.mdep.fpCC)
- return \"fb%b1 %0\";
- if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
- && (GET_CODE (operands[1]) == GT
- || GET_CODE (operands[1]) == GE
- || GET_CODE (operands[1]) == LE
- || GET_CODE (operands[1]) == LT))
- return 0;
- return \"b%b1 %0\";
-}"
- [(set_attr "cc" "none")])
-
-(define_insn ""
+ mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]);
+ DONE;
+})
+
+(define_insn "*am33_cmpsf"
+ [(set (reg:CC_FLOAT CC_REG)
+ (compare:CC_FLOAT (match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "nonmemory_operand" "fF")))]
+ "TARGET_AM33_2 && reload_completed"
+ "fcmp %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25)))]
+)
+
+(define_insn "*float_conditional_branch"
[(set (pc)
- (if_then_else (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
- (pc)
- (label_ref (match_operand 0 "" ""))))]
- ""
- "*
-{
- if (cc_status.mdep.fpCC)
- return \"fb%B1 %0\";
- if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
- && (GET_CODE (operands[1]) == GT
- || GET_CODE (operands[1]) == GE
- || GET_CODE (operands[1]) == LE
- || GET_CODE (operands[1]) == LT))
- return 0;
- return \"b%B1 %0\";
-}"
- [(set_attr "cc" "none")])
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(reg:CC_FLOAT CC_REG) (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "TARGET_AM33_2 && reload_completed"
+ "fb%b0 %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 44) (const_int 33)))]
+)
;; Unconditional and other jump instructions.
(label_ref (match_operand 0 "" "")))]
""
"jmp %l0"
- [(set_attr "cc" "none")])
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 44)))]
+)
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "a"))]
""
"jmp (%0)"
- [(set_attr "cc" "none")])
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 33)))]
+)
(define_expand "builtin_setjmp_receiver"
[(match_operand 0 "" "")]
"flag_pic"
- "
{
- if (flag_pic)
- emit_insn (gen_GOTaddr2picreg ());
-
+ emit_insn (gen_load_pic ());
DONE;
-}")
+})
(define_expand "casesi"
- [(match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "immediate_operand" "")
- (match_operand:SI 2 "immediate_operand" "")
- (match_operand 3 "" "") (match_operand 4 "" "")]
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "immediate_operand")
+ (match_operand:SI 2 "immediate_operand")
+ (match_operand 3 "" "") (match_operand 4 "")]
""
- "
{
rtx table = gen_reg_rtx (SImode);
rtx index = gen_reg_rtx (SImode);
rtx addr = gen_reg_rtx (Pmode);
+ rtx test;
emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3]));
- emit_move_insn (index, plus_constant (operands[0], - INTVAL (operands[1])));
- emit_insn (gen_cmpsi (index, operands[2]));
- emit_jump_insn (gen_bgtu (operands[4]));
- emit_move_insn (index, gen_rtx_ASHIFT (SImode, index, const2_rtx));
+ emit_insn (gen_addsi3 (index, operands[0], GEN_INT (- INTVAL (operands[1]))));
+ test = gen_rtx_fmt_ee (GTU, VOIDmode, index, operands[2]);
+ emit_jump_insn (gen_cbranchsi4 (test, index, operands[2], operands[4]));
+
+ emit_insn (gen_ashlsi3 (index, index, const2_rtx));
emit_move_insn (addr, gen_rtx_MEM (SImode,
gen_rtx_PLUS (SImode, table, index)));
if (flag_pic)
- emit_move_insn (addr, gen_rtx_PLUS (SImode, addr, table));
+ emit_insn (gen_addsi3 (addr, addr, table));
emit_jump_insn (gen_tablejump (addr, operands[3]));
DONE;
-}")
+})
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "a"))
(use (label_ref (match_operand 1 "" "")))]
""
"jmp (%0)"
- [(set_attr "cc" "none")])
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 33)))]
+)
;; Call subroutine with no return value.
(define_expand "call"
- [(call (match_operand:QI 0 "general_operand" "")
- (match_operand:SI 1 "general_operand" ""))]
+ [(call (match_operand:QI 0 "general_operand")
+ (match_operand:SI 1 "general_operand"))]
""
- "
{
- if (flag_pic && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+ rtx fn = XEXP (operands[0], 0);
+
+ if (flag_pic && GET_CODE (fn) == SYMBOL_REF)
{
- if (MN10300_GLOBAL_P (XEXP (operands[0], 0)))
+ if (MN10300_GLOBAL_P (fn))
{
/* The PLT code won't run on AM30, but then, there's no
shared library support for AM30 either, so we just assume
the linker is going to adjust all @PLT relocs to the
actual symbols. */
- emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
- XEXP (operands[0], 0) = gen_sym2PLT (XEXP (operands[0], 0));
+ emit_use (pic_offset_table_rtx);
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PLT);
}
else
- XEXP (operands[0], 0) = gen_sym2PIC (XEXP (operands[0], 0));
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PIC);
}
- if (! call_address_operand (XEXP (operands[0], 0), VOIDmode))
- XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
- emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1]));
- DONE;
-}")
+ if (! call_address_operand (fn, VOIDmode))
+ fn = force_reg (SImode, fn);
+
+ XEXP (operands[0], 0) = fn;
+})
-(define_insn "call_internal"
- [(call (mem:QI (match_operand:SI 0 "call_address_operand" "aS"))
- (match_operand:SI 1 "general_operand" "g"))]
+(define_insn "*call_internal"
+ [(call (mem:QI (match_operand:SI 0 "call_address_operand" "a,S"))
+ (match_operand:SI 1 "" ""))]
""
- "*
-{
- if (REG_P (operands[0]))
- return \"calls %C0\";
- else
- return \"call %C0,[],0\";
-}"
- [(set_attr "cc" "clobber")])
+ "@
+ calls %C0
+ call %C0,[],0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 33) (const_int 44))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 55) (const_int 33))
+ ])
+ ]
+)
;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
(define_expand "call_value"
- [(set (match_operand 0 "" "")
- (call (match_operand:QI 1 "general_operand" "")
- (match_operand:SI 2 "general_operand" "")))]
+ [(set (match_operand 0 "")
+ (call (match_operand:QI 1 "general_operand")
+ (match_operand:SI 2 "general_operand")))]
""
- "
{
- if (flag_pic && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+ rtx fn = XEXP (operands[1], 0);
+
+ if (flag_pic && GET_CODE (fn) == SYMBOL_REF)
{
- if (MN10300_GLOBAL_P (XEXP (operands[1], 0)))
+ if (MN10300_GLOBAL_P (fn))
{
/* The PLT code won't run on AM30, but then, there's no
shared library support for AM30 either, so we just assume
the linker is going to adjust all @PLT relocs to the
actual symbols. */
- emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
- XEXP (operands[1], 0) = gen_sym2PLT (XEXP (operands[1], 0));
+ emit_use (pic_offset_table_rtx);
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PLT);
}
else
- XEXP (operands[1], 0) = gen_sym2PIC (XEXP (operands[1], 0));
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PIC);
}
- if (! call_address_operand (XEXP (operands[1], 0), VOIDmode))
- XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
- emit_call_insn (gen_call_value_internal (operands[0],
- XEXP (operands[1], 0),
- operands[2]));
- DONE;
-}")
+ if (! call_address_operand (fn, VOIDmode))
+ fn = force_reg (SImode, fn);
+
+ XEXP (operands[1], 0) = fn;
+})
(define_insn "call_value_internal"
- [(set (match_operand 0 "" "=dax")
- (call (mem:QI (match_operand:SI 1 "call_address_operand" "aS"))
- (match_operand:SI 2 "general_operand" "g")))]
+ [(set (match_operand 0 "" "")
+ (call (mem:QI (match_operand:SI 1 "call_address_operand" "a,S"))
+ (match_operand:SI 2 "" "")))]
""
- "*
-{
- if (REG_P (operands[1]))
- return \"calls %C1\";
- else
- return \"call %C1,[],0\";
-}"
- [(set_attr "cc" "clobber")])
+ "@
+ calls %C1
+ call %C1,[],0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 33) (const_int 44))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 55) (const_int 33))
+ ])
+ ]
+)
(define_expand "untyped_call"
- [(parallel [(call (match_operand 0 "" "")
+ [(parallel [(call (match_operand 0 "")
(const_int 0))
- (match_operand 1 "" "")
- (match_operand 2 "" "")])]
+ (match_operand 1 "")
+ (match_operand 2 "")])]
""
- "
{
int i;
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
DONE;
-}")
+})
(define_insn "nop"
[(const_int 0)]
""
"nop"
- [(set_attr "cc" "none")])
+)
\f
;; ----------------------------------------------------------------------
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "zero_extendqisi2"
- [(set (match_operand:SI 0 "general_operand" "")
- (zero_extend:SI
- (match_operand:QI 1 "general_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,dx,!dax,!dax,!dax")
- (zero_extend:SI
- (match_operand:QI 1 "general_operand" "0,dax,m,0,dax,m")))]
- "TARGET_AM33"
- "@
- extbu %0
- mov %1,%0\;extbu %0
- movbu %1,%0
- extbu %0
- mov %1,%0\;extbu %0
- movbu %1,%0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,dx")
- (zero_extend:SI
- (match_operand:QI 1 "general_operand" "0,d,m")))]
- ""
- "@
- extbu %0
- mov %1,%0\;extbu %0
- movbu %1,%0"
- [(set_attr "cc" "none_0hit")])
-
-(define_expand "zero_extendhisi2"
- [(set (match_operand:SI 0 "general_operand" "")
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
(zero_extend:SI
- (match_operand:HI 1 "general_operand" "")))]
+ (match_operand:QI 1 "nonimmediate_operand" " 0,m,r")))]
""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,dx,!dax,!dax,!dax")
- (zero_extend:SI
- (match_operand:HI 1 "general_operand" "0,dax,m,0,dax,m")))]
- "TARGET_AM33"
"@
- exthu %0
- mov %1,%0\;exthu %0
- movhu %1,%0
- exthu %0
- mov %1,%0\;exthu %0
- movhu %1,%0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,dx")
+ extbu %0
+ movbu %1,%0
+ extbu %1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)
+ ])]
+)
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
(zero_extend:SI
- (match_operand:HI 1 "general_operand" "0,dx,m")))]
- ""
- "@
- exthu %0
- mov %1,%0\;exthu %0
- movhu %1,%0"
- [(set_attr "cc" "none_0hit")])
-
-;;- sign extension instructions
-
-(define_expand "extendqisi2"
- [(set (match_operand:SI 0 "general_operand" "")
- (sign_extend:SI
- (match_operand:QI 1 "general_operand" "")))]
+ (match_operand:HI 1 "nonimmediate_operand" " 0,m,r")))]
""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,!dax,!dax")
- (sign_extend:SI
- (match_operand:QI 1 "general_operand" "0,dx,0,dax")))]
- "TARGET_AM33"
"@
- extb %0
- mov %1,%0\;extb %0
- extb %0
- mov %1,%0\;extb %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx")
+ exthu %0
+ movhu %1,%0
+ exthu %1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)])]
+)
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
(sign_extend:SI
- (match_operand:QI 1 "general_operand" "0,dx")))]
+ (match_operand:QI 1 "register_operand" "0,r")))]
""
"@
- extb %0
- mov %1,%0\;extb %0"
- [(set_attr "cc" "none_0hit")])
+ extb %0
+ extb %1,%0"
+ [(set_attr "isa" "*,am33")]
+)
-(define_expand "extendhisi2"
- [(set (match_operand:SI 0 "general_operand" "")
- (sign_extend:SI
- (match_operand:HI 1 "general_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,!dax,!dax")
- (sign_extend:SI
- (match_operand:HI 1 "general_operand" "0,dax,0,dax")))]
- "TARGET_AM33"
- "@
- exth %0
- mov %1,%0\;exth %0
- exth %0
- mov %1,%0\;exth %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx")
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
(sign_extend:SI
- (match_operand:HI 1 "general_operand" "0,dx")))]
+ (match_operand:HI 1 "register_operand" "0,r")))]
""
"@
- exth %0
- mov %1,%0\;exth %0"
- [(set_attr "cc" "none_0hit")])
+ exth %0
+ exth %1,%0"
+ [(set_attr "isa" "*,am33")]
+)
\f
;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
-(define_expand "ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (ashift:SI
- (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dax,dx,!dax")
- (ashift:SI
- (match_operand:SI 1 "register_operand" "0,0,dax")
- (match_operand:QI 2 "nonmemory_operand" "J,dxi,dax")))]
- "TARGET_AM33"
- "*
-{
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 1)
- return \"add %0,%0\";
-
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 2)
- return \"asl2 %0\";
-
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 3
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
- return \"asl2 %0\;add %0,%0\";
-
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 4
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
- return \"asl2 %0\;asl2 %0\";
-
- if (true_regnum (operands[1]) == true_regnum (operands[0]))
- return \"asl %S2,%0\";
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;asl %S2,%0\";
- return \"asl %2,%1,%0\";
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dax,dx,dx,dx,dx")
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,D,r")
(ashift:SI
- (match_operand:SI 1 "register_operand" "0,0,0,0,0")
- (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,dxi")))]
+ (match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,O,i,r")))
+ (clobber (reg:CC CC_REG))]
""
"@
- add %0,%0
- asl2 %0
- asl2 %0\;add %0,%0
- asl2 %0\;asl2 %0
- asl %S2,%0"
- [(set_attr "cc" "set_zn")])
-
-(define_expand "lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (lshiftrt:SI
- (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
- ""
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (lshiftrt:SI
- (match_operand:SI 1 "register_operand" "0,dax")
- (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))]
- "TARGET_AM33"
- "*
-{
- if (true_regnum (operands[1]) == true_regnum (operands[0]))
- return \"lsr %S2,%0\";
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;lsr %S2,%0\";
- return \"lsr %2,%1,%0\";
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx")
+ add %0,%0
+ asl2 %0
+ asl2 %0\;add %0,%0
+ asl2 %0\;asl2 %0
+ asl %S2,%0
+ asl %S2,%0
+ asl %S2,%0
+ asl %2,%1,%0"
+ [(set_attr "isa" "*,*,*,*,*,*,*,am33")
+ (set_attr "liw" "op2,op2,op2,op2,op2,op2,*,*")
+ (set_attr "liw_op" "asl")
+ (set_attr "timings" "11,11,22,22,11,11,11,11")]
+)
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
(lshiftrt:SI
- (match_operand:SI 1 "register_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "dxi")))]
+ (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
+ (clobber (reg:CC CC_REG))]
""
- "lsr %S2,%0"
- [(set_attr "cc" "set_zn")])
-
-(define_expand "ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "")
+ "@
+ lsr %S2,%0
+ lsr %S2,%0
+ lsr %S2,%0
+ lsr %2,%1,%0"
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "op2,op2,*,*")
+ (set_attr "liw_op" "lsr")]
+)
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
(ashiftrt:SI
- (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
+ (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
+ (clobber (reg:CC CC_REG))]
""
- "")
+ "@
+ asr %S2,%0
+ asr %S2,%0
+ asr %S2,%0
+ asr %2,%1,%0"
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "op2,op2,*,*")
+ (set_attr "liw_op" "asr")]
+)
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (ashiftrt:SI
- (match_operand:SI 1 "register_operand" "0,dax")
- (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))]
+;; ----------------------------------------------------------------------
+;; MISCELLANEOUS
+;; ----------------------------------------------------------------------
+
+;; Note the use of the (const_int 0) when generating the insn that matches
+;; the bsch pattern. This ensures that the destination register is
+;; initialised with 0 which will make the BSCH instruction set searching
+;; at bit 31.
+;;
+;; The XOR in the instruction sequence below is there because the BSCH
+;; instruction returns the bit number of the highest set bit and we want
+;; the number of zero bits above that bit. The AM33 does not have a
+;; reverse subtraction instruction, but we can use a simple xor instead
+;; since we know that the top 27 bits are clear.
+(define_expand "clzsi2"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (unspec:SI [(match_operand:SI 1 "register_operand")
+ (const_int 0)] UNSPEC_BSCH))
+ (clobber (reg:CC CC_REG))])
+ (parallel [(set (match_dup 0)
+ (xor:SI (match_dup 0)
+ (const_int 31)))
+ (clobber (reg:CC CC_REG))])]
"TARGET_AM33"
- "*
-{
- if (true_regnum (operands[1]) == true_regnum (operands[0]))
- return \"asr %S2,%0\";
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;asr %S2,%0\";
- return \"asr %2,%1,%0\";
-}"
- [(set_attr "cc" "set_zn")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (ashiftrt:SI
- (match_operand:SI 1 "register_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "dxi")))]
- ""
- "asr %S2,%0"
- [(set_attr "cc" "set_zn")])
+)
+
+(define_insn "*bsch"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "nonmemory_operand" "0")]
+ UNSPEC_BSCH))
+ (clobber (reg:CC CC_REG))]
+ "TARGET_AM33"
+ "bsch %1, %0"
+)
;; ----------------------------------------------------------------------
;; FP INSTRUCTIONS
;; ----------------------------------------------------------------------
-;;
-;; The mn103 series does not have floating point instructions, but since
-;; FP values are held in integer regs, we can clear the high bit easily
-;; which gives us an efficient inline floating point absolute value.
-;;
-;; Similarly for negation of a FP value.
-;;
-
-(define_expand "absdf2"
- [(set (match_operand:DF 0 "register_operand" "")
- (abs:DF (match_operand:DF 1 "register_operand" "")))]
- ""
- "
-{
- rtx target, result, insns;
-
- start_sequence ();
- target = operand_subword (operands[0], 1, 1, DFmode);
- result = expand_binop (SImode, and_optab,
- operand_subword_force (operands[1], 1, DFmode),
- GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
-
- if (result == 0)
- abort ();
-
- if (result != target)
- emit_move_insn (result, target);
-
- emit_move_insn (operand_subword (operands[0], 0, 1, DFmode),
- operand_subword_force (operands[1], 0, DFmode));
-
- insns = get_insns ();
- end_sequence ();
-
- emit_no_conflict_block (insns, operands[0], operands[1], 0, 0);
- DONE;
-}")
-
-(define_expand "abssf2"
- [(set (match_operand:SF 0 "register_operand" "")
- (abs:SF (match_operand:SF 1 "register_operand" "")))]
- ""
- "
-{
- rtx result;
- rtx target;
-
- if (TARGET_AM33_2)
- {
- emit_insn (gen_abssf2_am33_2 (operands[0], operands[1]));
- DONE;
- }
-
- target = operand_subword_force (operands[0], 0, SFmode);
- result = expand_binop (SImode, and_optab,
- operand_subword_force (operands[1], 0, SFmode),
- GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
- if (result == 0)
- abort ();
-
- if (result != target)
- emit_move_insn (result, target);
-
- /* Make a place for REG_EQUAL. */
- emit_move_insn (operands[0], operands[0]);
- DONE;
-}")
-
-(define_insn "abssf2_am33_2"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
(abs:SF (match_operand:SF 1 "register_operand" "0,?f")))]
"TARGET_AM33_2"
"@
fabs %0
fabs %1, %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_expand "negdf2"
- [(set (match_operand:DF 0 "register_operand" "")
- (neg:DF (match_operand:DF 1 "register_operand" "")))]
- ""
- "
-{
- rtx target, result, insns;
-
- start_sequence ();
- target = operand_subword (operands[0], 1, 1, DFmode);
- result = expand_binop (SImode, xor_optab,
- operand_subword_force (operands[1], 1, DFmode),
- GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
- target, 0, OPTAB_WIDEN);
-
- if (result == 0)
- abort ();
-
- if (result != target)
- emit_move_insn (result, target);
-
- emit_move_insn (operand_subword (operands[0], 0, 1, DFmode),
- operand_subword_force (operands[1], 0, DFmode));
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14)))]
+)
- insns = get_insns ();
- end_sequence ();
-
- emit_no_conflict_block (insns, operands[0], operands[1], 0, 0);
- DONE;
-}")
-
-(define_expand "negsf2"
- [(set (match_operand:SF 0 "register_operand" "")
- (neg:SF (match_operand:SF 1 "register_operand" "")))]
- ""
- "
-{
- rtx result;
- rtx target;
-
- if (TARGET_AM33_2)
- {
- emit_insn (gen_negsf2_am33_2 (operands[0], operands[1]));
- DONE;
- }
-
- target = operand_subword_force (operands[0], 0, SFmode);
- result = expand_binop (SImode, xor_optab,
- operand_subword_force (operands[1], 0, SFmode),
- GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
- target, 0, OPTAB_WIDEN);
- if (result == 0)
- abort ();
-
- if (result != target)
- emit_move_insn (result, target);
-
- /* Make a place for REG_EQUAL. */
- emit_move_insn (operands[0], operands[0]);
- DONE;
-}")
-
-(define_insn "negsf2_am33_2"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
(neg:SF (match_operand:SF 1 "register_operand" "0,?f")))]
"TARGET_AM33_2"
"@
fneg %0
fneg %1, %0"
- [(set_attr "cc" "none_0hit")])
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14)))]
+)
(define_expand "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "")
(sqrt:SF (match_operand:SF 1 "register_operand" "")))]
"TARGET_AM33_2 && flag_unsafe_math_optimizations"
- "
{
rtx scratch = gen_reg_rtx (SFmode);
emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode)));
emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)),
scratch));
DONE;
-}")
+})
(define_insn "rsqrtsf2"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (div:SF (match_operand:SF 2 "const_1f_operand" "F,F")
- (sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))]
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (div:SF (match_operand:SF 2 "const_1f_operand" "F,F")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))
+ (clobber (reg:CC_FLOAT CC_REG))]
"TARGET_AM33_2"
"@
frsqrt %0
frsqrt %1, %0"
- [(set_attr "cc" "none_0hit")])
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 4753) (const_int 2327)))]
+)
(define_insn "addsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
(plus:SF (match_operand:SF 1 "register_operand" "%0,f")
- (match_operand:SF 2 "general_operand" "f,?fF")))]
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))]
"TARGET_AM33_2"
"@
fadd %2, %0
fadd %2, %1, %0"
- [(set_attr "cc" "none_0hit")])
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25))
+ ])]
+)
(define_insn "subsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
(minus:SF (match_operand:SF 1 "register_operand" "0,f")
- (match_operand:SF 2 "general_operand" "f,?fF")))]
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))]
"TARGET_AM33_2"
"@
fsub %2, %0
fsub %2, %1, %0"
- [(set_attr "cc" "none_0hit")])
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25))
+ ])]
+)
(define_insn "mulsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
(mult:SF (match_operand:SF 1 "register_operand" "%0,f")
- (match_operand:SF 2 "general_operand" "f,?fF")))]
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
"TARGET_AM33_2"
"@
fmul %2, %0
fmul %2, %1, %0"
- [(set_attr "cc" "none_0hit")])
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25))
+ ])]
+)
(define_insn "divsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (div:SF (match_operand:SF 1 "register_operand" "0,f")
- (match_operand:SF 2 "general_operand" "f,?fF")))]
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (div:SF (match_operand:SF 1 "register_operand" "0,f")
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))]
"TARGET_AM33_2"
"@
fdiv %2, %0
fdiv %2, %1, %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn "fmaddsf4"
- [(set (match_operand:SF 0 "register_operand" "=A")
- (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
- (match_operand:SF 2 "register_operand" "f"))
- (match_operand:SF 3 "register_operand" "f")))]
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 2531) (const_int 1216))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 2531) (const_int 1317))
+ ])]
+)
+
+(define_insn "fmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")
+ (match_operand:SF 3 "register_operand" "f")))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
"TARGET_AM33_2"
"fmadd %1, %2, %3, %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn "fmsubsf4"
- [(set (match_operand:SF 0 "register_operand" "=A")
- (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
- (match_operand:SF 2 "register_operand" "f"))
- (match_operand:SF 3 "register_operand" "f")))]
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+(define_insn "fmssf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")
+ (neg:SF (match_operand:SF 3 "register_operand" "f"))))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
"TARGET_AM33_2"
"fmsub %1, %2, %3, %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn "fnmaddsf4"
- [(set (match_operand:SF 0 "register_operand" "=A")
- (minus:SF (match_operand:SF 3 "register_operand" "f")
- (mult:SF (match_operand:SF 1 "register_operand" "%f")
- (match_operand:SF 2 "register_operand" "f"))))]
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+(define_insn "fnmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
+ (match_operand:SF 2 "register_operand" "f")
+ (match_operand:SF 3 "register_operand" "f")))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
"TARGET_AM33_2"
"fnmadd %1, %2, %3, %0"
- [(set_attr "cc" "none_0hit")])
-
-(define_insn "fnmsubsf4"
- [(set (match_operand:SF 0 "register_operand" "=A")
- (minus:SF (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
- (match_operand:SF 2 "register_operand" "f")))
- (match_operand:SF 3 "register_operand" "f")))]
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+(define_insn "fnmssf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
+ (match_operand:SF 2 "register_operand" "f")
+ (neg:SF (match_operand:SF 3 "register_operand" "f"))))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
"TARGET_AM33_2"
"fnmsub %1, %2, %3, %0"
- [(set_attr "cc" "none_0hit")])
-
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
;; ----------------------------------------------------------------------
;; PROLOGUE/EPILOGUE
(define_expand "prologue"
[(const_int 0)]
""
- "expand_prologue (); DONE;")
+ { mn10300_expand_prologue (); DONE; }
+)
(define_expand "epilogue"
[(return)]
""
- "
+ { mn10300_expand_epilogue (); DONE; }
+)
+
+(define_insn "return"
+ [(return)]
+ "mn10300_can_use_rets_insn ()"
{
- expand_epilogue ();
- DONE;
-}")
+ /* The RETF insn is 4 cycles faster than RETS, though 1 byte larger. */
+ if (optimize_insn_for_speed_p () && mn10300_can_use_retf_insn ())
+ return "retf [],0";
+ else
+ return "rets";
+})
-(define_insn "return_internal"
- [(const_int 2)
- (return)]
+(define_insn "return_ret"
+ [(return)
+ (use (match_operand:SI 0 "const_int_operand" ""))]
""
- "rets"
- [(set_attr "cc" "clobber")])
-
-;; This insn restores the callee saved registers and does a return, it
-;; can also deallocate stack space.
-(define_insn "return_internal_regs"
- [(const_int 0)
- (match_operand:SI 0 "const_int_operand" "i")
- (return)]
- ""
- "*
{
- fputs (\"\\tret \", asm_out_file);
- mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
- fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
- return \"\";
-}"
- [(set_attr "cc" "clobber")])
+ /* The RETF insn is up to 3 cycles faster than RET. */
+ fputs ((mn10300_can_use_retf_insn () ? "\tretf " : "\tret "), asm_out_file);
+ mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs (NULL));
+ fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
+ return "";
+})
;; This instruction matches one generated by mn10300_gen_multiple_store()
(define_insn "store_movm"
- [(match_parallel 0 "store_multiple_operation"
- [(set (reg:SI 9) (plus:SI (reg:SI 9) (match_operand 1 "" "")))])]
+ [(match_parallel 0 "mn10300_store_multiple_operation"
+ [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand 1 "" "")))])]
""
- "*
{
- fputs (\"\\tmovm \", asm_out_file);
+ fputs ("\tmovm ", asm_out_file);
mn10300_print_reg_list (asm_out_file,
- store_multiple_operation (operands[0], VOIDmode));
- fprintf (asm_out_file, \",(sp)\\n\");
- return \"\";
-}"
- [(set_attr "cc" "clobber")])
-
-(define_insn "return"
- [(return)]
- "can_use_return_insn ()"
- "*
-{
- rtx next = next_active_insn (insn);
-
- if (next
- && GET_CODE (next) == JUMP_INSN
- && GET_CODE (PATTERN (next)) == RETURN)
- return \"\";
- else
- return \"rets\";
-}"
- [(set_attr "cc" "clobber")])
-
-;; Try to combine consecutive updates of the stack pointer (or any
-;; other register for that matter).
-(define_peephole
- [(set (match_operand:SI 0 "register_operand" "=dxay")
- (plus:SI (match_dup 0)
- (match_operand 1 "const_int_operand" "")))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (match_operand 2 "const_int_operand" "")))]
- ""
- "*
-{
- operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
- return \"add %1,%0\";
-}"
- [(set_attr "cc" "clobber")])
+ mn10300_store_multiple_regs (operands[0]));
+ fprintf (asm_out_file, ",(sp)\n");
+ return "";
+}
+ ;; Assume that no more than 8 registers will be pushed.
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 99) (const_int 88)))]
+)
-;;
-;; We had patterns to check eq/ne, but the they don't work because
-;; 0x80000000 + 0x80000000 = 0x0 with a carry out.
-;;
-;; The Z flag and C flag would be set, and we have no way to
-;; check for the Z flag set and C flag clear.
-;;
-;; This will work on the mn10200 because we can check the ZX flag
-;; if the comparison is in HImode.
-(define_peephole
- [(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
- (set (pc) (if_then_else (ge (cc0) (const_int 0))
- (match_operand 1 "" "")
- (pc)))]
- "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
- "add %0,%0\;bcc %1"
- [(set_attr "cc" "clobber")])
-
-(define_peephole
- [(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
- (set (pc) (if_then_else (lt (cc0) (const_int 0))
- (match_operand 1 "" "")
- (pc)))]
- "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
- "add %0,%0\;bcs %1"
- [(set_attr "cc" "clobber")])
-
-(define_peephole
- [(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
- (set (pc) (if_then_else (ge (cc0) (const_int 0))
- (pc)
- (match_operand 1 "" "")))]
- "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
- "add %0,%0\;bcs %1"
- [(set_attr "cc" "clobber")])
-
-(define_peephole
- [(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
- (set (pc) (if_then_else (lt (cc0) (const_int 0))
- (pc)
- (match_operand 1 "" "")))]
- "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
- "add %0,%0\;bcc %1"
- [(set_attr "cc" "clobber")])
-
-(define_expand "int_label"
- [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
- "" "")
-
-(define_expand "GOTaddr2picreg"
- [(match_dup 0)]
- "" "
+(define_expand "load_pic"
+ [(const_int 0)]
+ "flag_pic"
{
- /* It would be nice to be able to have int_label keep track of the
- counter and all, but if we add C code to it, we'll get an insn
- back, and we just want the pattern. */
- operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
if (TARGET_AM33)
- emit_insn (gen_am33_loadPC (operands[0]));
+ emit_insn (gen_am33_load_pic (pic_offset_table_rtx));
+ else if (mn10300_frame_size () == 0)
+ emit_insn (gen_mn10300_load_pic0 (pic_offset_table_rtx));
else
- emit_insn (gen_mn10300_loadPC (operands[0]));
- emit_insn (gen_add_GOT_to_pic_reg (operands[0]));
+ emit_insn (gen_mn10300_load_pic1 (pic_offset_table_rtx));
DONE;
-}
-")
+})
-(define_insn "am33_loadPC"
- [(parallel
- [(set (reg:SI PIC_REG) (pc))
- (use (match_operand 0 "" ""))])]
+(define_insn "am33_load_pic"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(const_int 0)] UNSPEC_GOT))
+ (clobber (reg:CC CC_REG))]
"TARGET_AM33"
- "%0:\;mov pc,a2")
-
-
-(define_insn_and_split "mn10300_loadPC"
- [(parallel
- [(set (reg:SI PIC_REG) (pc))
- (use (match_operand 0 "" ""))])]
- ""
- "#"
- "reload_completed"
- [(match_operand 0 "" "")]
- "
-{
- rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
- int need_stack_space = (get_frame_size () == 0
- && current_function_outgoing_args_size == 0);
-
- if (need_stack_space)
- emit_move_insn (sp_reg, plus_constant (sp_reg, -4));
-
- emit_insn (gen_call_next_insn (operands[0]));
-
- if (need_stack_space)
- emit_insn (gen_pop_pic_reg ());
- else
- emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
-
- DONE;
-}")
-
-(define_insn "call_next_insn"
- [(parallel
- [(set (mem:SI (reg:SI SP_REG)) (pc))
- (use (match_operand 0 "" ""))])]
- "reload_completed"
- "calls %0\;%0:")
-
-(define_expand "add_GOT_to_pic_reg"
- [(set (reg:SI PIC_REG)
- (plus:SI
- (reg:SI PIC_REG)
- (const
- (unspec [(minus:SI
- (match_dup 1)
- (const (minus:SI
- (const (match_operand:SI 0 "" ""))
- (pc))))
- ] UNSPEC_PIC))))]
- ""
- "
{
operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
-}")
+ return ".LPIC%=:\;mov pc,%0\;add %1-(.LPIC%=-.),%0";
+}
+ [(set_attr "timings" "33")]
+)
-(define_expand "symGOT2reg"
- [(match_operand:SI 0 "" "")
- (match_operand:SI 1 "" "")]
+;; Load pic register with push/pop of stack.
+(define_insn "mn10300_load_pic0"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(const_int 0)] UNSPEC_GOT))
+ (clobber (reg:SI MDR_REG))
+ (clobber (reg:CC CC_REG))]
""
- "
{
- rtx insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1]));
-
- MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1;
-
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
- REG_NOTES (insn));
-
- DONE;
-}")
-
-(define_expand "symGOT2reg_i"
- [(set (match_operand:SI 0 "" "")
- (mem:SI (plus:SI (reg:SI PIC_REG)
- (const (unspec [(match_operand:SI 1 "" "")]
- UNSPEC_GOT)))))]
- ""
- "")
+ operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+ return ("add -4,sp\;"
+ "calls .LPIC%=\n"
+ ".LPIC%=:\;"
+ "movm (sp),[%0]\;"
+ "add %1-(.LPIC%=-.),%0");
+}
+ [(set_attr "timings" "88")]
+)
-(define_expand "symGOTOFF2reg"
- [(match_operand:SI 0 "" "") (match_operand:SI 1 "" "")]
+;; Load pic register re-using existing stack space.
+(define_insn "mn10300_load_pic1"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(const_int 0)] UNSPEC_GOT))
+ (clobber (mem:SI (reg:SI SP_REG)))
+ (clobber (reg:SI MDR_REG))
+ (clobber (reg:CC CC_REG))]
""
- "
{
- rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1]));
-
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
- REG_NOTES (insn));
-
- DONE;
-}")
-
-(define_expand "symGOTOFF2reg_i"
- [(set (match_operand:SI 0 "" "")
- (const (unspec [(match_operand:SI 1 "" "")] UNSPEC_GOTOFF)))
- (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI PIC_REG)))]
- ""
- "")
-
-(define_expand "sym2PIC"
- [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PIC)]
- "" "")
-
-(define_expand "sym2PLT"
- [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PLT)]
- "" "")
+ operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+ return ("calls .LPIC%=\n"
+ ".LPIC%=:\;"
+ "mov (sp),%0\;"
+ "add %1-(.LPIC%=-.),%0");
+}
+ [(set_attr "timings" "66")]
+)
+
+;; The mode on operand 3 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "liw"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 2 "liw_operand" "rO")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))
+ (set (match_operand:SI 1 "register_operand" "=r")
+ (unspec:SI [(match_dup 1)
+ (match_operand 3 "liw_operand" "rO")
+ (match_operand:SI 5 "const_int_operand" "")]
+ UNSPEC_LIW))]
+ "TARGET_ALLOW_LIW"
+ "%W4_%W5 %2, %0, %3, %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+;; The mode on operand 1 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "cmp_liw"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "liw_operand" "rO")))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 1 "liw_operand" "rO")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))]
+ "TARGET_ALLOW_LIW"
+ "cmp_%W4 %3, %2, %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+(define_insn "liw_cmp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 1 "liw_operand" "rO")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))
+ (set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "liw_operand" "rO")))]
+ "TARGET_ALLOW_LIW"
+ "%W4_cmp %1, %0, %3, %2"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+;; Note - in theory the doloop patterns could be used here to express
+;; the SETLB and Lcc instructions. In practice this does not work because
+;; the acceptable forms of the doloop patterns do not include UNSPECs
+;; and without them gcc's basic block reordering code can duplicate the
+;; doloop_end pattern, leading to bogus multiple decrements of the loop
+;; counter.
+
+(define_insn "setlb"
+ [(unspec [(const_int 0)] UNSPEC_SETLB)]
+ "TARGET_AM33 && TARGET_ALLOW_SETLB"
+ "setlb"
+)
+
+(define_insn "Lcc"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(reg:CC CC_REG) (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (unspec [(const_int 1)] UNSPEC_SETLB)]
+ "TARGET_AM33 && TARGET_ALLOW_SETLB"
+ "L%b0 # loop back to: %1"
+)
+
+(define_insn "FLcc"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(reg:CC_FLOAT CC_REG) (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (unspec [(const_int 2)] UNSPEC_SETLB)]
+ "TARGET_AM33_2 && TARGET_ALLOW_SETLB"
+ "FL%b0 # loop back to: %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))]
+)