;; Machine Description for Altera Nios II. ;; Copyright (C) 2012-2014 Free Software Foundation, Inc. ;; Contributed by Jonah Graham (jgraham@altera.com) and ;; Will Reece (wreece@altera.com). ;; Contributed by Mentor Graphics, Inc. ;; ;; 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 [ (FIRST_RETVAL_REGNO 2) ; Return value registers (LAST_RETVAL_REGNO 3) ; (FIRST_ARG_REGNO 4) ; Argument registers (LAST_ARG_REGNO 7) ;

(TP_REGNO 23) ; Thread pointer register (GP_REGNO 26) ; Global pointer register (FP_REGNO 28) ; Frame pointer register (EA_REGNO 29) ; Exception return address register (RA_REGNO 31) ; Return address register (LAST_GP_REG 31) ; Last general purpose register

;; Target register definitions (STATIC_CHAIN_REGNUM 12) (STACK_POINTER_REGNUM 27) (HARD_FRAME_POINTER_REGNUM 28) (PC_REGNUM 37) (FRAME_POINTER_REGNUM 38) (ARG_POINTER_REGNUM 39) (FIRST_PSEUDO_REGISTER 40) ] )

;; Enumeration of UNSPECs

(define_c_enum “unspecv” [ UNSPECV_BLOCKAGE UNSPECV_WRCTL UNSPECV_RDCTL UNSPECV_FWRX UNSPECV_FWRY UNSPECV_FRDXLO UNSPECV_FRDXHI UNSPECV_FRDY UNSPECV_CUSTOM_NXX UNSPECV_CUSTOM_XNXX UNSPECV_LDXIO UNSPECV_STXIO ])

(define_c_enum “unspec” [ UNSPEC_FCOS UNSPEC_FSIN UNSPEC_FTAN UNSPEC_FATAN UNSPEC_FEXP UNSPEC_FLOG UNSPEC_LOAD_GOT_REGISTER UNSPEC_PIC_SYM UNSPEC_PIC_CALL_SYM UNSPEC_PIC_GOTOFF_SYM UNSPEC_LOAD_TLS_IE UNSPEC_ADD_TLS_LE UNSPEC_ADD_TLS_GD UNSPEC_ADD_TLS_LDM UNSPEC_ADD_TLS_LDO UNSPEC_EH_RETURN UNSPEC_SYNC ])

;; Instruction scheduler

; No schedule info is currently available, using an assumption that no ; instruction can use the results of the previous instruction without ; incuring a stall.

; length of an instruction (in bytes) (define_attr “length” "" (const_int 4)) (define_attr “type” “unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom” (const_string “complex”))

(define_asm_attributes [(set_attr “length” “4”) (set_attr “type” “complex”)])

(define_automaton “nios2”) (automata_option “v”) ;(automata_option “no-minimization”) (automata_option “ndfa”)

; The nios2 pipeline is fairly straightforward for the fast model. ; Every alu operation is pipelined so that an instruction can ; be issued every cycle. However, there are still potential ; stalls which this description tries to deal with.

(define_cpu_unit “cpu” “nios2”)

(define_insn_reservation “complex” 1 (eq_attr “type” “complex”) “cpu”)

(define_insn_reservation “control” 1 (eq_attr “type” “control”) “cpu”)

(define_insn_reservation “alu” 1 (eq_attr “type” “alu”) “cpu”)

(define_insn_reservation “cond_alu” 1 (eq_attr “type” “cond_alu”) “cpu”)

(define_insn_reservation “st” 1 (eq_attr “type” “st”) “cpu”)

(define_insn_reservation “custom” 1 (eq_attr “type” “custom”) “cpu”)

; shifts, muls and lds have three cycle latency (define_insn_reservation “ld” 3 (eq_attr “type” “ld”) “cpu”)

(define_insn_reservation “shift” 3 (eq_attr “type” “shift”) “cpu”)

(define_insn_reservation “mul” 3 (eq_attr “type” “mul”) “cpu”)

