nios2.md 30 KB

;; Machine Description for Altera Nios II. ;; Copyright (C) 2012-2015 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_ROUND 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 "ldio" [(set (match_operand:BHW 0 "register_operand" "=r")

    (unspec_volatile:BHW
      [(match_operand:BHW 1 "memory_operand" "m")] UNSPECV_LDXIO))]

"" "ldio\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);

emitinsn (genmulsi3_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 "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")))]

"" "%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")])

(defineinsn "nios2" [(set (match_operand:SF 0 "register_operand" "=r")

    (unspec_volatile:SF [(const_int 0)] UNSPEC_READ_XY))]

"nios2_fpu_insnenabled (n2fpu)" { return nios2_fpu_insnasm (n2fpu); } [(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 "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 "_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 "lroundsfsi2" [(set (match_operand:SI 0 "register_operand" "=r")

    (unspec:SI [(match_operand:SF 1 "general_operand" "r")] UNSPEC_ROUND))]

"nios2_fpu_insn_enabled (n2fpu_round)" { return nios2_fpu_insn_asm (n2fpu_round); } [(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], NULL_RTX);")

(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], NULL_RTX);")

(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], NULL_RTX);")

(define_expand "sibcall_value" [(parallel [(set (match_operand 0 "" "")

               (call (match_operand 1 "" "")
                     (match_operand 2 "" "")))
          (return)])]

"" "nios2_adjust_call_address (&operands[1], NULL_RTX);")

(define_insn "sibcall_internal" [(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_internal" [(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>mode))
{
  rtx condreg = gen_reg_rtx (SImode);
  emit_insn (gen_cstore<mode>4
              (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 3) (pc)) (const_int -32768))
         (le (minus (match_dup 3) (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; })