diff gcc/config/cr16/cr16.md @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/config/cr16/cr16.md	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,1084 @@
+;; GCC machine description for CR16.
+;; Copyright (C) 2012-2017 Free Software Foundation, Inc.
+;; Contributed by KPIT Cummins Infosystems Limited.
+
+;; 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 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>. 
+
+;;  Register numbers
+(define_constants
+  [(SP_REGNUM 15); Stack pointer
+   (RA_REGNUM 14); Return address
+  ]
+)
+
+;; Predicates & Constraints
+(include "predicates.md")
+(include "constraints.md")
+
+;; UNSPEC usage
+(define_constants
+  [(UNSPEC_PIC_ADDR             0)
+   (UNSPEC_PIC_LOAD_ADDR        1)
+   (UNSPEC_LIBRARY_OFFSET       2)
+   (UNSPEC_SH_LIB_PUSH_R12      3)
+   (UNSPEC_SH_LIB_POP_R12       4)
+   (UNSPEC_RETURN_ADDR          5)
+  ]
+)
+
+;; Attributes
+(define_attr "length" "" (const_int 2))
+
+(define_asm_attributes
+  [(set_attr "length" "2")]
+)
+
+;;  Mode Macro Definitions
+(define_mode_iterator CR16IM [QI HI SI])
+(define_mode_iterator LONG   [SI SF])
+(define_mode_iterator ALLMTD [QI HI SI SF DI DF])
+(define_mode_iterator DOUBLE [DI DF])
+(define_mode_iterator SHORT  [QI HI])
+(define_mode_attr tIsa       [(QI "b") (HI "w") (SI "d") (SF "d")])
+(define_mode_attr lImmArith  [(QI "4") (HI "4") (SI "6") (SF "6")])
+(define_mode_attr lImmArithD [(QI "4") (HI "4") (SI "6") (SF "6") (DI "12") (DF "12")])
+(define_mode_attr iF         [(QI "i") (HI "i") (SI "i") (SF "F")])
+(define_mode_attr iFD        [(DI "i") (DF "F")])
+(define_mode_attr LL         [(QI "L") (HI "L")])
+(define_mode_attr shImmBits  [(QI "3") (HI "4") (SI "5")])
+
+; In QI mode we push 2 bytes instead of 1 byte.
+(define_mode_attr pushCnstr [(QI "X") (HI "<") (SI "<") (SF "<") (DI "<") (DF "<")])
+
+; tpush will be used to generate the 'number of registers to push' in the 
+; push instruction.
+(define_mode_attr tpush [(QI "1") (HI "1") (SI "2") (SF "2") (DI "4") (DF "4")])
+
+;;  Code Macro Definitions
+(define_code_attr  sIsa    [(sign_extend "")  (zero_extend "u")])
+(define_code_attr  sPat    [(sign_extend "s") (zero_extend "u")])
+(define_code_attr  szPat   [(sign_extend "")  (zero_extend "zero_")])
+(define_code_attr  szIsa   [(sign_extend "x") (zero_extend "z")])
+
+(define_code_iterator sz_xtnd    [ sign_extend       zero_extend])
+(define_code_iterator any_cond   [eq ne gt gtu lt ltu ge geu le leu])
+(define_code_iterator plusminus  [plus minus])
+
+(define_code_attr plusminus_insn [(plus "add") (minus "sub")])
+(define_code_attr plusminus_flag [(plus "PLUS") (minus "MINUS")])
+(define_code_attr comm 		 [(plus "%") (minus "")])
+
+(define_code_iterator any_logic  [and ior xor])
+(define_code_attr logic 	 [(and "and") (ior "or") (xor "xor")])
+(define_code_attr any_logic_insn [(and "and") (ior "ior") (xor "xor")])
+(define_code_attr any_logic_flag [(and "AND") (ior "IOR") (xor "XOR")])
+
+(define_mode_iterator QH 	 [QI HI])
+(define_mode_attr qh 		 [(QI "qi") (HI "hi")])
+(define_mode_attr QHsz 		 [(QI "2,2,2") (HI "2,2,4")])
+(define_mode_attr QHsuffix 	 [(QI "b") (HI "w")])
+
+
+;;  Function Prologue and Epilogue
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  {
+    cr16_expand_prologue ();
+    DONE;
+  }
+)
+
+(define_insn "push_for_prologue"
+  [(set (reg:SI SP_REGNUM)
+	(minus:SI (reg:SI SP_REGNUM)
+		  (match_operand:SI 0 "immediate_operand" "i")))]
+  "reload_completed"
+  {
+    return cr16_prepare_push_pop_string (0);
+  }
+  [(set_attr "length" "4")]
+)
+
+(define_expand "epilogue"
+  [(return)]
+  ""
+  {
+    cr16_expand_epilogue ();
+    DONE;
+  }
+)
+
+(define_insn "pop_and_popret_return"
+  [(set (reg:SI SP_REGNUM)
+	(plus:SI (reg:SI SP_REGNUM)
+		 (match_operand:SI 0 "immediate_operand" "i")))
+   (use (reg:SI RA_REGNUM))
+   (return)]
+  "reload_completed"
+  {
+    return cr16_prepare_push_pop_string (1);
+  }
+  [(set_attr "length" "4")]
+)
+
+(define_insn "popret_RA_return"
+  [(use (reg:SI RA_REGNUM))
+   (return)]
+  "reload_completed"
+  "popret\tra"
+  [(set_attr "length" "2")]
+)
+
+;; Arithmetic Instruction  Patterns
+
+;; Addition-Subtraction "adddi3/subdi3" insns.
+(define_insn "<plusminus_insn>di3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(plusminus:DI (match_operand:DI 1 "register_operand" "<comm>0")
+		      (match_operand:DI 2 "register_operand" "r")))]
+  ""
+  {
+    return cr16_emit_add_sub_di (operands, <plusminus_flag>);
+  })
+
+(define_insn "addsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0")
+		 (match_operand:SI 2 "reg_si_int_operand" "r,M,N,O,i")))]
+  ""
+  "addd\t%2, %0"
+  [(set_attr "length" "2,2,4,4,6")]
+)
+
+;; Addition-Subtraction "addhi3/subhi3" insns.
+(define_insn "<plusminus_insn>hi3"
+  [(set (match_operand:HI 0 "register_operand" "=c,c,c")
+	(plusminus:HI (match_operand:HI 1 "register_operand" "<comm>0,0,0")
+		      (match_operand:HI 2 "reg_hi_int_operand" "c,M,N")))]
+  ""
+  "<plusminus_insn>w\t%2, %0"
+  [(set_attr "length" "2,2,4")]
+)
+
+;; Addition-Subtraction "addqi3/subqi3" insns.
+(define_insn "<plusminus_insn>qi3"
+  [(set (match_operand:QI 0 "register_operand" "=c,c")
+	(plusminus:QI (match_operand:QI 1 "register_operand" "<comm>0,0")
+		      (match_operand:QI 2 "reg_qi_int_operand" "c,M")))]
+  ""
+  "<plusminus_insn>b\t%2, %0"
+  [(set_attr "length" "2,2")]
+)
+
+;;  Subtract Instruction
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+	(minus:SI (match_operand:SI 1 "register_operand" "0,0")
+		  (match_operand:SI 2 "reg_si_int_operand" "r,i")))]
+  ""
+  "subd\t%2, %0"
+  [(set_attr "length" "4,6")]
+)
+
+;;  Multiply and Accumulate Instructions "smachisi3/umachisi3"
+(define_insn "<sPat>maddhisi4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(plus:SI
+	(mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r"))
+		 (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r")))
+	(match_operand:SI 3 "register_operand" "0")))]
+  "TARGET_MAC"
+  "mac<sPat>w\t%1, %2, %0"
+  [(set_attr "length" "2")]
+)
+
+;;  Multiply Instructions
+(define_insn "mulhi3"
+  [(set (match_operand:HI 0 "register_operand" "=c,c,c")
+	(mult:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+		 (match_operand:HI 2 "reg_or_int_operand" "c,M,N")))]
+  ""
+  "mulw\t%2, %0"
+  [(set_attr "length" "2,2,4")]
+)
+
+(define_insn "mulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "=c")
+	(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+		 (sign_extend:HI (match_operand:QI 2 "register_operand" "c"))))]
+  ""
+  "mulsb\t%2, %0"
+  [(set_attr "length" "2")]
+)
+
+;;  Bit Set/Clear Instructions
+(define_expand "insv"
+  [(set (zero_extract (match_operand 0 "memory_operand" "")
+		      (match_operand 1 "immediate_operand" "")
+		      (match_operand 2 "immediate_operand" ""))
+	(match_operand 3 "immediate_operand" ""))]
+  "TARGET_BIT_OPS"
+  {
+    if (INTVAL (operands[1]) != 1)
+      FAIL;
+    if (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 15)
+      FAIL;
+    if (INTVAL (operands[3]) == 1)
+      {
+	if (GET_MODE (operands[0]) == QImode)
+	  {
+	    emit_insn (gen_set_bitqi (operands[0], operands[2]));
+	    DONE;
+	  }
+	else if (GET_MODE (operands[0]) == HImode)
+	  {
+	    emit_insn (gen_set_bithi (operands[0], operands[2]));
+	    DONE;
+	  }
+      }
+    if (INTVAL (operands[3]) == 0)
+      {
+	if (GET_MODE (operands[0]) == QImode)
+	  {
+	    emit_insn (gen_clr_bitqi (operands[0], operands[2]));
+	    DONE;
+	  }
+	else if (GET_MODE (operands[0]) == HImode)
+	  {
+	    emit_insn (gen_clr_bithi (operands[0], operands[2]));
+	    DONE;
+	  }
+      }
+  }
+)
+
+(define_insn "set_bit<mode>"
+  [(set (zero_extract:SHORT (match_operand:SHORT 0 "memory_operand" "+m")
+			    (const_int 1)
+			    (match_operand 1 "immediate_operand" "i"))
+	(const_int 1))]
+  "TARGET_BIT_OPS"
+  "sbit<tIsa>\t%1,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "clr_bit<mode>"
+  [(set (zero_extract:SHORT (match_operand:SHORT 0 "memory_operand" "+m")
+			    (const_int 1)
+			    (match_operand 1 "immediate_operand" "i"))
+	(const_int 0))]
+  "TARGET_BIT_OPS"
+  "cbit<tIsa>\t%1,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "set_bit<mode>_mem"
+  [(set (match_operand:SHORT 0 "bit_operand" "=m")
+	(ior:SHORT (match_dup 0)
+		   (match_operand:SHORT 1 "one_bit_operand" "i"))
+  )]
+  "TARGET_BIT_OPS"
+  "sbit<tIsa>\t$%s1,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "clear_bit<mode>_mem"
+  [(set (match_operand:SHORT 0 "bit_operand" "=m")
+	(and:SHORT (match_dup 0)
+		   (match_operand:SHORT 1 "rev_one_bit_operand" "i"))
+  )]
+  "TARGET_BIT_OPS"
+  "cbit<tIsa>\t$%r1,%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Logical Instructions - and/ior/xor "anddi3/iordi3/xordi3"
+(define_insn "<any_logic_insn>di3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(any_logic:DI (match_operand:DI 1 "register_operand" "%0")
+		      (match_operand:DI 2 "register_operand" "r")))]
+  ""
+  {
+    return cr16_emit_logical_di (operands, <any_logic_flag>);
+  })
+
+; Logical and/ior/xor "andsi3/iorsi3/xorsi3"
+(define_insn "<any_logic_insn>si3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+	(any_logic:SI (match_operand:SI 1 "register_operand" "%0,0,0,0")
+		      (match_operand:SI 2 "reg_si_int_operand" "r,M,N,i")))]
+  ""
+  "<logic>d\t%2, %0"
+  [(set_attr "length" "2,2,4,6")]
+)
+
+; Logical and/ior/xor in HImode "andhi3/iorhi3/xorhi3"
+; Logical and/ior/xor in QImode "andqi3/iorqi3/xorqi3"
+(define_insn "<any_logic_insn><qh>3"
+  [(set (match_operand:QH 0 "register_operand" "=c,c,c")
+	(any_logic:QH (match_operand:QH 1 "register_operand" "%0,0,0")
+		      (match_operand:QH 2 "reg_hi_int_operand" "c,M,N")))]
+  ""
+  "<logic><QHsuffix>\t%2, %0"
+  [(set_attr "length" "<QHsz>")]
+)
+
+;;  Sign and Zero Extend Instructions
+(define_insn "<szPat>extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(sz_xtnd:SI (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "mov<szIsa>w\t%1, %0"
+  [(set_attr "length" "4")]
+)
+
+(define_insn "<szPat>extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+	(sz_xtnd:HI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "mov<szIsa>b\t%1, %0"
+  [(set_attr "length" "4")]
+)
+
+;;  One's Complement
+(define_insn "one_cmpldi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(not:DI (match_operand:DI 1 "register_operand" "0")))]
+  ""
+  {
+    rtx xoperand ;
+    int reg0 = REGNO (operands[0]);
+
+    xoperand = gen_rtx_REG (SImode, reg0 + 2);
+    output_asm_insn ("xord\t$-1, %0", operands);
+    output_asm_insn ("xord\t$-1, %0", &xoperand);
+    return "" ;
+  }
+  [(set_attr "length" "12")]
+)
+
+(define_insn "one_cmpl<mode>2"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r")
+	(not:CR16IM (match_operand:CR16IM 1 "register_operand" "0")))]
+  ""
+  "xor<tIsa>\t$-1, %0"
+  [(set_attr "length" "2")]
+)
+
+;;  Arithmetic Left and Right Shift Instructions
+(define_insn "ashlqi3"
+  [(set (match_operand:QI 0 "register_operand" "=c,c")
+	(ashift:QI (match_operand:QI 1 "register_operand" "0,0")
+		   (match_operand:QI 2 "nonmemory_operand" "c,I")))]
+  ""
+  "ashub\t%2, %0"
+  [(set_attr "length" "2,2")]
+)
+
+(define_insn "ashlhi3"
+  [(set (match_operand:HI 0 "register_operand" "=c,c")
+	(ashift:HI (match_operand:HI 1 "register_operand" "0,0")
+		   (match_operand:QI 2 "nonmemory_operand" "c,J")))]
+  ""
+  "ashuw\t%2, %0"
+  [(set_attr "length" "2,2")]
+)
+
+(define_insn "ashlsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
+		   (match_operand:QI 2 "nonmemory_operand" "r,K")))]
+  ""
+  "ashud\t%2, %0"
+  [(set_attr "length" "2,2")]
+)
+
+(define_expand "ashr<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "")
+	(ashiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "")
+			 (match_operand:QI 2 "nonmemory_operand" "")))]
+  ""
+  {
+    if (GET_CODE (operands[2]) == CONST_INT)
+      {
+	/* If the constant is not in range, try placing it in a reg */
+	if (!UNSIGNED_INT_FITS_N_BITS(INTVAL (operands[2]),<shImmBits>))
+	operands[2] = copy_to_mode_reg(QImode, operands[2]);
+      }
+
+    if (GET_CODE (operands[2]) != CONST_INT)
+      operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
+  }
+)
+
+(define_insn "ashrqi3_imm_insn"
+  [(set (match_operand:QI 0 "register_operand" "=c")
+	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
+		     (match_operand:QI 2 "shift_qi_imm_operand" "i")))]
+  ""
+  "ashub\t$%n2, %0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "ashrhi3_imm_insn"
+  [(set (match_operand:HI 0 "register_operand" "=c")
+	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+		     (match_operand:QI 2 "shift_hi_imm_operand" "i")))]
+  ""
+  "ashuw\t$%n2, %0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "ashrsi3_imm_insn"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+		     (match_operand:QI 2 "shift_si_imm_operand" "i")))]
+  ""
+  "ashud\t$%n2, %0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "ashrqi3_neg_insn"
+  [(set (match_operand:QI 0 "register_operand" "=c")
+	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
+		     (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+  ""
+  "ashub\t%2,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "ashrhi3_neg_insn"
+  [(set (match_operand:HI 0 "register_operand" "=c")
+	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+		     (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+  ""
+  "ashuw\t%2,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "ashrdi3_neg_insn"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+		     (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
+  ""
+  "ashud\t%2,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_expand "lshr<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "")
+	(lshiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "")
+			 (match_operand:QI 2 "reg_or_int_operand" "")))]
+  ""
+  {
+    if (GET_CODE (operands[2]) == CONST_INT)
+      {
+	/* If the constant is not in range, try placing it in a reg */
+	if (!UNSIGNED_INT_FITS_N_BITS(INTVAL (operands[2]),<shImmBits>))
+	operands[2] = copy_to_mode_reg(QImode, operands[2]);
+      }
+
+	if (GET_CODE (operands[2]) != CONST_INT)
+	operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
+   }
+)
+
+(define_insn "lshrqi3_imm_insn"
+  [(set (match_operand:QI 0 "register_operand" "=c")
+	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
+		     (match_operand:QI 2 "shift_qi_operand" "Q")))]
+  ""
+  "lshb\t$%n2, %0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "lshrhi3_imm_insn"
+  [(set (match_operand:HI 0 "register_operand" "=c")
+	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+		     (match_operand:QI 2 "shift_hi_operand" "R")))]
+  ""
+  "lshw\t$%n2, %0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "lshrsi3_imm_insn"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
+		     (match_operand:QI 2 "shift_si_operand" "S")))]
+  ""
+  "lshd\t$%n2, %0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "lshrqi3_neg_insn"
+  [(set (match_operand:QI 0 "register_operand" "=c")
+	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
+		     (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+  ""
+  "lshb\t%2,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "lshrhi3_neg_insn"
+  [(set (match_operand:HI 0 "register_operand" "=c")
+	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+		     (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+  ""
+  "lshw\t%2,%0"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "lshrsi3_neg_insn"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
+		     (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
+  ""
+  "lshd\t%2,%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Move Instructions
+
+;; Move any non-immediate operand 0 to a general operand 1.
+;; This applies only before starting the reload process
+;; Operand 0 is not a register operand of type mode MODE
+;; If Operand 0 is a push operand of type mode MODE
+;; then, if Operand 1 is a non-SP register
+;; then, Operand 1 = copy_to_mode_reg (<MODE>mode, Operand 1)
+;; endif
+;; else
+;; if Operand 1 is either register or 4-bit immediate constant
+;; then, Operand 1 = copy_to_mode_reg (<MODE>mode, Operand 1)
+;; endif
+;; endif
+;;
+;; What does copy_to_mode_reg (mode, rtx val) do?
+;; Copy the value into new temp reg and return the reg where the
+;; mode of the new reg is always mode MODE when value is constant
+;;
+;; Why should copy_to_mode_reg be called?
+;; All sorts of move are nor supported by CR16. Therefore, 
+;; when unsupported move is encountered, the additional instructions 
+;; will be introduced for the purpose.
+;;
+;; A new move insn is inserted for Op 1 when one of the following
+;; conditions is met.
+;; Case 1:  Op 0 is push_operand
+;;          Op 1 is SP register
+;;
+;; Case 2:  Op 0 is not push_operand
+;;          Op 1 is neither register nor unsigned 4-bit immediate
+
+(define_expand "mov<mode>"
+  [(set (match_operand:ALLMTD 0 "nonimmediate_operand" "")
+	(match_operand:ALLMTD 1 "general_operand" ""))]
+  ""
+  {
+    if (!(reload_in_progress || reload_completed))
+      {
+	/* Only if Op0 is a register operand.  */
+	if (!register_operand (operands[0], <MODE>mode))
+	  {
+	    if (push_operand (operands[0], <MODE>mode)) 
+	      {
+		/* Use copy_to_mode_reg only if the register needs 
+		to be pushed is SP as CR16 does not support pushing SP.  */
+		if (!nosp_reg_operand (operands[1], <MODE>mode))
+		  operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]);
+	      }
+	    else
+	      {
+		/* Use copy_to_mode_reg if op1 is not register operand
+		   subject to conditions inside.  */
+		if (!register_operand (operands[1], <MODE>mode))
+		  {
+		    /* CR16 does not support moving immediate to SI or SF 
+		       type memory.  */
+		    if (<MODE>mode == SImode || <MODE>mode == SFmode ||
+			<MODE>mode == DImode || <MODE>mode == DFmode)
+		      operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]);
+		    else
+		      /* moving imm4 is supported by CR16 instruction.  */
+		      if (!u4bits_operand (operands[1], <MODE>mode))
+			operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]);
+		  }
+	       }
+	  }
+
+	  /* If operand-1 is a symbol, convert it into a BRO or GOT Format.  */
+	  if (flag_pic && ! legitimate_pic_operand_p (operands[1]))
+	    {
+	      operands[1] = legitimize_pic_address (operands[1], <MODE>mode, 0);
+	    }
+      }
+  }
+)
+
+; ALLMT     : QI,HI,SI,SF
+; pushCnstr : Push constraints 
+;                QI : X
+;             HI,SI,SF,DI,DF : <
+; b         : All non-sp registers
+; tpush     : Push count
+;                QI,HI : 1
+;                SI,SF : 2
+;                DI,DF : 4
+(define_insn "push<mode>_internal"
+  [(set (match_operand:ALLMTD 0 "push_operand" "=<pushCnstr>")
+	(match_operand:ALLMTD 1 "nosp_reg_operand" "b"))]
+  ""
+  "push\t$<tpush>,%p1"
+  [(set_attr "length" "2")]
+)
+
+; (DI, DF) move
+(define_insn "*mov<mode>_double"
+  [(set (match_operand:DOUBLE 0 "nonimmediate_operand" "=r, r, r, m")
+	(match_operand:DOUBLE 1 "general_operand" "r, <iFD>, m, r"))]
+  "register_operand (operands[0], DImode) 
+   || register_operand (operands[0], DFmode)
+   || register_operand (operands[1], DImode)
+   || register_operand (operands[1], DFmode)"
+  {
+    if (0 == which_alternative) {
+      rtx xoperands[2] ;
+      int reg0 = REGNO (operands[0]);
+      int reg1 = REGNO (operands[1]);
+
+      xoperands[0] = gen_rtx_REG (SImode, reg0 + 2);
+      xoperands[1] = gen_rtx_REG (SImode, reg1 + 2);
+      if ((reg1 + 2) != reg0)
+	{
+	  output_asm_insn ("movd\t%1, %0", operands);
+	  output_asm_insn ("movd\t%1, %0", xoperands);
+	}
+      else
+	{
+	  output_asm_insn ("movd\t%1, %0", xoperands);
+	  output_asm_insn ("movd\t%1, %0", operands);
+	}}
+
+    else if (1 == which_alternative) {
+      rtx lo_operands[2] ;
+      rtx hi_operands[2] ;
+
+      lo_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
+      hi_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
+      lo_operands[1] = simplify_gen_subreg (SImode, operands[1],
+		       VOIDmode == GET_MODE (operands[1])
+		       ? DImode  : GET_MODE (operands[1]), 0);
+      hi_operands[1] = simplify_gen_subreg (SImode, operands[1],
+		       VOIDmode == GET_MODE (operands[1])
+		       ? DImode  : GET_MODE (operands[1]), 4);
+      output_asm_insn ("movd\t%1, %0", lo_operands);
+      output_asm_insn ("movd\t%1, %0", hi_operands);}
+
+    else if (2 == which_alternative) {
+      rtx xoperands[2] ;
+      int reg0 = REGNO (operands[0]), reg1 = -2 ;
+      rtx addr ;
+
+	if (MEM_P (operands[1]))
+	  addr = XEXP (operands[1], 0);
+	else
+	  addr = NULL_RTX ;
+	switch (GET_CODE (addr))
+	  {
+	    case REG:
+	    case SUBREG:
+	      reg1 = REGNO (addr);
+	      break ;
+	    case PLUS:
+	      switch (GET_CODE (XEXP (addr, 0))) {
+		case REG:
+		case SUBREG:
+		  reg1 = REGNO (XEXP (addr, 0));
+		  break ;
+		case PLUS:
+		  reg1 = REGNO (XEXP (XEXP (addr, 0), 0));
+		  break ;
+		default:
+		  inform (DECL_SOURCE_LOCATION (cfun->decl), "unexpected expression; addr:");
+		  debug_rtx (addr);
+		  inform (DECL_SOURCE_LOCATION (cfun->decl), "operands[1]:");
+		  debug_rtx (operands[1]);
+		  inform (DECL_SOURCE_LOCATION (cfun->decl), "generated code might now work\n");
+		  break ;}
+	      break ;
+	    default:
+	      break ;
+	  }
+
+	xoperands[0] = gen_rtx_REG (SImode, reg0 + 2);
+	xoperands[1] = offset_address (operands[1], GEN_INT (4), 2);
+	gcc_assert ((reg0 + 1) != reg1);
+	if (reg0 != reg1  &&  (reg1 + 1) != reg0)
+	  {
+	    output_asm_insn ("loadd\t%1, %0", operands);
+	    output_asm_insn ("loadd\t%1, %0", xoperands);
+	  }
+	else
+	  {
+	    output_asm_insn ("loadd\t%1, %0", xoperands);
+	    output_asm_insn ("loadd\t%1, %0", operands);
+	  }}
+    else
+      {
+	rtx xoperands[2] ;
+	xoperands[0] = offset_address (operands[0], GEN_INT (4), 2);
+	xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
+	output_asm_insn ("stord\t%1, %0", operands);
+   	output_asm_insn ("stord\t%1, %0", xoperands);
+      }
+    return "" ;
+  }
+  [(set_attr "length" "4, <lImmArithD>, <lImmArithD>, <lImmArithD>")]
+)
+
+; All long (SI, SF) register move, load and store operations
+; The print_operand will take care of printing the register pair 
+; when mode is SI/SF and register is in SHORT_REGS
+(define_insn "*mov<mode>_long"
+  [(set (match_operand:LONG 0 "nonimmediate_operand" "=r, r, r, m")
+	(match_operand:LONG 1 "general_operand" "r, <iF>, m, r"))]
+  "register_operand (operands[0], <MODE>mode)
+   || register_operand (operands[1], <MODE>mode)"
+  "@
+  mov<tIsa>\t%1, %0
+  mov<tIsa>\t%1, %0
+  load<tIsa>\t%1, %0
+  stor<tIsa>\t%1, %0"
+  [(set_attr "length" "2,<lImmArith>,<lImmArith>,<lImmArith>")]
+)
+
+;; All short (QI, HI) register move, load and store operations
+(define_insn "*mov<mode>_short"
+  [(set (match_operand:SHORT 0 "nonimmediate_operand" "=r, r, r, m, m")
+	(match_operand:SHORT 1 "general_operand" "r, <iF>, m, r, <LL>"))]
+  "(register_operand (operands[0], <MODE>mode))
+    || (store_operand (operands[0], <MODE>mode)
+	&& (register_operand (operands[1], <MODE>mode)
+	    || u4bits_operand (operands[1], <MODE>mode)))"
+  "@
+  mov<tIsa>\t%1, %0
+  mov<tIsa>\t%1, %0
+  load<tIsa>\t%1, %0
+  stor<tIsa>\t%1, %0
+  stor<tIsa>\t%1, %0"
+  [(set_attr "length" "2,<lImmArith>,<lImmArith>,<lImmArith>,<lImmArith>")]
+)
+
+;;  Compare Instructions
+; Instruction generated compares the operands in reverse order
+; Therefore, while printing the asm, the reverse of the
+; compare condition shall be printed.
+(define_insn "cbranch<mode>4"
+  [(set (pc)
+	(if_then_else (match_operator 0 "ordered_comparison_operator"
+		      [(match_operand:CR16IM 1 "register_operand" "r,r")
+		       (match_operand:CR16IM 2 "nonmemory_operand" "r,n")])
+		       (label_ref (match_operand 3 "" ""))
+                      (pc)))
+   (clobber (cc0))]
+  ""
+  "cmp<tIsa>\t%2, %1\;b%d0\t%l3"
+  [(set_attr "length" "6,6")]
+)
+
+(define_expand "cmp<mode>"
+  [(parallel [(set (cc0)
+    (compare (match_operand:CR16IM 0 "register_operand" "")
+	     (match_operand:CR16IM 1 "nonmemory_operand" "")))
+    (clobber (match_scratch:HI 2 "=r"))] ) ]
+  ""
+  "")
+
+;;  Scond Instructions
+(define_expand "cstore<mode>4"
+  [(set (cc0)
+	(compare (match_operand:CR16IM 2 "register_operand" "")
+		 (match_operand:CR16IM 3 "nonmemory_operand" "")))
+   (set (match_operand:HI 0 "register_operand")
+	(match_operator:HI 1 "ordered_comparison_operator"
+	[(cc0) (const_int 0)]))]
+  ""
+  ""
+)
+
+(define_insn "*cmp<mode>_insn"
+  [(set (cc0)
+	(compare (match_operand:CR16IM 0 "register_operand" "r,r")
+		 (match_operand:CR16IM 1 "nonmemory_operand" "r,n")))]
+  ""
+  "cmp<tIsa>\t%1, %0"
+  [(set_attr "length" "2,4")]
+)
+
+(define_insn "sCOND_internal"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+	(match_operator:HI 1 "ordered_comparison_operator"
+	[(cc0) (const_int 0)]))]
+  ""
+  "s%d1\t%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Jumps and Branches
+(define_insn "indirect_jump_return"
+  [(set (pc)
+	  (reg:SI RA_REGNUM))
+   (return)]
+  "reload_completed"
+  "jump\t (ra)"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "jump_return"
+  [(unspec:SI [(const_int 0)] UNSPEC_RETURN_ADDR)
+   (return)]
+  "reload_completed"
+  "jump\t(ra)"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "indirect_jump"
+  [(set (pc)
+	(match_operand:SI 0 "reg_or_sym_operand" "r,i"))]
+  ""
+  "@
+  jump\t%0
+  br\t%a0"
+  [(set_attr "length" "2,6")]
+)
+
+(define_insn "interrupt_return"
+  [(unspec_volatile [(const_int 0)] 0)
+   (return)]
+  ""
+  {
+    return cr16_prepare_push_pop_string (1);
+  }
+  [(set_attr "length" "14")]
+)
+
+(define_insn "jump_to_imm"
+  [(set (pc)
+	(match_operand 0 "jump_imm_operand" "i"))]
+  ""
+  "br\t%c0"
+  [(set_attr "length" "6")]
+)
+
+(define_insn "jump"
+  [(set (pc)
+	(label_ref (match_operand 0 "" "")))]
+  ""
+  "br\t%l0"
+  [(set_attr "length" "6")]
+)
+
+;;  Table Jump
+(define_insn "tablejump"
+  [(set (pc)
+	(match_operand:SI 0 "register_operand" "r"))
+   (use (label_ref:SI (match_operand 1 "" "")))]
+  "!flag_pic"
+  "jump\t%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Call Instructions
+(define_expand "call"
+  [(call (match_operand:QI 0 "memory_operand" "")
+	 (match_operand 1 "" ""))]
+  ""
+  {
+    if (flag_pic && ! legitimate_pic_operand_p (operands[0]))
+      {
+	operands[0] = gen_const_mem (QImode,
+	legitimize_pic_address (XEXP (operands[0], 0), Pmode, 0));
+	emit_call_insn (gen_cr16_call (operands[0], operands[1]));
+      }
+    else
+      emit_call_insn (gen_cr16_call (operands[0], operands[1]));
+      DONE;
+  }
+)
+
+(define_expand "cr16_call"
+  [(parallel
+    [(call (match_operand:QI 0 "memory_operand" "")
+	   (match_operand 1 "" ""))
+   (clobber (reg:SI RA_REGNUM))])]
+  ""
+  ""
+)
+
+(define_insn "cr16_call_insn_branch_pic"
+  [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i"))
+	 (match_operand 1 "" ""))
+   (clobber (match_operand:SI 2 "register_operand" "+r"))]
+  "flag_pic == FAR_PIC"
+  {
+    if (GET_CODE (operands[0]) != CONST_INT)
+      return "loadd\t%g0, %2 \n\tjal %2";
+    else
+      return "jal %2";
+  }
+  [(set_attr "length" "8")]
+)
+
+(define_insn "cr16_call_insn_branch"
+  [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i"))
+	 (match_operand 1 "" ""))
+   (clobber (match_operand:SI 2 "register_operand" "+r"))]
+  "flag_pic == 0 || flag_pic == NEAR_PIC"
+  {
+    /* Print the immediate address for bal 
+       'b' is used instead of 'a' to avoid compiler calling
+       the GO_IF_LEGITIMATE_ADDRESS which cannot
+       perform checks on const_int code addresses as it
+       assumes all const_int are data addresses.
+    */
+    if (GET_CODE (operands[0]) != CONST_INT)
+      return "bal (ra), %a0";
+    else
+      operands[4] = GEN_INT ((INTVAL (operands[0]))>>1);
+      return "movd\t%g4,\t(r1,r0)\n\tjal\t(r1,r0)";	
+  }
+  [(set_attr "length" "6")]
+)
+
+(define_insn "cr16_call_insn_jump"
+  [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
+	 (match_operand 1 "" ""))
+   (clobber (match_operand:SI 2 "register_operand" "+r"))]
+  ""
+  "jal\t%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Call Value Instructions
+
+(define_expand "call_value"
+  [(set (match_operand 0 "general_operand" "")
+	(call (match_operand:QI 1 "memory_operand" "")
+	      (match_operand 2 "" "")))]
+  ""
+  {
+    if (flag_pic && !legitimate_pic_operand_p (operands[1]))
+      {
+	operands[1] = gen_const_mem (QImode,
+	legitimize_pic_address (XEXP (operands[1], 0), Pmode, 0));
+	emit_call_insn (gen_cr16_call_value (operands[0], operands[1], operands[2]));
+      }
+    else
+	emit_call_insn (gen_cr16_call_value (operands[0], operands[1], operands[2]));
+    DONE;
+  }
+)
+
+(define_expand "cr16_call_value"
+  [(parallel
+    [(set (match_operand 0 "general_operand" "")
+	  (call (match_operand 1 "memory_operand" "")
+		(match_operand 2 "" "")))
+     (clobber (reg:SI RA_REGNUM))])]
+  ""
+  ""
+)
+
+(define_insn "cr16_call_value_insn_branch_pic"
+  [(set (match_operand 0 "" "=g")
+	(call (mem:QI (match_operand:SI 1 "call_imm_operand" "i"))
+	      (match_operand 2 "" "")))
+   (clobber (match_operand:SI 3 "register_operand" "+r"))]
+  "flag_pic == FAR_PIC"
+  {
+    if (GET_CODE (operands[1]) != CONST_INT)
+      return "loadd\t%g1, %3 \n\tjal %3";
+    else
+      return "jal %3";
+  }
+  [(set_attr "length" "8")]
+)
+
+(define_insn "cr16_call_value_insn_branch"
+  [(set (match_operand 0 "" "=g")
+	(call (mem:QI (match_operand:SI 1 "call_imm_operand" "i"))
+	      (match_operand 2 "" "")))
+   (clobber (match_operand:SI 3 "register_operand" "+r"))]
+  "flag_pic == 0 || flag_pic == NEAR_PIC"
+  {
+    /* Print the immediate address for bal 
+       'b' is used instead of 'a' to avoid compiler calling
+       the GO_IF_LEGITIMATE_ADDRESS which cannot
+       perform checks on const_int code addresses as it
+       assumes all const_int are data addresses.
+    */
+    if (GET_CODE (operands[1]) != CONST_INT) 
+      return "bal (ra), %a1";
+    else
+      {
+	operands[4] = GEN_INT ((INTVAL (operands[1]))>>1);
+        return "movd\t%g4,\t(r1,r0)\n\tjal\t(r1,r0)";	
+      }
+  }
+  [(set_attr "length" "6")]
+)
+
+
+(define_insn "cr16_call_value_insn_jump"
+  [(set (match_operand 0 "" "=g")
+	(call (mem:QI (match_operand:SI 1 "register_operand" "r"))
+	      (match_operand 2 "" "")))
+   (clobber (match_operand:SI 3 "register_operand" "+r"))]
+  ""
+  "jal\t%1"
+  [(set_attr "length" "2")]
+)
+
+
+;;  Nop
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop\t"
+)
+
+;; PIC
+/* When generating pic, we need to load the symbol offset into a register.
+   So that the optimizer does not confuse this with a normal symbol load
+   we use an unspec.  The offset will be loaded from a constant pool entry,
+   since that is the only type of relocation we can use.  */
+                                                                                                                            
+(define_insn "unspec_bro_addr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand 1 "" "")] UNSPEC_PIC_ADDR))]
+  ""
+  "movd \t%f1, %0"
+  [(set_attr "length" "4")]
+)
+
+(define_insn "unspec_got_addr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand 1 "" "")] UNSPEC_PIC_LOAD_ADDR))]
+  ""
+  "loadd \t%g1, %0"
+  [(set_attr "length" "6")]
+)