(define_insn_reservation “div” 1 (eq_attr “type” “div”) “cpu”)

(include “predicates.md”) (include “constraints.md”)

;; Move instructions

(define_mode_iterator M [QI HI SI])

(define_expand “mov” [(set (match_operand:M 0 “nonimmediate_operand” "") (match_operand:M 1 “general_operand” ""))] "" { if (nios2_emit_move_sequence (operands, mode)) DONE; })

(define_insn “movqi_internal” [(set (match_operand:QI 0 “nonimmediate_operand” “=m, r,r, r”) (match_operand:QI 1 “general_operand” “rM,m,rM,I”))] “(register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode))” “@ stb%o0\t%z1, %0 ldbu%o1\t%0, %1 mov\t%0, %z1 movi\t%0, %1” [(set_attr “type” “st,ld,alu,alu”)])

(define_insn “movhi_internal” [(set (match_operand:HI 0 “nonimmediate_operand” “=m, r,r, r”) (match_operand:HI 1 “general_operand” “rM,m,rM,I”))] “(register_operand (operands[0], HImode) || reg_or_0_operand (operands[1], HImode))” “@ sth%o0\t%z1, %0 ldhu%o1\t%0, %1 mov\t%0, %z1 movi\t%0, %1” [(set_attr “type” “st,ld,alu,alu”)])

(define_insn “movsi_internal” [(set (match_operand:SI 0 “nonimmediate_operand” “=m, r,r, r,r,r,r,r”) (match_operand:SI 1 “general_operand” “rM,m,rM,I,J,K,S,i”))] “(register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))” “@ stw%o0\t%z1, %0 ldw%o1\t%0, %1 mov\t%0, %z1 movi\t%0, %1 movui\t%0, %1 movhi\t%0, %H1 addi\t%0, gp, %%gprel(%1) movhi\t%0, %H1;addi\t%0, %0, %L1” [(set_attr “type” “st,ld,alu,alu,alu,alu,alu,alu”) (set_attr “length” “4,4,4,4,4,4,4,8”)])

(define_mode_iterator BH [QI HI]) (define_mode_iterator BHW [QI HI SI]) (define_mode_attr bh [(QI “b”) (HI “h”)]) (define_mode_attr bhw [(QI “b”) (HI “h”) (SI “w”)]) (define_mode_attr bhw_uns [(QI “bu”) (HI “hu”) (SI “w”)])

(define_insn “ld<bhw_uns>io” [(set (match_operand:BHW 0 “register_operand” “=r”) (unspec_volatile:BHW [(match_operand:BHW 1 “memory_operand” “m”)] UNSPECV_LDXIO))] "" “ld<bhw_uns>io\t%0, %1” [(set_attr “type” “ld”)])

(define_expand “ldio” [(set (match_operand:BH 0 “register_operand” “=r”) (match_operand:BH 1 “memory_operand” “m”))] "" { rtx tmp = gen_reg_rtx (SImode); emit_insn (gen_ldio_signed (tmp, operands[1])); emit_insn (gen_mov (operands[0], gen_lowpart (mode, tmp))); DONE; })

(define_insn “ldio_signed” [(set (match_operand:SI 0 “register_operand” “=r”) (sign_extend:SI (unspec_volatile:BH [(match_operand:BH 1 “memory_operand” “m”)] UNSPECV_LDXIO)))] "" “ldio\t%0, %1” [(set_attr “type” “ld”)])

(define_insn “stio” [(set (match_operand:BHW 0 “memory_operand” “=m”) (unspec_volatile:BHW [(match_operand:BHW 1 “reg_or_0_operand” “rM”)] UNSPECV_STXIO))] "" “stio\t%z1, %0” [(set_attr “type” “st”)])

;; QI to [HI, SI] extension patterns are collected together (define_mode_iterator QX [HI SI])

;; Zero extension patterns (define_insn “zero_extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r,r”) (zero_extend:SI (match_operand:HI 1 “nonimmediate_operand” “r,m”)))] "" “@ andi\t%0, %1, 0xffff ldhu%o1\t%0, %1” [(set_attr “type” “alu,ld”)])

