_using_"
+ [(set (match_operand:GPR 0 "register_operand" "=r,r")
+ (if_then_else:GPR
+ (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
+ (const_int 0))
+ (match_operand:GPR 2 "reg_or_0_operand" "r,J")
+ (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
+ "register_operand (operands[2], mode)
+ != register_operand (operands[3], mode)"
+ "@
+ \t%0,%2,%1
+ \t%0,%3,%1"
+ [(set_attr "type" "condmove")
+ (set_attr "mode" "")])
+
+;; sel.fmt copies the 3rd argument when the 1st is non-zero and the 2nd
+;; argument if the 1st is zero. This means operand 2 and 3 are
+;; inverted in the instruction.
+
+(define_insn "*sel"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (if_then_else:ANYF
+ (ne:FCC (match_operand:FCC 1 "register_operand" "z")
+ (const_int 0))
+ (match_operand:ANYF 2 "reg_or_0_operand" "f")
+ (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fsel\t%0,%3,%2,%1"
+ [(set_attr "type" "condmove")
+ (set_attr "mode" "")])
+
+;; These are the main define_expand's used to make conditional moves.
+
+(define_expand "movcc"
+ [(set (match_operand:GPR 0 "register_operand")
+ (if_then_else:GPR (match_operator 1 "comparison_operator"
+ [(match_operand:GPR 2 "reg_or_0_operand")
+ (match_operand:GPR 3 "reg_or_0_operand")])))]
+ "TARGET_COND_MOVE_INT"
+{
+ if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
+ FAIL;
+
+ loongarch_expand_conditional_move (operands);
+ DONE;
+})
+
+(define_expand "movcc"
+ [(set (match_operand:ANYF 0 "register_operand")
+ (if_then_else:ANYF (match_operator 1 "comparison_operator"
+ [(match_operand:ANYF 2 "reg_or_0_operand")
+ (match_operand:ANYF 3 "reg_or_0_operand")])))]
+ "TARGET_COND_MOVE_FLOAT"
+{
+ if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
+ FAIL;
+
+ loongarch_expand_conditional_move (operands);
+ DONE;
+})
+;; lu32i.d
+(define_insn "lu32i_d"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI
+ (zero_extend:DI
+ (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
+ (match_operand:DI 2 "const_lu32i_operand" "u")))]
+ "TARGET_64BIT"
+ "lu32i.d\t%0,%X2>>32"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
+
+;; lu52i.d
+
+(define_insn "lu52i_d"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI
+ (and:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "lu52i_mask_operand"))
+ (match_operand 3 "const_lu52i_operand" "v")))]
+ "TARGET_64BIT"
+ "lu52i.d\t%0,%1,%X3>>52"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
+
+;; Convert floating-point numbers to integers
+
+(define_insn "frint_"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
+ UNSPEC_FRINT))]
+ "TARGET_HARD_FLOAT"
+ "frint.\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "")])
+
+;; LoongArch supports loading and storing a floating point register from
+;; the sum of two general registers. We use two versions for each of
+;; these four instructions: one where the two general registers are
+;; SImode, and one where they are DImode. This is because general
+;; registers will be in SImode when they hold 32-bit values, but,
+;; since the 32-bit values are always sign extended, the f{ld/st}x.{s/d}
+;; instructions will still work correctly.
+
+;; ??? Perhaps it would be better to support these instructions by
+;; modifying TARGET_LEGITIMATE_ADDRESS_P and friends. However, since
+;; these instructions can only be used to load and store floating
+;; point registers, that would probably cause trouble in reload.
+
+(define_insn "*_"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "r")
+ (match_operand:P 2 "register_operand" "r"))))]
+ "TARGET_HARD_FLOAT"
+ "\t%0,%1,%2"
+ [(set_attr "type" "fpidxload")
+ (set_attr "mode" "")])
+
+(define_insn "*_"
+ [(set (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "r")
+ (match_operand:P 2 "register_operand" "r")))
+ (match_operand:ANYF 0 "register_operand" "f"))]
+ "TARGET_HARD_FLOAT"
+ "\t%0,%1,%2"
+ [(set_attr "type" "fpidxstore")
+ (set_attr "mode" "")])
+
+;; loading and storing a integer register from the sum of two general
+;; registers.
+
+(define_insn "*_"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (mem:GPR
+ (plus:P (match_operand:P 1 "register_operand" "r")
+ (match_operand:P 2 "register_operand" "r"))))]
+ ""
+ "\t%0,%1,%2"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "*_"
+ [(set (mem:GPR (plus:P (match_operand:P 1 "register_operand" "r")
+ (match_operand:P 2 "register_operand" "r")))
+ (match_operand:GPR 0 "register_operand" "r"))]
+ ""
+ "\t%0,%1,%2"
+ [(set_attr "type" "store")
+ (set_attr "mode" "")])
+
+;; SHORT mode sign_extend.
+(define_insn "*extend__"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (sign_extend:GPR
+ (mem:SHORT
+ (plus:P (match_operand:P 1 "register_operand" "r")
+ (match_operand:P 2 "register_operand" "r")))))]
+ ""
+ "\t%0,%1,%2"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "*extend_"
+ [(set (mem:SHORT (plus:P (match_operand:P 1 "register_operand" "r")
+ (match_operand:P 2 "register_operand" "r")))
+ (match_operand:SHORT 0 "register_operand" "r"))]
+ ""
+ "\t%0,%1,%2"
+ [(set_attr "type" "store")
+ (set_attr "mode" "SI")])
+
+;; Load the low word of operand 0 with operand 1.
+(define_insn "load_low"
+ [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
+ (unspec:SPLITF [(match_operand: 1 "general_operand" "rJ,m")]
+ UNSPEC_LOAD_LOW))]
+ "TARGET_HARD_FLOAT"
+{
+ operands[0] = loongarch_subword (operands[0], 0);
+ return loongarch_output_move (operands[0], operands[1]);
+}
+ [(set_attr "move_type" "mgtf,fpload")
+ (set_attr "mode" "")])
+
+;; Load the high word of operand 0 from operand 1, preserving the value
+;; in the low word.
+(define_insn "load_high"
+ [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
+ (unspec:SPLITF [(match_operand: 1 "general_operand" "rJ,m")
+ (match_operand:SPLITF 2 "register_operand" "0,0")]
+ UNSPEC_LOAD_HIGH))]
+ "TARGET_HARD_FLOAT"
+{
+ operands[0] = loongarch_subword (operands[0], 1);
+ return loongarch_output_move (operands[0], operands[1]);
+}
+ [(set_attr "move_type" "mgtf,fpload")
+ (set_attr "mode" "")])
+
+;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the
+;; high word and 0 to store the low word.
+(define_insn "store_word"
+ [(set (match_operand: 0 "nonimmediate_operand" "=r,m")
+ (unspec: [(match_operand:SPLITF 1 "register_operand" "f,f")
+ (match_operand 2 "const_int_operand")]
+ UNSPEC_STORE_WORD))]
+ "TARGET_HARD_FLOAT"
+{
+ operands[1] = loongarch_subword (operands[1], INTVAL (operands[2]));
+ return loongarch_output_move (operands[0], operands[1]);
+}
+ [(set_attr "move_type" "mftg,fpstore")
+ (set_attr "mode" "")])
+
+;; Thread-Local Storage
+
+(define_insn "got_load_tls_gd"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec:P
+ [(match_operand:P 1 "symbolic_operand" "")]
+ UNSPEC_TLS_GD))]
+ ""
+ "la.tls.gd\t%0,%1"
+ [(set_attr "got" "load")
+ (set_attr "mode" "")])
+
+(define_insn "got_load_tls_ld"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec:P
+ [(match_operand:P 1 "symbolic_operand" "")]
+ UNSPEC_TLS_LD))]
+ ""
+ "la.tls.ld\t%0,%1"
+ [(set_attr "got" "load")
+ (set_attr "mode" "")])
+
+(define_insn "got_load_tls_le"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec:P
+ [(match_operand:P 1 "symbolic_operand" "")]
+ UNSPEC_TLS_LE))]
+ ""
+ "la.tls.le\t%0,%1"
+ [(set_attr "got" "load")
+ (set_attr "mode" "")])
+
+(define_insn "got_load_tls_ie"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec:P
+ [(match_operand:P 1 "symbolic_operand" "")]
+ UNSPEC_TLS_IE))]
+ ""
+ "la.tls.ie\t%0,%1"
+ [(set_attr "got" "load")
+ (set_attr "mode" "")])
+
+;; Move operand 1 to the high word of operand 0 using movgr2frh, preserving the
+;; value in the low word.
+(define_insn "movgr2frh"
+ [(set (match_operand:SPLITF 0 "register_operand" "=f")
+ (unspec:SPLITF [(match_operand: 1 "reg_or_0_operand" "rJ")
+ (match_operand:SPLITF 2 "register_operand" "0")]
+ UNSPEC_MOVGR2FRH))]
+ "TARGET_DOUBLE_FLOAT"
+ "movgr2frh.w\t%z1,%0"
+ [(set_attr "move_type" "mgtf")
+ (set_attr "mode" "")])
+
+;; Move high word of operand 1 to operand 0 using movfrh2gr.
+(define_insn "movfrh2gr"
+ [(set (match_operand: 0 "register_operand" "=r")
+ (unspec: [(match_operand:SPLITF 1 "register_operand" "f")]
+ UNSPEC_MOVFRH2GR))]
+ "TARGET_DOUBLE_FLOAT"
+ "movfrh2gr.s\t%0,%1"
+ [(set_attr "move_type" "mftg")
+ (set_attr "mode" "")])
+
+
+;; Expand in-line code to clear the instruction cache between operand[0] and
+;; operand[1].
+(define_expand "clear_cache"
+ [(match_operand 0 "pmode_register_operand")
+ (match_operand 1 "pmode_register_operand")]
+ ""
+ "
+{
+ emit_insn (gen_ibar (const0_rtx));
+ DONE;
+}")
+
+(define_insn "ibar"
+ [(unspec_volatile:SI [(match_operand 0 "const_uimm15_operand")] UNSPEC_IBAR)]
+ ""
+ "ibar\t%0")
+
+(define_insn "dbar"
+ [(unspec_volatile:SI [(match_operand 0 "const_uimm15_operand")] UNSPEC_DBAR)]
+ ""
+ "dbar\t%0")
+
+
+
+;; Privileged state instruction
+
+(define_insn "cpucfg"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
+ UNSPEC_CPUCFG))]
+ ""
+ "cpucfg\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "SI")])
+
+(define_insn "asrtle_d"
+ [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "register_operand" "r")]
+ UNSPEC_ASRTLE_D)]
+ "TARGET_64BIT"
+ "asrtle.d\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "DI")])
+
+(define_insn "asrtgt_d"
+ [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "register_operand" "r")]
+ UNSPEC_ASRTGT_D)]
+ "TARGET_64BIT"
+ "asrtgt.d\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "DI")])
+
+(define_insn "csrrd"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (unspec_volatile:GPR [(match_operand 1 "const_uimm14_operand")]
+ UNSPEC_CSRRD))]
+ ""
+ "csrrd\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "csrwr"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (unspec_volatile:GPR
+ [(match_operand:GPR 1 "register_operand" "0")
+ (match_operand 2 "const_uimm14_operand")]
+ UNSPEC_CSRWR))]
+ ""
+ "csrwr\t%0,%2"
+ [(set_attr "type" "store")
+ (set_attr "mode" "")])
+
+(define_insn "csrxchg"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (unspec_volatile:GPR
+ [(match_operand:GPR 1 "register_operand" "0")
+ (match_operand:GPR 2 "register_operand" "q")
+ (match_operand 3 "const_uimm14_operand")]
+ UNSPEC_CSRXCHG))]
+ ""
+ "csrxchg\t%0,%2,%3"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "iocsrrd_"
+ [(set (match_operand:QHWD 0 "register_operand" "=r")
+ (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
+ UNSPEC_IOCSRRD))]
+ ""
+ "iocsrrd.\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "iocsrwr_"
+ [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
+ (match_operand:SI 1 "register_operand" "r")]
+ UNSPEC_IOCSRWR)]
+ ""
+ "iocsrwr.\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "cacop"
+ [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
+ (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "const_imm12_operand")]
+ UNSPEC_CACOP)]
+ ""
+ "cacop\t%0,%1,%2"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "lddir"
+ [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
+ (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "const_uimm5_operand")]
+ UNSPEC_LDDIR)]
+ ""
+ "lddir\t%0,%1,%2"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+(define_insn "ldpte"
+ [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
+ (match_operand 1 "const_uimm5_operand")]
+ UNSPEC_LDPTE)]
+ ""
+ "ldpte\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "")])
+
+
+;; Block moves, see loongarch.c for more details.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "cpymemsi"
+ [(parallel [(set (match_operand:BLK 0 "general_operand")
+ (match_operand:BLK 1 "general_operand"))
+ (use (match_operand:SI 2 ""))
+ (use (match_operand:SI 3 "const_int_operand"))])]
+ " !TARGET_MEMCPY"
+{
+ if (loongarch_expand_block_move (operands[0], operands[1], operands[2]))
+ DONE;
+ else
+ FAIL;
+})
+
+;;
+;; ....................
+;;
+;; SHIFTS
+;;
+;; ....................
+
+(define_insn "3"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+{
+ if (CONST_INT_P (operands[2]))
+ operands[2] = GEN_INT (INTVAL (operands[2])
+ & (GET_MODE_BITSIZE (mode) - 1));
+
+ return "%i2.\t%0,%1,%2";
+}
+ [(set_attr "type" "shift")
+ (set_attr "compression" "none")
+ (set_attr "mode" "