diff options
Diffstat (limited to 'gcc/config/cr16/cr16.md')
-rw-r--r-- | gcc/config/cr16/cr16.md | 1084 |
1 files changed, 1084 insertions, 0 deletions
diff --git a/gcc/config/cr16/cr16.md b/gcc/config/cr16/cr16.md new file mode 100644 index 00000000000..5e4530c32ce --- /dev/null +++ b/gcc/config/cr16/cr16.md @@ -0,0 +1,1084 @@ +;; GCC machine description for CR16. +;; Copyright (C) 2012 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 Instuction 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")] +) |