(define_insn “zero_extendqi2” [(set (match_operand:QX 0 “register_operand” “=r,r”) (zero_extend:QX (match_operand:QI 1 “nonimmediate_operand” “r,m”)))] "" “@ andi\t%0, %1, 0xff ldbu%o1\t%0, %1” [(set_attr “type” “alu,ld”)])

;; Sign extension patterns

(define_insn “extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r,r”) (sign_extend:SI (match_operand:HI 1 “nonimmediate_operand” “r,m”)))] "" "@

ldh%o1\t%0, %1" [(set_attr “type” “alu,ld”)])

(define_insn “extendqi2” [(set (match_operand:QX 0 “register_operand” “=r,r”) (sign_extend:QX (match_operand:QI 1 “nonimmediate_operand” “r,m”)))] "" "@

ldb%o1\t%0, %1" [(set_attr “type” “alu,ld”)])

;; Split patterns for register alternative cases. (define_split [(set (match_operand:SI 0 “register_operand” "") (sign_extend:SI (match_operand:HI 1 “register_operand” "")))] “reload_completed” [(set (match_dup 0) (and:SI (match_dup 1) (const_int 65535))) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 32768))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -32768)))] “operands[1] = gen_lowpart (SImode, operands[1]);”)

(define_split [(set (match_operand:QX 0 “register_operand” "") (sign_extend:QX (match_operand:QI 1 “register_operand” "")))] “reload_completed” [(set (match_dup 0) (and:SI (match_dup 1) (const_int 255))) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 128))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -128)))] “operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]);”)

;; Arithmetic Operations

(define_insn “addsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “add_regimm_operand” “rIT”)))] "" “add%i2\t%0, %1, %z2” [(set_attr “type” “alu”)])

(define_insn “subsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (minus:SI (match_operand:SI 1 “reg_or_0_operand” “rM”) (match_operand:SI 2 “register_operand” “r”)))] "" “sub\t%0, %z1, %2” [(set_attr “type” “alu”)])

(define_insn “mulsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (mult:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “arith_operand” “rI”)))] “TARGET_HAS_MUL” “mul%i2\t%0, %1, %z2” [(set_attr “type” “mul”)])

(define_expand “divsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (div:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)))] "" { if (!TARGET_HAS_DIV) { if (TARGET_FAST_SW_DIV) { nios2_emit_expensive_div (operands, SImode); DONE; } else FAIL; } })

(define_insn “divsi3_insn” [(set (match_operand:SI 0 “register_operand” “=r”) (div:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)))] “TARGET_HAS_DIV” “div\t%0, %1, %2” [(set_attr “type” “div”)])

(define_insn “udivsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (udiv:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)))] “TARGET_HAS_DIV” “divu\t%0, %1, %2” [(set_attr “type” “div”)])

(define_code_iterator EXTEND [sign_extend zero_extend]) (define_code_attr us [(sign_extend “s”) (zero_extend “u”)]) (define_code_attr mul [(sign_extend “mul”) (zero_extend “umul”)])

(define_insn “mulsi3_highpart” [(set (match_operand:SI 0 “register_operand” “=r”) (truncate:SI (lshiftrt:DI (mult:DI (EXTEND:DI (match_operand:SI 1 “register_operand” “r”)) (EXTEND:DI (match_operand:SI 2 “register_operand” “r”))) (const_int 32))))] “TARGET_HAS_MULX” “mulx\t%0, %1, %2” [(set_attr “type” “mul”)])

(define_expand “sidi3” [(set (match_operand:DI 0 “register_operand” "") (mult:DI (EXTEND:DI (match_operand:SI 1 “register_operand” "")) (EXTEND:DI (match_operand:SI 2 “register_operand” ""))))] “TARGET_HAS_MULX” { rtx hi = gen_reg_rtx (SImode); rtx lo = gen_reg_rtx (SImode);

emit_insn (gen_mulsi3_highpart (hi, operands[1], operands[2])); emit_insn (gen_mulsi3 (lo, operands[1], operands[2])); emit_move_insn (gen_lowpart (SImode, operands[0]), lo); emit_move_insn (gen_highpart (SImode, operands[0]), hi); DONE; })

