gcc/ChangeLog:

        * config/loongarch/constraints.md: Disable k on LA32.
        * config/loongarch/loongarch.md (*and<mode>3): Delete.
        (*and<mode>3_extend): New.
        (zero_extend<SHORT:mode><GPR:mode>2_la32r): New.
        (extend<SHORT:mode><GPR:mode>2_la32r): New.
        (extendqihi2_la32r): New.
        (*movdi_32bit): Remove not working split, use existing
        loongarch_split_move instead.
        (move_doubleword_2_<mode>): New.
        (load_low<mode>): New.
        (load_high<mode>): New.
        (store_word<mode>): New.
        (movgr2frh<mode>): New.
        (movfrh2gr<mode>): New.
        * config/loongarch/predicates.md: Disable low_bitmask_operand and
        ins_zero_bitmask_operand on LA32. Enable const_call_insn_operand on 
LA32.
        * config/loongarch/sync.md (atomic_<amop><mode>): Change to 
define_expand.
        (la64_atomic_<amop><mode>): New.
        (la32_atomic_<amop>si): New.
        (atomic_fetch_<amop><mode>): Change to define_expand.
        (la64_atomic_fetch_<amop><mode>): New.
        (la32_atomic_fetch_<amop>si): New.
        (atomic_exchange<mode>): Change to define_expand.
        (la64_atomic_exchange<mode>): New.
        (la32_atomic_exchangesi): New.
---
 gcc/config/loongarch/constraints.md |   1 +
 gcc/config/loongarch/loongarch.md   | 436 ++++++++++++++++++++--------
 gcc/config/loongarch/predicates.md  |   8 +-
 gcc/config/loongarch/sync.md        | 198 ++++++++++---
 4 files changed, 482 insertions(+), 161 deletions(-)

diff --git a/gcc/config/loongarch/constraints.md 
b/gcc/config/loongarch/constraints.md
index 82bf1d80b1f..1ca9a752580 100644
--- a/gcc/config/loongarch/constraints.md
+++ b/gcc/config/loongarch/constraints.md
@@ -133,6 +133,7 @@ (define_memory_constraint "k"
   "A memory operand whose address is formed by a base register and (optionally 
scaled)
    index register."
   (and (match_code "mem")
+       (match_test "TARGET_64BIT")
        (match_test "loongarch_base_index_address_p (XEXP (op, 0), mode)")))
 
 (define_constraint "l"
diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index 763d514cac7..39e315c818b 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -409,6 +409,12 @@ (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
 (define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
                             (DI "TARGET_DOUBLE_FLOAT")])
 
+;; A mode for which moves involving FPRs may need to be split.
+(define_mode_iterator SPLITF
+  [(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
+   (DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
+   (TF "TARGET_64BIT && TARGET_DOUBLE_FLOAT")])
+
 ;; A mode for anything with 32 bits or more, and able to be loaded with
 ;; the same addressing mode as ld.w.
 (define_mode_iterator LD_AT_LEAST_32_BIT [GPR ANYF])
@@ -633,7 +639,7 @@ (define_int_attr bytepick_imm [(8 "1")
 ;; so the redundant sign extension can be removed if the output is used as
 ;; an input of a bitwise operation.  Note plus, rotl, and div are handled
 ;; separately.
-(define_code_iterator shift_w [any_shift rotatert])
+(define_code_iterator shift_w [any_shift (rotatert "!TARGET_32BIT_R")])
 (define_code_iterator arith_w [minus mult])
 
 (define_expand "<optab><mode>3"
@@ -743,30 +749,33 @@ (define_expand "addsi3"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
        (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
                 (match_operand:SI 2 "plus_si_operand"  "r,I,La,Le,Lb")))]
-  "TARGET_64BIT"
+  ""
 {
-  if (CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])
-      && ADDU16I_OPERAND (INTVAL (operands[2])))
-    {
-      rtx t1 = gen_reg_rtx (DImode);
-      rtx t2 = gen_reg_rtx (DImode);
-      rtx t3 = gen_reg_rtx (DImode);
-      emit_insn (gen_extend_insn (t1, operands[1], DImode, SImode, 0));
-      t2 = operands[2];
-      emit_insn (gen_adddi3 (t3, t1, t2));
-      t3 = gen_lowpart (SImode, t3);
-      emit_move_insn (operands[0], t3);
-      DONE;
-    }
-  else
+  if (TARGET_64BIT)
     {
-      rtx t = gen_reg_rtx (DImode);
-      emit_insn (gen_addsi3_extended (t, operands[1], operands[2]));
-      t = gen_lowpart (SImode, t);
-      SUBREG_PROMOTED_VAR_P (t) = 1;
-      SUBREG_PROMOTED_SET (t, SRP_SIGNED);
-      emit_move_insn (operands[0], t);
-      DONE;
+      if (CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])
+         && ADDU16I_OPERAND (INTVAL (operands[2])))
+       {
+         rtx t1 = gen_reg_rtx (DImode);
+         rtx t2 = gen_reg_rtx (DImode);
+         rtx t3 = gen_reg_rtx (DImode);
+         emit_insn (gen_extend_insn (t1, operands[1], DImode, SImode, 0));
+         t2 = operands[2];
+         emit_insn (gen_adddi3 (t3, t1, t2));
+         t3 = gen_lowpart (SImode, t3);
+         emit_move_insn (operands[0], t3);
+         DONE;
+       }
+      else
+       {
+         rtx t = gen_reg_rtx (DImode);
+         emit_insn (gen_addsi3_extended (t, operands[1], operands[2]));
+         t = gen_lowpart (SImode, t);
+         SUBREG_PROMOTED_VAR_P (t) = 1;
+         SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+         emit_move_insn (operands[0], t);
+         DONE;
+       }
     }
 })
 
@@ -1376,7 +1385,7 @@ (define_insn "ldexp<mode>3"
        (unspec:ANYF [(match_operand:ANYF    1 "register_operand" "f")
                      (match_operand:<IMODE> 2 "register_operand" "f")]
                     UNSPEC_FSCALEB))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_64BIT"
   "fscaleb.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fscaleb")
    (set_attr "mode" "<UNITMODE>")])
@@ -1392,7 +1401,7 @@ (define_insn "logb_non_negative<mode>2"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
        (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
                     UNSPEC_FLOGB))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_64BIT"
   "flogb.<fmt>\t%0,%1"
   [(set_attr "type" "flogb")
    (set_attr "mode" "<UNITMODE>")])
