;; 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 ;; . ;; 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 "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); 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")))] "" "@ \\t%0, %1, %z2 %i2\\t%0, %1, %2 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")]) (define_insn "nios2_" [(set (match_operand:SF 0 "register_operand" "=r") (unspec_volatile:SF [(const_int 0)] UNSPEC_READ_XY))] "nios2_fpu_insn_enabled (n2fpu_)" { return nios2_fpu_insn_asm (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 "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; })