;; Negate and ones complement

(define_insn “negsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (neg:SI (match_operand:SI 1 “register_operand” “r”)))] "" “sub\t%0, zero, %1” [(set_attr “type” “alu”)])

(define_insn “one_cmplsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (not:SI (match_operand:SI 1 “register_operand” “r”)))] "" “nor\t%0, zero, %1” [(set_attr “type” “alu”)])

;; Integer logical Operations

(define_code_iterator LOGICAL [and ior xor]) (define_code_attr logical_asm [(and “and”) (ior “or”) (xor “xor”)])

(define_insn “si3” [(set (match_operand:SI 0 “register_operand” “=r,r,r”) (LOGICAL:SI (match_operand:SI 1 “register_operand” “%r,r,r”) (match_operand:SI 2 “logical_operand” “rM,J,K”)))] "" “@ <logical_asm>\t%0, %1, %z2 <logical_asm>%i2\t%0, %1, %2 <logical_asm>h%i2\t%0, %1, %U2” [(set_attr “type” “alu”)])

(define_insn “*norsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (and:SI (not:SI (match_operand:SI 1 “register_operand” “%r”)) (not:SI (match_operand:SI 2 “register_operand” “r”))))] "" “nor\t%0, %1, %2” [(set_attr “type” “alu”)])

;; Shift instructions

(define_code_iterator SHIFT [ashift ashiftrt lshiftrt rotate]) (define_code_attr shift_op [(ashift “ashl”) (ashiftrt “ashr”) (lshiftrt “lshr”) (rotate “rotl”)]) (define_code_attr shift_asm [(ashift “sll”) (ashiftrt “sra”) (lshiftrt “srl”) (rotate “rol”)])

(define_insn “<shift_op>si3” [(set (match_operand:SI 0 “register_operand” “=r”) (SHIFT:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “shift_operand” “rL”)))] "" “<shift_asm>%i2\t%0, %1, %z2” [(set_attr “type” “shift”)])

(define_insn “rotrsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (rotatert:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)))] "" “ror\t%0, %1, %2” [(set_attr “type” “shift”)])

;; Floating point instructions

;; Mode iterator for single/double float (define_mode_iterator F [SF DF]) (define_mode_attr f [(SF “s”) (DF “d”)])

;; Basic arithmetic instructions (define_code_iterator FOP3 [plus minus mult div]) (define_code_attr fop3 [(plus “add”) (minus “sub”) (mult “mul”) (div “div”)])