@@ -1401,7 +1410,7 @@ (define_expand "logb<mode>2"
   [(set (match_operand:ANYF 0 "register_operand")
        (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
                     UNSPEC_FLOGB))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_64BIT"
 {
   rtx tmp = gen_reg_rtx (<MODE>mode);
 
@@ -1421,7 +1430,7 @@ (define_expand "logb<mode>2"
 (define_insn "clz<mode>2"
   [(set (match_operand:GPR 0 "register_operand" "=r")
        (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "clz.<d>\t%0,%1"
   [(set_attr "type" "clz")
    (set_attr "mode" "<MODE>")])
@@ -1437,7 +1446,7 @@ (define_insn "clz<mode>2"
 (define_insn "ctz<mode>2"
   [(set (match_operand:GPR 0 "register_operand" "=r")
        (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "ctz.<d>\t%0,%1"
   [(set_attr "type" "clz")
    (set_attr "mode" "<MODE>")])
@@ -1553,28 +1562,26 @@ (define_insn "neg<mode>2"
 
 (define_insn "*<optab><mode>3"
   [(set (match_operand:GPR 0 "register_operand" "=r,r")
-       (any_or:GPR (match_operand:GPR 1 "register_operand" "%r,r")
-                   (match_operand:GPR 2 "uns_arith_operand" "r,K")))]
+       (any_bitwise:GPR (match_operand:GPR 1 "register_operand" "%r,r")
+                        (match_operand:GPR 2 "uns_arith_operand" "r,K")))]
   ""
   "<insn>%i2\t%0,%1,%2"
   [(set_attr "type" "logical")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=r,r,r,r")
-       (and:GPR (match_operand:GPR 1 "register_operand" "%r,r,r,0")
-                (match_operand:GPR 2 "and_operand" "r,K,Yx,Yy")))]
-  ""
+(define_insn "*and<mode>3_extend"
+  [(set (match_operand:GPR 0 "register_operand" "=r,r")
+       (and:GPR (match_operand:GPR 1 "register_operand" "%r,0")
+                (match_operand:GPR 2 "and_operand" "Yx,Yy")))]
+  "TARGET_64BIT || TARGET_32BIT_S"
   "@
-   and\t%0,%1,%2
-   andi\t%0,%1,%2
    * operands[2] = GEN_INT (INTVAL (operands[2]) \
                            & GET_MODE_MASK (<MODE>mode)); \
      return \"bstrpick.<d>\t%0,%1,%M2\";
    * operands[2] = GEN_INT (~INTVAL (operands[2]) \
                            & GET_MODE_MASK (<MODE>mode)); \
      return \"bstrins.<d>\t%0,%.,%M2\";"
-  [(set_attr "move_type" "logical,logical,pick_ins,pick_ins")
+  [(set_attr "move_type" "pick_ins,pick_ins")
    (set_attr "mode" "<MODE>")])
 
 (define_expand "<optab><mode>3"
@@ -1606,7 +1613,8 @@ (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
                   (match_operand:GPR 2 "const_int_operand" "i"))
          (and:GPR (match_operand:GPR 3 "register_operand" "r")
                   (match_operand:GPR 4 "const_int_operand" "i"))))]
-  "loongarch_pre_reload_split ()
+  "(TARGET_64BIT || TARGET_32BIT_S)
+   && loongarch_pre_reload_split ()
    && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
   "#"
   "&& true"
@@ -1734,7 +1742,7 @@ (define_peephole2
                          (match_operand:SI 3 "const_int_operand")
                          (const_int 0))
        (match_dup 0))]
-  "peep2_reg_dead_p (3, operands[0])"
+  "(TARGET_64BIT || TARGET_32BIT_S) && peep2_reg_dead_p (3, operands[0])"
   [(const_int 0)]
   {
     int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
@@ -1795,7 +1803,7 @@ (define_insn "<optab>n<mode>3"
        (neg_bitwise:X
            (not:X (match_operand:X 2 "register_operand" "r"))
            (match_operand:X 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "<insn>n\t%0,%1,%2"
   [(set_attr "type" "logical")
    (set_attr "mode" "<MODE>")])
@@ -1894,7 +1902,7 @@ (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
   [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
        (zero_extend:GPR
             (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "@
    bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
    ld.<SHORT:size>u\t%0,%1
@@ -1902,6 +1910,15 @@ (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
   [(set_attr "move_type" "pick_ins,load,load")
    (set_attr "mode" "<GPR:MODE>")])
 
+(define_insn "zero_extend<SHORT:mode><GPR:mode>2_la32r"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+       (zero_extend:GPR
+            (match_operand:SHORT 1 "nonimmediate_operand" "m")))]
+  "TARGET_32BIT_R"
+  "ld.<SHORT:size>u\t%0,%1"
+  [(set_attr "move_type" "load")
+   (set_attr "mode" "<GPR:MODE>")])
+
 (define_insn "zero_extendqihi2"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
        (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
@@ -1919,7 +1936,7 @@ (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
   [(set (match_operand:GPR 0 "register_operand" "=r")
        (zero_extend:GPR
            (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
-  "TARGET_64BIT"
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
   [(set_attr "move_type" "pick_ins")
    (set_attr "mode" "<GPR:MODE>")])
@@ -1958,7 +1975,7 @@ (define_insn "extend<SHORT:mode><GPR:mode>2"
   [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
        (sign_extend:GPR
             (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "@
    ext.w.<SHORT:size>\t%0,%1
    ld.<SHORT:size>\t%0,%1
@@ -1966,11 +1983,20 @@ (define_insn "extend<SHORT:mode><GPR:mode>2"
   [(set_attr "move_type" "signext,load,load")
    (set_attr "mode" "<GPR:MODE>")])
 
+(define_insn "extend<SHORT:mode><GPR:mode>2_la32r"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+       (sign_extend:GPR
+            (match_operand:SHORT 1 "nonimmediate_operand" "m")))]
+  "TARGET_32BIT_R"
+  "ld.<SHORT:size>\t%0,%1"
+  [(set_attr "move_type" "load")
+   (set_attr "mode" "<GPR:MODE>")])
+
 (define_insn "extendqihi2"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
        (sign_extend:HI
             (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "@
    ext.w.b\t%0,%1
    ld.b\t%0,%1
@@ -1978,6 +2004,15 @@ (define_insn "extendqihi2"
   [(set_attr "move_type" "signext,load,load")
    (set_attr "mode" "SI")])
 
+(define_insn "extendqihi2_la32r"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (sign_extend:HI
+            (match_operand:QI 1 "nonimmediate_operand" "m")))]
+  ""
+  "ld.b\t%0,%1"
+  [(set_attr "move_type" "load")
+   (set_attr "mode" "SI")])
+
 (define_insn "extendsfdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
@@ -2090,7 +2125,7 @@ (define_expand "fixuns_truncdfsi2"
 (define_expand "fixuns_truncdfdi2"
   [(set (match_operand:DI 0 "register_operand")
        (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
-  "TARGET_DOUBLE_FLOAT"
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT"
 {
   rtx reg1 = gen_reg_rtx (DFmode);
   rtx reg2 = gen_reg_rtx (DFmode);
@@ -2172,7 +2207,7 @@ (define_expand "fixuns_truncsfsi2"
 (define_expand "fixuns_truncsfdi2"
   [(set (match_operand:DI 0 "register_operand")
        (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
-  "TARGET_DOUBLE_FLOAT"
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT"
 {
   rtx reg1 = gen_reg_rtx (SFmode);
   rtx reg2 = gen_reg_rtx (SFmode);
@@ -2222,7 +2257,7 @@ (define_expand "extzv<mode>"
        (zero_extract:X (match_operand:X 1 "register_operand")
                        (match_operand 2 "const_int_operand")
                        (match_operand 3 "const_int_operand")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
 {
   if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
                                INTVAL (operands[3])))
@@ -2232,10 +2267,11 @@ (define_expand "extzv<mode>"
 (define_insn "*extzv<mode>"
   [(set (match_operand:X 0 "register_operand" "=r")
        (zero_extract:X (match_operand:X 1 "register_operand" "r")
-                         (match_operand 2 "const_int_operand" "")
-                         (match_operand 3 "const_int_operand" "")))]
-  "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
-                           INTVAL (operands[3]))"
+                       (match_operand 2 "const_int_operand" "")
+                       (match_operand 3 "const_int_operand" "")))]
+  "(TARGET_64BIT || TARGET_32BIT_S)
+   && loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
+                              INTVAL (operands[3]))"
 {
   operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
   return "bstrpick.<d>\t%0,%1,%2,%3";
@@ -2248,7 +2284,7 @@ (define_expand "insv<mode>"
                          (match_operand 1 "const_int_operand")
                          (match_operand 2 "const_int_operand"))
        (match_operand:GPR 3 "reg_or_0_operand"))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
 {
   if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
                                INTVAL (operands[2])))
@@ -2260,8 +2296,9 @@ (define_insn "*insv<mode>"
                          (match_operand:SI 1 "const_int_operand" "")
                          (match_operand:SI 2 "const_int_operand" ""))
        (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
-  "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
-                           INTVAL (operands[2]))"
+  "(TARGET_64BIT || TARGET_32BIT_S)
+   && loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
+                              INTVAL (operands[2]))"
 {
   operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
   return "bstrins.<d>\t%0,%z3,%1,%2";
@@ -2291,24 +2328,28 @@ (define_expand "movdi"
     DONE;
 })
 
-(define_insn_and_split "*movdi_32bit"
+(define_insn "*movdi_32bit"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
        (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
   "!TARGET_64BIT
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
   { return loongarch_output_move (operands); }
-  "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
-  (operands[0]))"
+  [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
+   (set_attr "mode" "DI")])
+
+;; Split 64-bit move in LoongArch32
+
+(define_split
+  [(set (match_operand:MOVE64 0 "nonimmediate_operand")
+       (match_operand:MOVE64 1 "move_operand"))]
+  "TARGET_32BIT && reload_completed
+   && loongarch_split_move_p (operands[0], operands[1])"
   [(const_int 0)]
-  "
 {
-  loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
+  loongarch_split_move (operands[0], operands[1]);
   DONE;
-}
-  "
-  [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
-   (set_attr "mode" "DI")])
+})
 
 (define_insn_and_split "*movdi_64bit"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
@@ -2319,8 +2360,8 @@ (define_insn_and_split "*movdi_64bit"
   {
     return loongarch_output_move (operands);
   }
-  "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
-  (operands[0]))"
+  "&& CONST_INT_P (operands[1]) && REG_P (operands[0])
+   && GP_REG_P (REGNO (operands[0]))"
   [(const_int 0)]
   "
 {
@@ -2378,7 +2419,7 @@ (define_insn "la_pcrel64_two_parts"
        (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1))
    (set (match_operand:DI 1 "register_operand" "=r")
        (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))]
-  "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE"
+  "TARGET_64BIT && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE"
   {
     return "pcalau12i\t%0,%r2\n\t"
           "addi.d\t%1,$r0,%L2\n\t"
@@ -2396,6 +2437,15 @@ (define_expand "movsi"
        (match_operand:SI 1 ""))]
   ""
 {
+  if (TARGET_32BIT
+      && ((MEM_P (operands[0])
+          && loongarch_14bit_shifted_offset_address_p (XEXP (operands[0], 0), 
SImode)
+          && !loongarch_12bit_offset_address_p (XEXP (operands[0], 0), SImode))
+         || (MEM_P (operands[1])
+             && loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 
0), SImode)
+             && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), 
SImode))))
+    FAIL;
+
   if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
     DONE;
 })
@@ -2404,10 +2454,17 @@ (define_insn_and_split "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,f,f,r,*m")
        (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,rJ,m,f,*f"))]
   "(register_operand (operands[0], SImode)
-    || reg_or_0_operand (operands[1], SImode))"
+    || reg_or_0_operand (operands[1], SImode))
+   && !(TARGET_32BIT
+       && ((MEM_P (operands[0])
+            && loongarch_14bit_shifted_offset_address_p (XEXP (operands[0], 
0), SImode)
+            && !loongarch_12bit_offset_address_p (XEXP (operands[0], 0), 
SImode))
+           || (MEM_P (operands[1])
+               && loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 
0), SImode)
+               && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), 
SImode))))"
   { return loongarch_output_move (operands); }
-  "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
-  (operands[0]))"
+  "&& CONST_INT_P (operands[1]) && REG_P (operands[0])
+   && GP_REG_P (REGNO (operands[0]))"
   [(const_int 0)]
   "
 {
@@ -2482,7 +2539,7 @@ (define_insn "*movqi_internal"
 (define_expand "movsf"
   [(set (match_operand:SF 0 "")
        (match_operand:SF 1 ""))]
-  ""
+  "TARGET_HARD_FLOAT"
 {
   if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
     DONE;
@@ -2513,7 +2570,7 @@ (define_insn "*movsf_softfloat"
 (define_expand "movdf"
   [(set (match_operand:DF 0 "")
        (match_operand:DF 1 ""))]
-  ""
+  "TARGET_DOUBLE_FLOAT"
 {
   if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
     DONE;
@@ -2540,6 +2597,41 @@ (define_insn "*movdf_softfloat"
   [(set_attr "move_type" "move,load,store")
    (set_attr "mode" "DF")])
 
+;; Emit a doubleword move in which exactly one of the operands is
+;; a floating-point register.  We can't just emit two normal moves
+;; because of the constraints imposed by the FPU register model;
+;; see loongarch_can_change_mode_class for details.  Instead, we keep
+;; the FPR whole and use special patterns to refer to each word of
+;; the other operand.
+
+(define_expand "move_doubleword_2_<mode>"
+  [(set (match_operand:SPLITF 0)
+       (match_operand:SPLITF 1))]
+  ""
+{
+  if (FP_REG_RTX_P (operands[0]))
+    {
+      rtx low = loongarch_subword (operands[1], 0);
+      rtx high = loongarch_subword (operands[1], 1);
+      emit_insn (gen_load_low<mode> (operands[0], low));
+      if (!TARGET_64BIT)
+       emit_insn (gen_movgr2frh<mode> (operands[0], high, operands[0]));
+      else
+       emit_insn (gen_load_high<mode> (operands[0], high, operands[0]));
+    }
+  else
+    {
+      rtx low = loongarch_subword (operands[0], 0);
+      rtx high = loongarch_subword (operands[0], 1);
+      emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx));
+      if (!TARGET_64BIT)
+       emit_insn (gen_movfrh2gr<mode> (high, operands[1]));
+      else
+       emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx));
+    }
+  DONE;
+})
+
 ;; Clear one FCC register
 
 (define_expand "movfcc"
@@ -2618,8 +2710,9 @@ (define_insn "*sel<code><GPR:mode>_using_<X:mode>"
                        (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], <GPR:MODE>mode)
-   != register_operand (operands[3], <GPR:MODE>mode)"
+  "(TARGET_64BIT || TARGET_32BIT_S)
+    && register_operand (operands[2], <GPR:MODE>mode)
+       != register_operand (operands[3], <GPR:MODE>mode)"
   "@
    <sel>\t%0,%2,%1
    <selinv>\t%0,%3,%1"
@@ -2681,7 +2774,7 @@ (define_expand "mov<mode>cc"
        (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"
+  "(TARGET_64BIT || TARGET_32BIT_S) && TARGET_COND_MOVE_INT"
 {
   if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
     FAIL;
@@ -2786,7 +2879,7 @@ (define_insn "@pcalau12i<mode>"
   [(set (match_operand:P 0 "register_operand" "=j")
        (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
        UNSPEC_PCALAU12I))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "pcalau12i\t%0,%%pc_hi20(%1)"
   [(set_attr "type" "move")])
 
@@ -2796,7 +2889,7 @@ (define_insn "@pcalau12i_gr<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
        (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
        UNSPEC_PCALAU12I_GR))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "pcalau12i\t%0,%%pc_hi20(%1)"
   [(set_attr "type" "move")])
 
@@ -2846,7 +2939,7 @@ (define_insn "rint<mode>2"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
        (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
                      UNSPEC_FRINT))]
-  ""
+  "TARGET_64BIT"
   "frint.<fmt>\t%0,%1"
   [(set_attr "type" "fcvt")
    (set_attr "mode" "<MODE>")])
@@ -2864,6 +2957,71 @@ (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
   [(set_attr "type" "fcvt")
    (set_attr "mode" "<ANYF:MODE>")])
 
+;; Load the low word of operand 0 with operand 1.
+(define_insn "load_low<mode>"
+  [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
+       (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "rJ,m")]
+                      UNSPEC_LOAD_LOW))]
+  "TARGET_HARD_FLOAT"
+{
+  operands[0] = loongarch_subword (operands[0], 0);
+  return loongarch_output_move (operands);
+}
+  [(set_attr "move_type" "mgtf,fpload")
+   (set_attr "mode" "<HALFMODE>")])
+
+;; Load the high word of operand 0 from operand 1, preserving the value
+;; in the low word.
+(define_insn "load_high<mode>"
+  [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
+       (unspec:SPLITF [(match_operand:<HALFMODE> 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);
+}
+  [(set_attr "move_type" "mgtf,fpload")
+   (set_attr "mode" "<HALFMODE>")])
+
+;; 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<mode>"
+  [(set (match_operand:<HALFMODE> 0 "nonimmediate_operand" "=r,m")
+       (unspec:<HALFMODE> [(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);
+}
+  [(set_attr "move_type" "mftg,fpstore")
+   (set_attr "mode" "<HALFMODE>")])
+
+;; Move operand 1 to the high word of operand 0 using movgr2frh.w, preserving 
the
+;; value in the low word.
+(define_insn "movgr2frh<mode>"
+  [(set (match_operand:SPLITF 0 "register_operand" "=f")
+       (unspec:SPLITF [(match_operand:<HALFMODE> 1 "reg_or_0_operand" "rJ")
+                       (match_operand:SPLITF 2 "register_operand" "0")]
+                       UNSPEC_MOVGR2FRH))]
+  "TARGET_DOUBLE_FLOAT"
+  "movgr2frh.w\t%0,%z1"
+  [(set_attr "move_type" "mgtf")
+   (set_attr "mode" "<HALFMODE>")])
+
+;; Move high word of operand 1 to operand 0 using movfrh2gr.s.
+(define_insn "movfrh2gr<mode>"
+  [(set (match_operand:<HALFMODE> 0 "register_operand" "=r")
+       (unspec:<HALFMODE> [(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" "<HALFMODE>")])
+
 ;; Thread-Local Storage
 
 (define_insn "@got_load_tls_desc<mode>"
@@ -2879,13 +3037,13 @@ (define_insn "@got_load_tls_desc<mode>"
     (clobber (reg:SI FCC5_REGNUM))
     (clobber (reg:SI FCC6_REGNUM))
     (clobber (reg:SI FCC7_REGNUM))
-    (clobber (reg:SI RETURN_ADDR_REGNUM))]
+    (clobber (reg:P RETURN_ADDR_REGNUM))]
   "TARGET_TLS_DESC"
 {
   return TARGET_EXPLICIT_RELOCS
     ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
-      "addi.d\t$r4,$r4,%%desc_pc_lo12(%0)\n\t"
-      "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
+      "addi.<d>\t$r4,$r4,%%desc_pc_lo12(%0)\n\t"
+      "ld.<d>\t$r1,$r4,%%desc_ld(%0)\n\t"
       "jirl\t$r1,$r1,%%desc_call(%0)"
     : "la.tls.desc\t$r4,%0";
 }
@@ -3102,7 +3260,7 @@ (define_insn "loongarch_lddir_<d>"
                       (match_operand 2 "const_uimm5_operand")]
                       UNSPECV_LDDIR)
    (clobber (mem:BLK (scratch)))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "lddir\t%0,%1,%2"
   [(set_attr "type" "load")
    (set_attr "mode" "<MODE>")])
@@ -3112,7 +3270,7 @@ (define_insn "loongarch_ldpte_<d>"
                       (match_operand 1 "const_uimm5_operand")]
                       UNSPECV_LDPTE)
    (clobber (mem:BLK (scratch)))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "ldpte\t%0,%1"
   [(set_attr "type" "load")
    (set_attr "mode" "<MODE>")])
@@ -3190,7 +3348,7 @@ (define_insn "*rotr<mode>3"
   [(set (match_operand:GPR 0 "register_operand" "=r,r")
        (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
                      (match_operand:SI 2 "arith_operand" "r,I")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "rotr%i2.<d>\t%0,%1,%2"
   [(set_attr "type" "shift,shift")
    (set_attr "mode" "<MODE>")])
@@ -3200,7 +3358,7 @@ (define_insn "rotrsi3_extend"
        (sign_extend:DI
          (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
                       (match_operand:SI 2 "arith_operand" "r,I"))))]
-  "TARGET_64BIT"
+  "TARGET_64BIT || TARGET_32BIT_S"
   "rotr%i2.w\t%0,%1,%2"
   [(set_attr "type" "shift,shift")
    (set_attr "mode" "SI")])
@@ -3212,7 +3370,7 @@ (define_expand "rotl<mode>3"
    (set (match_operand:GPR 0 "register_operand")
        (rotatert:GPR (match_operand:GPR 1 "register_operand")
                      (match_dup 3)))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   {
     operands[3] = gen_reg_rtx (SImode);
 
@@ -3235,7 +3393,7 @@ (define_insn "alsl<mode>3"
        (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
                              (match_operand 2 "const_immalsl_operand" ""))
                  (match_operand:GPR 3 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "alsl.<d>\t%0,%1,%3,%2"
   [(set_attr "type" "arith")
    (set_attr "mode" "<MODE>")])
@@ -3278,8 +3436,9 @@ (define_insn_and_split "<optab>_shift_reverse<X:mode>"
          (ashift:X (match_operand:X  1 "register_operand"  "r")
                    (match_operand:SI 2 "const_int_operand" "i"))
          (match_operand:X 3 "const_int_operand" "i")))]
-  "(const_immalsl_operand (operands[2], SImode)
-    || !<bitwise_operand> (operands[3], <MODE>mode))
+  "TARGET_64BIT
+   && (const_immalsl_operand (operands[2], SImode)
+       || !<bitwise_operand> (operands[3], <MODE>mode))
    && loongarch_reassoc_shift_bitwise (<is_and>, operands[2], operands[3],
                                       <MODE>mode)"
   "#"
@@ -3360,7 +3519,7 @@ (define_insn "revb_2h"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (rotatert:SI (bswap:SI (match_operand:SI 1 "register_operand" "r"))
                     (const_int 16)))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "revb.2h\t%0,%1"
   [(set_attr "type" "shift")])
 
@@ -3370,14 +3529,14 @@ (define_insn "revb_2h_extend"
          (rotatert:SI
            (bswap:SI (match_operand:SI 1 "register_operand" "r"))
            (const_int 16))))]
-  "TARGET_64BIT"
+  "TARGET_64BIT || TARGET_32BIT_S"
   "revb.2h\t%0,%1"
   [(set_attr "type" "shift")])
 
 (define_insn "bswaphi2"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "revb.2h\t%0,%1"
   [(set_attr "type" "shift")])
 
@@ -3399,9 +3558,9 @@ (define_insn "*bswapsi2"
 (define_expand "bswapsi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
 {
-  if (!TARGET_64BIT)
+  if (TARGET_32BIT_S)
     {
       rtx t = gen_reg_rtx (SImode);
       emit_insn (gen_revb_2h (t, operands[1]));
@@ -3565,7 +3724,7 @@ (define_expand "cstore<mode>4"
        (match_operator:SI 1 "loongarch_cstore_operator"
         [(match_operand:GPR 2 "register_operand")
          (match_operand:GPR 3 "nonmemory_operand")]))]
-  ""
+  "TARGET_64BIT"
 {
   loongarch_expand_scc (operands);
   DONE;
@@ -3933,12 +4092,18 @@ (define_insn "sibcall_internal"
       return "jr\t%0";
     case 1:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
+       else
+         return "pcaddu12i\t$r12,%%call30(%0)\n\tjirl\t$r0,$r12,0";
       else
        return "b\t%0";
     case 2:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
+       else
+         return "pcaddu12i\t$r12,%%call30(%0)\n\tjirl\t$r0,$r12,0";
       else
        return "b\t%%plt(%0)";
     default:
@@ -4026,12 +4191,18 @@ (define_insn "sibcall_value_internal"
       return "jr\t%1";
     case 1:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       else
+         return "pcaddu12i\t$r12,%%call30(%1)\n\tjirl\t$r0,$r12,0";
       else
        return "b\t%1";
     case 2:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       else
+         return "pcaddu12i\t$r12,%%call30(%1)\n\tjirl\t$r0,$r12,0";
       else
        return "b\t%%plt(%1)";
     default:
@@ -4064,12 +4235,18 @@ (define_insn "sibcall_value_multiple_internal"
       return "jr\t%1";
     case 1:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       else
+         return "pcaddu12i\t$r12,%%call30(%1)\n\tjirl\t$r0,$r12,0";
       else
        return "b\t%1";
     case 2:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+       else
+         return "pcaddu12i\t$r12,%%call30(%1)\n\tjirl\t$r0,$r12,0";
       else
        return "b\t%%plt(%1)";
     default:
@@ -4122,12 +4299,18 @@ (define_insn "call_internal"
       return "jirl\t$r1,%0,0";
     case 1:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
+       else
+         return "pcaddu12i\t$r1,%%call30(%0)\n\tjirl\t$r1,$r1,0";
       else
        return "bl\t%0";
     case 2:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
+       else
+         return "pcaddu12i\t$r1,%%call30(%0)\n\tjirl\t$r1,$r1,0";
       else
        return "bl\t%%plt(%0)";
     default:
@@ -4199,12 +4382,18 @@ (define_insn "call_value_internal"
       return "jirl\t$r1,%1,0";
     case 1:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       else
+         return "pcaddu12i\t$r1,%%call30(%1)\n\tjirl\t$r1,$r1,0";
       else
        return "bl\t%1";
     case 2:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       else
+         return "pcaddu12i\t$r1,%%call30(%1)\n\tjirl\t$r1,$r1,0";
       else
        return "bl\t%%plt(%1)";
     default:
@@ -4239,12 +4428,18 @@ (define_insn "call_value_multiple_internal"
       return "jirl\t$r1,%1,0";
     case 1:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       else
+         return "pcaddu12i\t$r1,%%call30(%1)\n\tjirl\t$r1,$r1,0";
       else
        return "bl\t%1";
     case 2:
       if (TARGET_CMODEL_MEDIUM)
-       return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       if (TARGET_64BIT)
+         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+       else
+         return "pcaddu12i\t$r1,%%call30(%1)\n\tjirl\t$r1,$r1,0";
       else
        return "bl\t%%plt(%1)";
     default:
@@ -4393,7 +4588,7 @@ (define_insn "*bytepick_w_<bytepick_imm>"
                       (const_int <bytepick_w_lshiftrt_amount>))
          (ashift:SI (match_operand:SI 2 "register_operand" "r")
                     (const_int bytepick_w_ashift_amount))))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bytepick.w\t%0,%1,%2,<bytepick_imm>"
   [(set_attr "mode" "SI")])
 
@@ -4411,7 +4606,7 @@ (define_insn "bytepick_w_<bytepick_imm>_extend"
          (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
                           (const_int <bytepick_w_ashift_amount>)
                           (const_int <bitsize>))))]
-  "TARGET_64BIT"
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bytepick.w\t%0,%2,%1,<bytepick_imm>"
   [(set_attr "mode" "SI")])
 
@@ -4426,7 +4621,7 @@ (define_insn "bytepick_w_1_extend"
          (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
                           (const_int 8)
                           (const_int 24))))]
-  "TARGET_64BIT"
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bytepick.w\t%0,%2,%1,1"
   [(set_attr "mode" "SI")])
 
@@ -4456,7 +4651,7 @@ (define_insn "bitrev_4b"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
                    UNSPEC_BITREV_4B))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bitrev.4b\t%0,%1"
   [(set_attr "type" "unknown")
    (set_attr "mode" "SI")])
@@ -4465,7 +4660,7 @@ (define_insn "bitrev_8b"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
                    UNSPEC_BITREV_8B))]
-  ""
+  "TARGET_64BIT"
   "bitrev.8b\t%0,%1"
   [(set_attr "type" "unknown")
    (set_attr "mode" "DI")])
@@ -4473,7 +4668,7 @@ (define_insn "bitrev_8b"
 (define_insn "@rbit<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=r")
        (bitreverse:GPR (match_operand:GPR 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bitrev.<size>\t%0,%1"
   [(set_attr "type" "unknown")
    (set_attr "mode" "<MODE>")])
@@ -4492,7 +4687,7 @@ (define_insn "rbitsi_extended"
 (define_insn "rbitqi"
   [(set (match_operand:QI 0 "register_operand" "=r")
        (bitreverse:QI (match_operand:QI 1 "register_operand" "r")))]
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
   "bitrev.4b\t%0,%1"
   [(set_attr "type" "unknown")
    (set_attr "mode" "SI")])
@@ -4635,7 +4830,7 @@ (define_insn "loongarch_<crc>_w_<size>_w"
        (unspec:SI [(match_operand:QHWD 1 "register_operand" "r")
                   (match_operand:SI 2 "register_operand" "r")]
                     CRC))]
-  ""
+  "TARGET_64BIT"
   "<crc>.w.<size>.w\t%0,%1,%2"
   [(set_attr "type" "unknown")
    (set_attr "mode" "<MODE>")])
@@ -4656,7 +4851,7 @@ (define_expand "crc_rev<mode>si4"
    (match_operand:SI   1 "register_operand")   ; old_chksum
    (match_operand:SUBDI        2 "reg_or_0_operand")   ; msg
    (match_operand      3 "const_int_operand")] ; poly
-  ""
+  "TARGET_64BIT"
   {
     unsigned HOST_WIDE_INT poly = UINTVAL (operands[3]);
     rtx msg = operands[2];
@@ -4753,7 +4948,8 @@ (define_insn_and_split "*crc_combine"
 (define_insn_and_rewrite "simple_load<mode>"
   [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
        (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
-  "loongarch_pre_reload_split ()
+  "(TARGET_64BIT || TARGET_32BIT_S)
+   && loongarch_pre_reload_split ()
    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
   "#"
@@ -4766,7 +4962,8 @@ (define_insn_and_rewrite 
"simple_load_<su>ext<SUBDI:mode><GPR:mode>"
   [(set (match_operand:GPR 0 "register_operand" "=r")
        (any_extend:GPR
          (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
-  "loongarch_pre_reload_split ()
+  "(TARGET_64BIT || TARGET_32BIT_S)
+   && loongarch_pre_reload_split ()
    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
   "#"
@@ -4778,7 +4975,8 @@ (define_insn_and_rewrite 
"simple_load_<su>ext<SUBDI:mode><GPR:mode>"
 (define_insn_and_rewrite "simple_store<mode>"
   [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
        (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
-  "loongarch_pre_reload_split ()
+  "(TARGET_64BIT || TARGET_32BIT_S)
+   && loongarch_pre_reload_split ()
    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
   "#"
diff --git a/gcc/config/loongarch/predicates.md 
b/gcc/config/loongarch/predicates.md
index 7e4d8abc822..980ae5cc8dd 100644
--- a/gcc/config/loongarch/predicates.md
+++ b/gcc/config/loongarch/predicates.md
@@ -295,7 +295,8 @@ (define_predicate "si_mask_operand"
 
 (define_predicate "low_bitmask_operand"
   (and (match_code "const_int")
-       (match_test "low_bitmask_len (mode, INTVAL (op)) > 12")))
+       (match_test "low_bitmask_len (mode, INTVAL (op)) > 12")
+       (match_test "!TARGET_32BIT_R")))
 
 (define_predicate "d_operand"
   (and (match_code "reg")
@@ -406,6 +407,7 @@ (define_predicate "muldiv_target_operand"
 
 (define_predicate "ins_zero_bitmask_operand"
   (and (match_code "const_int")
+       (match_test "!TARGET_32BIT_R")
        (match_test "low_bitmask_len (mode, \
                                     ~UINTVAL (op) | (~UINTVAL(op) - 1)) \
                    > 0")
@@ -438,6 +440,10 @@ (define_predicate "const_call_insn_operand"
   if (offset != const0_rtx)
     return false;
 
+  /* TARGET_32BIT always support call30.  */
+  if (TARGET_32BIT)
+    return true;
+
   /* When compiling with '-mcmodel=medium -mexplicit-relocs'
      symbols are splited in loongarch_legitimize_call_address.
 
diff --git a/gcc/config/loongarch/sync.md b/gcc/config/loongarch/sync.md
index 5784dab92a6..86c475d052f 100644
--- a/gcc/config/loongarch/sync.md
+++ b/gcc/config/loongarch/sync.md
@@ -45,6 +45,10 @@ (define_code_iterator any_atomic [plus ior xor and])
 ;; particular code.
 (define_code_attr amop [(ior "or") (xor "xor") (and "and") (plus "add")])
 
+;; For 32 bit.
+(define_code_attr atomic_optab_insn
+  [(plus "add.w") (ior "or") (xor "xor") (and "and")])
+
 ;; Memory barriers.
 
 (define_expand "mem_thread_fence"
@@ -260,17 +264,48 @@ (define_expand "atomic_storeti"
   DONE;
 })
 
-(define_insn "atomic_<amop><mode>"
+(define_expand "atomic_<amop><mode>"
+  [(any_atomic:GPR (match_operand:GPR 0 "memory_operand")    ;; mem location
+                  (match_operand:GPR 1 "reg_or_0_operand")) ;; value for op
+   (match_operand:SI 2 "const_int_operand")]                ;; model
+  ""
+{
+  if (TARGET_64BIT)
+    emit_insn (gen_la64_atomic_<amop><mode> (operands[0], operands[1], 
operands[2]));
+  else
+    emit_insn (gen_la32_atomic_<amop>si (operands[0], operands[1], 
operands[2]));
+  DONE;
+})
+
+(define_insn "la64_atomic_<amop><mode>"
   [(set (match_operand:GPR 0 "memory_operand" "+ZB")
        (unspec_volatile:GPR
          [(any_atomic:GPR (match_dup 0)
                           (match_operand:GPR 1 "reg_or_0_operand" "rJ"))
           (match_operand:SI 2 "const_int_operand")] ;; model
         UNSPEC_SYNC_OLD_OP))]
-  ""
+  "TARGET_64BIT"
   "am<amop>%A2.<size>\t$zero,%z1,%0"
   [(set (attr "length") (const_int 4))])
 
+(define_insn "la32_atomic_<amop>si"
+  [(set (match_operand:SI 0 "memory_operand" "+ZB")
+       (unspec_volatile:SI
+         [(any_atomic:SI (match_dup 0)
+                          (match_operand:SI 1 "reg_or_0_operand" "rJ"))
+          (match_operand:SI 2 "const_int_operand")] ;; model
+        UNSPEC_SYNC_OLD_OP))
+   (clobber (match_scratch:SI 3 "=&r"))]
+  "!TARGET_64BIT"
+{
+  return "1:\n\t"
+        "ll.w\t%3,%0\n\t"
+        "<atomic_optab_insn>\t%3,%z1,%3\n\t"
+        "sc.w\t%3,%0\n\t"
+        "beq\t$zero,%3,1b\n\t";
+}
+  [(set (attr "length") (const_int 16))])
+
 (define_insn "atomic_add<mode>"
   [(set (match_operand:SHORT 0 "memory_operand" "+ZB")
        (unspec_volatile:SHORT
@@ -282,7 +317,23 @@ (define_insn "atomic_add<mode>"
   "amadd%A2.<size>\t$zero,%z1,%0"
   [(set (attr "length") (const_int 4))])
 
-(define_insn "atomic_fetch_<amop><mode>"
+(define_expand "atomic_fetch_<amop><mode>"
+  [(match_operand:GPR 0 "register_operand")                 ;; old value at mem
+   (any_atomic:GPR (match_operand:GPR 1 "memory_operand")    ;; mem location
+                  (match_operand:GPR 2 "reg_or_0_operand")) ;; value for op
+   (match_operand:SI 3 "const_int_operand")]                ;; model
+  ""
+  {
+    if (TARGET_64BIT)
+      emit_insn (gen_la64_atomic_fetch_<amop><mode> (operands[0], operands[1],
+                                                    operands[2], operands[3]));
+    else
+      emit_insn (gen_la32_atomic_fetch_<amop>si (operands[0], operands[1],
+                                                    operands[2], operands[3]));
+    DONE;
+  })
+
+(define_insn "la64_atomic_fetch_<amop><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
        (match_operand:GPR 1 "memory_operand" "+ZB"))
    (set (match_dup 1)
@@ -291,10 +342,30 @@ (define_insn "atomic_fetch_<amop><mode>"
                           (match_operand:GPR 2 "reg_or_0_operand" "rJ"))
           (match_operand:SI 3 "const_int_operand")] ;; model
         UNSPEC_SYNC_OLD_OP))]
-  ""
+  "TARGET_64BIT"
   "am<amop>%A3.<size>\t%0,%z2,%1"
   [(set (attr "length") (const_int 4))])
 
+(define_insn "la32_atomic_fetch_<amop>si"
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (match_operand:SI 1 "memory_operand" "+ZB"))
+   (set (match_dup 1)
+       (unspec_volatile:SI
+         [(any_atomic:SI (match_dup 1)
+                          (match_operand:SI 2 "reg_or_0_operand" "rJ"))
+          (match_operand:SI 3 "const_int_operand")] ;; model
+        UNSPEC_SYNC_OLD_OP))
+   (clobber (match_scratch:SI 4 "=&r"))]
+  "!TARGET_64BIT"
+{
+  return "1:\n\t"
+         "ll.w\t%0,%1\n\t"
+         "<atomic_optab_insn>\t%4,%z2,%0\n\t"
+         "sc.w\t%4,%1\n\t"
+         "beq\t$zero,%4,1b\n\t";
+}
+  [(set (attr "length") (const_int 16))])
+
 (define_insn "atomic_fetch_nand_mask_inverted<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
        (match_operand:GPR 1 "memory_operand" "+ZC"))
@@ -305,14 +376,24 @@ (define_insn "atomic_fetch_nand_mask_inverted<mode>"
          UNSPEC_SYNC_OLD_OP))
    (clobber (match_scratch:GPR 3 "=&r"))]
   ""
-  {
-    return "1:\\n\\t"
-          "ll.<d>\\t%0,%1\\n\\t"
-          "orn\\t%3,%2,%0\\n\\t"
-          "sc.<d>\\t%3,%1\\n\\t"
-          "beqz\\t%3,1b";
-  }
-  [(set (attr "length") (const_int 16))])
+{
+  output_asm_insn ("1:", operands);
+  output_asm_insn ("ll.<d>\t%0,%1", operands);
+  if (TARGET_32BIT_R)
+    {
+      output_asm_insn ("nor\t%3,%0,$zero", operands);
+      output_asm_insn ("or\t%3,%2,%3", operands);
+    }
+  else
+    output_asm_insn ("orn\t%3,%2,%0", operands);
+  output_asm_insn ("sc.<d>\t%3,%1", operands);
+  output_asm_insn ("beq\t%3,$zero,1b", operands);
+  return "";
+}
+  [(set (attr "length") (if_then_else
+                         (match_test "TARGET_32BIT_R")
+                         (const_int 20)
+                         (const_int 16)))])
 
 (define_mode_iterator ALL_SC [GPR (TI "loongarch_16b_atomic_lock_free_p ()")])
 (define_mode_attr _scq [(SI "") (DI "") (TI "_scq")])
@@ -338,7 +419,23 @@ (define_expand "atomic_fetch_nand<mode>"
     DONE;
   })
 
-(define_insn "atomic_exchange<mode>"
+(define_expand "atomic_exchange<mode>"
+  [(match_operand:GPR 0 "register_operand")  ;; old value at mem
+   (match_operand:GPR 1 "memory_operand")    ;; mem location
+   (match_operand:GPR 2 "register_operand")  ;; value for op
+   (match_operand:SI 3 "const_int_operand")] ;; model
+  ""
+  {
+    if (TARGET_64BIT)
+      emit_insn (gen_la64_atomic_exchange<mode> (operands[0], operands[1],
+                                                operands[2], operands[3]));
+    else
+      emit_insn (gen_la32_atomic_exchangesi (operands[0], operands[1],
+                                                operands[2], operands[3]));
+    DONE;
+  })
+
+(define_insn "la64_atomic_exchange<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
        (unspec_volatile:GPR
          [(match_operand:GPR 1 "memory_operand" "+ZB")
@@ -346,10 +443,29 @@ (define_insn "atomic_exchange<mode>"
          UNSPEC_SYNC_EXCHANGE))
    (set (match_dup 1)
        (match_operand:GPR 2 "register_operand" "r"))]
-  ""
+  "TARGET_64BIT"
   "amswap%A3.<size>\t%0,%z2,%1"
   [(set (attr "length") (const_int 4))])
 
+(define_insn "la32_atomic_exchangesi"
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (unspec_volatile:SI
+         [(match_operand:SI 1 "memory_operand" "+ZB")
+          (match_operand:SI 3 "const_int_operand")] ;; model
+         UNSPEC_SYNC_EXCHANGE))
+   (set (match_dup 1)
+       (match_operand:SI 2 "register_operand" "r"))
+   (clobber (match_scratch:SI 4 "=&r"))]
+  "!TARGET_64BIT"
+{
+  return "1:\n\t"
+        "ll.w\t%0,%1\n\t"
+        "or\t%4,$zero,%2\n\t"
+        "sc.w\t%4,%1\n\t"
+        "beq\t$zero,%4,1b\n\t";
+}
+  [(set (attr "length") (const_int 16))])
+
 (define_insn "atomic_exchangeti_scq"
   [(set (match_operand:TI 0 "register_operand" "=&r")
        (unspec_volatile:TI
@@ -367,7 +483,7 @@ (define_insn "atomic_exchangeti_scq"
   output_asm_insn ("ld.d\t%t0,%b1,8", operands);
   output_asm_insn ("move\t%3,%z2", operands);
   output_asm_insn ("sc.q\t%3,%t2,%1", operands);
-  output_asm_insn ("beqz\t%3,1b", operands);
+  output_asm_insn ("beq\t%3,$zero,1b", operands);
 
   return "";
 }
@@ -430,7 +546,7 @@ (define_insn "atomic_cas_value_strong<mode>"
 
   output_asm_insn ("or%i3\t%5,$zero,%3", operands);
   output_asm_insn ("sc.<size>\t%5,%1", operands);
-  output_asm_insn ("beqz\t%5,1b", operands);
+  output_asm_insn ("beq\t%5,$zero,1b", operands);
   output_asm_insn ("%T4b\t3f", operands);
   output_asm_insn ("2:", operands);
   output_asm_insn ("%G4", operands);
@@ -498,7 +614,7 @@ (define_expand "atomic_compare_and_swap<mode>"
       emit_insn (gen_rtx_SET (compare, difference));
     }
 
-  if (word_mode != <MODE>mode)
+  if (word_mode != GET_MODE (compare))
     {
       rtx reg = gen_reg_rtx (word_mode);
       emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, compare)));
@@ -515,7 +631,7 @@ (define_expand "atomic_fetch_<amop><mode>"
    (any_bitwise (match_operand:SHORT 1 "memory_operand"   "+ZB") ;; memory
                (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) ;; val
    (match_operand:SI 3 "const_int_operand" "")]                         ;; 
model
-  ""
+  "TARGET_64BIT || TARGET_32BIT_S"
 {
   /* We have no QI/HImode bitwise atomics, so use the address LSBs to form
      a mask, then use an aligned SImode atomic.  */
@@ -642,26 +758,26 @@ (define_expand "atomic_compare_and_swap<mode>"
                                    operands[3], operands[4], mod_f);
     }
 
-      rtx compare = operands[1];
-      if (operands[3] != const0_rtx)
-       {
-         machine_mode mode = GET_MODE (operands[3]);
-         rtx op1 = convert_modes (SImode, mode, operands[1], true);
-         rtx op3 = convert_modes (SImode, mode, operands[3], true);
-         rtx difference = gen_rtx_MINUS (SImode, op1, op3);
-         compare = gen_reg_rtx (SImode);
-         emit_insn (gen_rtx_SET (compare, difference));
-       }
-
-      if (word_mode != <MODE>mode)
-       {
-         rtx reg = gen_reg_rtx (word_mode);
-         emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, 
compare)));
-         compare = reg;
-       }
-
-      emit_insn (gen_rtx_SET (operands[0],
-                             gen_rtx_EQ (SImode, compare, const0_rtx)));
+  rtx compare = operands[1];
+  if (operands[3] != const0_rtx)
+    {
+      machine_mode mode = GET_MODE (operands[3]);
+      rtx op1 = convert_modes (SImode, mode, operands[1], true);
+      rtx op3 = convert_modes (SImode, mode, operands[3], true);
+      rtx difference = gen_rtx_MINUS (SImode, op1, op3);
+      compare = gen_reg_rtx (SImode);
+      emit_insn (gen_rtx_SET (compare, difference));
+    }
+
+  if (word_mode != GET_MODE (compare))
+    {
+      rtx reg = gen_reg_rtx (word_mode);
+      emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, compare)));
+      compare = reg;
+    }
+
+  emit_insn (gen_rtx_SET (operands[0],
+                         gen_rtx_EQ (SImode, compare, const0_rtx)));
   DONE;
 })
 
@@ -716,7 +832,7 @@ (define_insn "atomic_compare_and_swapti_scq"
   output_asm_insn ("sc.q\t%7,%t3,%1", operands);
 
   /* Check if sc.q has done the store.  */
-  output_asm_insn ("beqz\t%7,1b", operands);
+  output_asm_insn ("beq\t%7,$zero,1b", operands);
 
   /* Jump over the mod_f barrier if sc.q has succeeded.  */
   output_asm_insn ("%T4b\t3f", operands);
@@ -870,7 +986,7 @@ (define_insn "atomic_cas_value_exchange_7_<mode>"
         "and\\t%7,%0,%z3\\n\\t"
         "or%i5\\t%7,%7,%5\\n\\t"
         "sc.<size>\\t%7,%1\\n\\t"
-        "beqz\\t%7,1b\\n\\t";
+        "beq\\t%7,$zero,1b\\n\\t";
 }
   [(set (attr "length") (const_int 20))])
 
@@ -967,7 +1083,7 @@ (define_insn "atomic_fetch_<amop_ti_fetch>ti_scq"
     }
 
   output_asm_insn ("sc.q\t%3,%4,%1", operands);
-  output_asm_insn ("beqz\t%3,1b", operands);
+  output_asm_insn ("beq\t%3,$zero,1b", operands);
 
   return "";
 }
-- 
2.34.1

Reply via email to