;; GCC machine description for CR16. ;; Copyright (C) 2012-2015 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” “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” “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” “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 “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” “macw\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” [(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\t%1,%0” [(set_attr “length” “2”)] )

(define_insn “clr_bit” [(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\t%1,%0” [(set_attr “length” “2”)] )

(define_insn “set_bit_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\t$%s1,%0” [(set_attr “length” “2”)] )

(define_insn “clear_bit_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\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”)))] "" “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>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”)))] "" “\t%2, %0” [(set_attr “length” “”)] )

;; Sign and Zero Extend Instructions (define_insn “extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r”) (sz_xtnd:SI (match_operand:HI 1 “register_operand” “r”)))] "" “movw\t%1, %0” [(set_attr “length” “4”)] )

(define_insn “extendqihi2” [(set (match_operand:HI 0 “register_operand” “=r”) (sz_xtnd:HI (match_operand:QI 1 “register_operand” “r”)))] "" “movb\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_cmpl2” [(set (match_operand:CR16IM 0 “register_operand” “=r”) (not:CR16IM (match_operand:CR16IM 1 “register_operand” “0”)))] "" “xor\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 “ashr3” [(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]),)) 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 “lshr3” [(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]),)) 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, Operand 1) ;; endif ;; else ;; if Operand 1 is either register or 4-bit immediate constant ;; then, Operand 1 = copy_to_mode_reg (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” [(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)) { if (push_operand (operands[0], 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)) operands[1] = copy_to_mode_reg (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)) { / CR16 does not support moving immediate to SI or SF type memory. / if (mode == SImode || mode == SFmode || mode == DImode || mode == DFmode) operands[1] = copy_to_mode_reg (mode, operands[1]); else / moving imm4 is supported by CR16 instruction. */ if (!u4bits_operand (operands[1], mode)) operands[1] = copy_to_mode_reg (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_internal” [(set (match_operand:ALLMTD 0 “push_operand” “=”) (match_operand:ALLMTD 1 “nosp_reg_operand” “b”))] "" “push\t$,%p1” [(set_attr “length” “2”)] )

; (DI, DF) move (define_insn “*mov_double” [(set (match_operand:DOUBLE 0 “nonimmediate_operand” “=r, r, r, m”) (match_operand:DOUBLE 1 “general_operand” “r, , 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, , , ”)] )

; 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_long” [(set (match_operand:LONG 0 “nonimmediate_operand” “=r, r, r, m”) (match_operand:LONG 1 “general_operand” “r, , m, r”))] “register_operand (operands[0], mode) || register_operand (operands[1], mode)” “@ mov\t%1, %0 mov\t%1, %0 load\t%1, %0 stor\t%1, %0” [(set_attr “length” “2,,,”)] )

;; All short (QI, HI) register move, load and store operations (define_insn “*mov_short” [(set (match_operand:SHORT 0 “nonimmediate_operand” “=r, r, r, m, m”) (match_operand:SHORT 1 “general_operand” “r, , m, r, ”))] “(register_operand (operands[0], mode)) || (store_operand (operands[0], mode) && (register_operand (operands[1], mode) || u4bits_operand (operands[1], mode)))” “@ mov\t%1, %0 mov\t%1, %0 load\t%1, %0 stor\t%1, %0 stor\t%1, %0” [(set_attr “length” “2,,,,”)] )

;; 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 “cbranch4” [(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\t%2, %1;b%d0\t%l3” [(set_attr “length” “6,6”)] )

(define_expand “cmp” [(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 “cstore4” [(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_insn” [(set (cc0) (compare (match_operand:CR16IM 0 “register_operand” “r,r”) (match_operand:CR16IM 1 “nonmemory_operand” “r,n”)))] "" “cmp\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”)] )