(define_insn “3” [(set (match_operand:F 0 “register_operand” “=r”) (FOP3:F (match_operand:F 1 “register_operand” “r”) (match_operand:F 2 “register_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_f)” { return nios2_fpu_insn_asm (n2fpu_f); } [(set_attr “type” “custom”)])

;; Floating point min/max operations (define_code_iterator SMINMAX [smin smax]) (define_code_attr minmax [(smin “min”) (smax “max”)]) (define_insn “3” [(set (match_operand:F 0 “register_operand” “=r”) (SMINMAX:F (match_operand:F 1 “register_operand” “r”) (match_operand:F 2 “register_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_f)” { return nios2_fpu_insn_asm (n2fpu_f); } [(set_attr “type” “custom”)])

;; These 2-operand FP operations can be collected together (define_code_iterator FOP2 [abs neg sqrt]) (define_insn “2” [(set (match_operand:F 0 “register_operand” “=r”) (FOP2:F (match_operand:F 1 “register_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_f)” { return nios2_fpu_insn_asm (n2fpu_f); } [(set_attr “type” “custom”)])

;; X, Y register access instructions (define_insn “nios2_fwrx” [(unspec_volatile [(match_operand:DF 0 “register_operand” “r”)] UNSPECV_FWRX)] “nios2_fpu_insn_enabled (n2fpu_fwrx)” { return nios2_fpu_insn_asm (n2fpu_fwrx); } [(set_attr “type” “custom”)])

(define_insn “nios2_fwry” [(unspec_volatile [(match_operand:SF 0 “register_operand” “r”)] UNSPECV_FWRY)] “nios2_fpu_insn_enabled (n2fpu_fwry)” { return nios2_fpu_insn_asm (n2fpu_fwry); } [(set_attr “type” “custom”)])

;; The X, Y read insns uses an int iterator (define_int_iterator UNSPEC_READ_XY [UNSPECV_FRDXLO UNSPECV_FRDXHI UNSPECV_FRDY]) (define_int_attr read_xy [(UNSPECV_FRDXLO “frdxlo”) (UNSPECV_FRDXHI “frdxhi”) (UNSPECV_FRDY “frdy”)]) (define_insn “nios2_<read_xy>” [(set (match_operand:SF 0 “register_operand” “=r”) (unspec_volatile:SF [(const_int 0)] UNSPEC_READ_XY))] “nios2_fpu_insn_enabled (n2fpu_<read_xy>)” { return nios2_fpu_insn_asm (n2fpu_<read_xy>); } [(set_attr “type” “custom”)])

;; Various math functions (define_int_iterator MATHFUNC [UNSPEC_FCOS UNSPEC_FSIN UNSPEC_FTAN UNSPEC_FATAN UNSPEC_FEXP UNSPEC_FLOG]) (define_int_attr mathfunc [(UNSPEC_FCOS “cos”) (UNSPEC_FSIN “sin”) (UNSPEC_FTAN “tan”) (UNSPEC_FATAN “atan”) (UNSPEC_FEXP “exp”) (UNSPEC_FLOG “log”)])

(define_insn “2” [(set (match_operand:F 0 “register_operand” “=r”) (unspec:F [(match_operand:F 1 “register_operand” “r”)] MATHFUNC))] “nios2_fpu_insn_enabled (n2fpu_f)” { return nios2_fpu_insn_asm (n2fpu_f); } [(set_attr “type” “custom”)])

;; Converting between floating point and fixed point

(define_code_iterator FLOAT [float unsigned_float]) (define_code_iterator FIX [fix unsigned_fix])

(define_code_attr conv_op [(float “float”) (unsigned_float “floatuns”) (fix “fix”) (unsigned_fix “fixuns”)]) (define_code_attr i [(float “i”) (unsigned_float “u”) (fix “i”) (unsigned_fix “u”)])

;; Integer to float conversions (define_insn “<conv_op>si2” [(set (match_operand:F 0 “register_operand” “=r”) (FLOAT:F (match_operand:SI 1 “register_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_float)” { return nios2_fpu_insn_asm (n2fpu_float); } [(set_attr “type” “custom”)])

;; Float to integer conversions (define_insn “<conv_op>_truncsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (FIX:SI (match_operand:F 1 “general_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_fix)” { return nios2_fpu_insn_asm (n2fpu_fix); } [(set_attr “type” “custom”)])

(define_insn “extendsfdf2” [(set (match_operand:DF 0 “register_operand” “=r”) (float_extend:DF (match_operand:SF 1 “general_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_fextsd)” { return nios2_fpu_insn_asm (n2fpu_fextsd); } [(set_attr “type” “custom”)])

(define_insn “truncdfsf2” [(set (match_operand:SF 0 “register_operand” “=r”) (float_truncate:SF (match_operand:DF 1 “general_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_ftruncds)” { return nios2_fpu_insn_asm (n2fpu_ftruncds); } [(set_attr “type” “custom”)])

;; Prologue, Epilogue and Return

(define_expand “prologue” [(const_int 1)] "" { nios2_expand_prologue (); DONE; })

(define_expand “epilogue” [(return)] "" { nios2_expand_epilogue (false); DONE; })

(define_expand “sibcall_epilogue” [(return)] "" { nios2_expand_epilogue (true); DONE; })

(define_insn “return” [(simple_return)] “nios2_can_use_return_insn ()” “ret”)

(define_insn “simple_return” [(simple_return)] "" “ret”)

;; Block any insns from being moved before this point, since the ;; profiling call to mcount can use various registers that aren't ;; saved or used to pass arguments.

(define_insn “blockage” [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] "" "" [(set_attr “type” “unknown”) (set_attr “length” “0”)])

;; This is used in compiling the unwind routines. (define_expand “eh_return” [(use (match_operand 0 “general_operand”))] "" { if (GET_MODE (operands[0]) != Pmode) operands[0] = convert_to_mode (Pmode, operands[0], 0); emit_insn (gen_eh_set_ra (operands[0])); DONE; })

;; Modify the return address for EH return. We can't expand this ;; until we know where it will be put in the stack frame.

(define_insn_and_split “eh_set_ra” [(unspec [(match_operand:SI 0 “register_operand” “r”)] UNSPEC_EH_RETURN) (clobber (match_scratch:SI 1 “=&r”))] "" “#” “reload_completed” [(const_int 0)] { nios2_set_return_address (operands[0], operands[1]); DONE; })

;; Jumps and calls

; Note that the assembler fixes up any out-of-range branch instructions not ; caught by the compiler branch shortening code. The sequence emitted by ; the assembler can be very inefficient, but it is correct for PIC code. ; For non-PIC we are better off converting to an absolute JMPI. ; ; Direct calls and sibcalls use the CALL and JMPI instructions, respectively. ; These instructions have an immediate operand that specifies the low 28 bits ; of the PC, effectively allowing direct calls within a 256MB memory segment. ; Per the Nios II Processor Reference Handbook, the linker is not required to ; check or adjust for overflow.

(define_insn “indirect_jump” [(set (pc) (match_operand:SI 0 “register_operand” “r”))] "" “jmp\t%0” [(set_attr “type” “control”)])

(define_insn “jump” [(set (pc) (label_ref (match_operand 0 "" "")))] "" { if (flag_pic || get_attr_length (insn) == 4) return “br\t%0”; else return “jmpi\t%0”; } [(set_attr “type” “control”) (set (attr “length”) (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -32768)) (le (minus (match_dup 0) (pc)) (const_int 32764))) (const_int 4) (const_int 8)))])

(define_expand “call” [(parallel [(call (match_operand 0 "" "") (match_operand 1 "" "")) (clobber (reg:SI RA_REGNO))])] "" “nios2_adjust_call_address (&operands[0]);”)

(define_expand “call_value” [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (clobber (reg:SI RA_REGNO))])] "" “nios2_adjust_call_address (&operands[1]);”)

(define_insn “*call” [(call (mem:QI (match_operand:SI 0 “call_operand” “i,r”)) (match_operand 1 "" "")) (clobber (reg:SI RA_REGNO))] "" “@ call\t%0 callr\t%0” [(set_attr “type” “control”)])

(define_insn “*call_value” [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 “call_operand” “i,r”)) (match_operand 2 "" ""))) (clobber (reg:SI RA_REGNO))] "" “@ call\t%1 callr\t%1” [(set_attr “type” “control”)])

(define_expand “sibcall” [(parallel [(call (match_operand 0 "" "") (match_operand 1 "" "")) (return)])] "" “nios2_adjust_call_address (&operands[0]);”)

(define_expand “sibcall_value” [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (return)])] "" “nios2_adjust_call_address (&operands[1]);”)

(define_insn “*sibcall” [(call (mem:QI (match_operand:SI 0 “call_operand” “i,j”)) (match_operand 1 "" "")) (return)] "" “@ jmpi\t%0 jmp\t%0” [(set_attr “type” “control”)])

(define_insn “*sibcall_value” [(set (match_operand 0 “register_operand” "") (call (mem:QI (match_operand:SI 1 “call_operand” “i,j”)) (match_operand 2 "" ""))) (return)] "" “@ jmpi\t%1 jmp\t%1” [(set_attr “type” “control”)])

(define_expand “tablejump” [(parallel [(set (pc) (match_operand 0 “register_operand” “r”)) (use (label_ref (match_operand 1 "" "")))])] "" { if (flag_pic) { /* Hopefully, CSE will eliminate this copy. */ rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1])); rtx reg2 = gen_reg_rtx (SImode);

  emit_insn (gen_addsi3 (reg2, operands[0], reg1));
  operands[0] = reg2;
}

})

(define_insn “*tablejump” [(set (pc) (match_operand:SI 0 “register_operand” “r”)) (use (label_ref (match_operand 1 "" "")))] "" “jmp\t%0” [(set_attr “type” “control”)])

;; cstore, cbranch patterns

(define_mode_iterator CM [SI SF DF])

(define_expand “cstore4” [(set (match_operand:SI 0 “register_operand” “=r”) (match_operator:SI 1 “expandable_comparison_operator” [(match_operand:CM 2 “register_operand”) (match_operand:CM 3 “nonmemory_operand”)]))] "" { if (!nios2_validate_compare (mode, &operands[1], &operands[2], &operands[3])) FAIL; })

(define_expand “cbranch4” [(set (pc) (if_then_else (match_operator 0 “expandable_comparison_operator” [(match_operand:CM 1 “register_operand”) (match_operand:CM 2 “nonmemory_operand”)]) (label_ref (match_operand 3 "")) (pc)))] "" { if (!nios2_validate_compare (mode, &operands[0], &operands[1], &operands[2])) FAIL; if (GET_MODE_CLASS (mode) == MODE_FLOAT || !reg_or_0_operand (operands[2], mode)) { rtx condreg = gen_reg_rtx (SImode); emit_insn (gen_cstore4 (condreg, operands[0], operands[1], operands[2])); operands[1] = condreg; operands[2] = const0_rtx; operands[0] = gen_rtx_fmt_ee (NE, VOIDmode, condreg, const0_rtx); } })

(define_insn “nios2_cbranch” [(set (pc) (if_then_else (match_operator 0 “ordered_comparison_operator” [(match_operand:SI 1 “reg_or_0_operand” “rM”) (match_operand:SI 2 “reg_or_0_operand” “rM”)]) (label_ref (match_operand 3 "" "")) (pc)))] "" { if (flag_pic || get_attr_length (insn) == 4) return “b%0\t%z1, %z2, %l3”; else return “b%R0\t%z1, %z2, .+8;jmpi\t%l3”; } [(set_attr “type” “control”) (set (attr “length”) (if_then_else (and (ge (minus (match_dup 1) (pc)) (const_int -32768)) (le (minus (match_dup 1) (pc)) (const_int 32764))) (const_int 4) (const_int 8)))])

;; Floating point comparisons (define_code_iterator FCMP [eq ne gt ge le lt]) (define_insn “nios2_s” [(set (match_operand:SI 0 “register_operand” “=r”) (FCMP:SI (match_operand:F 1 “register_operand” “r”) (match_operand:F 2 “register_operand” “r”)))] “nios2_fpu_insn_enabled (n2fpu_fcmp)” { return nios2_fpu_insn_asm (n2fpu_fcmp); } [(set_attr “type” “custom”)])

;; Integer comparisons

(define_code_iterator EQNE [eq ne]) (define_insn “nios2_cmp” [(set (match_operand:SI 0 “register_operand” “=r”) (EQNE:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “arith_operand” “rI”)))] "" “cmp%i2\t%0, %1, %z2” [(set_attr “type” “alu”)])

(define_code_iterator SCMP [ge lt]) (define_insn “nios2_cmp” [(set (match_operand:SI 0 “register_operand” “=r”) (SCMP:SI (match_operand:SI 1 “reg_or_0_operand” “rM”) (match_operand:SI 2 “arith_operand” “rI”)))] "" “cmp%i2\t%0, %z1, %z2” [(set_attr “type” “alu”)])

(define_code_iterator UCMP [geu ltu]) (define_insn “nios2_cmp” [(set (match_operand:SI 0 “register_operand” “=r”) (UCMP:SI (match_operand:SI 1 “reg_or_0_operand” “rM”) (match_operand:SI 2 “uns_arith_operand” “rJ”)))] "" “cmp%i2\t%0, %z1, %z2” [(set_attr “type” “alu”)])

;; Custom instruction patterns. The operands are intentionally ;; mode-less, to serve as generic carriers of all Altera defined ;; built-in instruction/function types.

(define_insn “custom_nxx” [(unspec_volatile [(match_operand 0 “custom_insn_opcode” “N”) (match_operand 1 “reg_or_0_operand” “rM”) (match_operand 2 “reg_or_0_operand” “rM”)] UNSPECV_CUSTOM_NXX)] "" “custom\t%0, zero, %z1, %z2” [(set_attr “type” “custom”)])

(define_insn “custom_xnxx” [(set (match_operand 0 “register_operand” “=r”) (unspec_volatile [(match_operand 1 “custom_insn_opcode” “N”) (match_operand 2 “reg_or_0_operand” “rM”) (match_operand 3 “reg_or_0_operand” “rM”)] UNSPECV_CUSTOM_XNXX))] "" “custom\t%1, %0, %z2, %z3” [(set_attr “type” “custom”)])

;; Misc. patterns

(define_insn “nop” [(const_int 0)] "" “nop” [(set_attr “type” “alu”)])

;; Connect ‘sync’ to ‘memory_barrier’ standard expand name (define_expand “memory_barrier” [(const_int 0)] "" { emit_insn (gen_sync ()); DONE; })

;; For the nios2 __builtin_sync built-in function (define_expand “sync” [(set (match_dup 0) (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))] "" { operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); MEM_VOLATILE_P (operands[0]) = 1; })

(define_insn “*sync_insn” [(set (match_operand:BLK 0 "" "") (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))] "" “sync” [(set_attr “type” “control”)])

(define_insn “rdctl” [(set (match_operand:SI 0 “register_operand” “=r”) (unspec_volatile:SI [(match_operand:SI 1 “rdwrctl_operand” “O”)] UNSPECV_RDCTL))] "" “rdctl\t%0, ctl%1” [(set_attr “type” “control”)])

(define_insn “wrctl” [(unspec_volatile:SI [(match_operand:SI 0 “rdwrctl_operand” “O”) (match_operand:SI 1 “reg_or_0_operand” “rM”)] UNSPECV_WRCTL)] "" “wrctl\tctl%0, %z1” [(set_attr “type” “control”)])

;; Trap patterns (define_insn “trap” [(trap_if (const_int 1) (const_int 3))] "" “break\t3” [(set_attr “type” “control”)])

(define_insn “ctrapsi4” [(trap_if (match_operator 0 “ordered_comparison_operator” [(match_operand:SI 1 “reg_or_0_operand” “rM”) (match_operand:SI 2 “reg_or_0_operand” “rM”)]) (match_operand 3 “const_int_operand” “i”))] "" “b%R0\t%z1, %z2, 1f;break\t%3;1:” [(set_attr “type” “control”) (set_attr “length” “8”)])

;; Load the GOT register. (define_insn “load_got_register” [(set (match_operand:SI 0 “register_operand” “=&r”) (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER)) (set (match_operand:SI 1 “register_operand” “=r”) (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))] "" “nextpc\t%0 \t1: \tmovhi\t%1, %%hiadj(_gp_got - 1b) \taddi\t%1, %1, %%lo(_gp_got - 1b)” [(set_attr “length” “12”)])

;; Read thread pointer register (define_expand “get_thread_pointersi” [(match_operand:SI 0 “register_operand” “=r”)] “TARGET_LINUX_ABI” { emit_move_insn (operands[0], gen_rtx_REG (Pmode, TP_REGNO)); DONE; })