diff --git a/gcc/config/loongarch/loongarch-builtins.cc b/gcc/config/loongarch/loongarch-builtins.cc
index b929f224dfa..58b612bf445 100644
--- a/gcc/config/loongarch/loongarch-builtins.cc
+++ b/gcc/config/loongarch/loongarch-builtins.cc
@@ -256,6 +256,11 @@ loongarch_init_builtins (void)
   unsigned int i;
   tree type;
 
+  /* Register the type float128_type_node as a built-in type and
+     give it an alias "__float128".  */
+  (*lang_hooks.types.register_builtin_type) (float128_type_node,
+					    "__float128");
+
   /* Iterate through all of the bdesc arrays, initializing all of the
      builtin functions.  */
   for (i = 0; i < ARRAY_SIZE (loongarch_builtins); i++)
diff --git a/gcc/config/loongarch/loongarch-c.cc b/gcc/config/loongarch/loongarch-c.cc
index 67911b78f28..6ffbf748316 100644
--- a/gcc/config/loongarch/loongarch-c.cc
+++ b/gcc/config/loongarch/loongarch-c.cc
@@ -99,6 +99,17 @@ loongarch_cpu_cpp_builtins (cpp_reader *pfile)
   else
     builtin_define ("__loongarch_frlen=0");
 
+  /* Add support for FLOAT128_TYPE on the LoongArch architecture.  */
+  builtin_define ("__FLOAT128_TYPE__");
+
+  /* Map the old _Float128 'q' builtins into the new 'f128' builtins.  */
+  builtin_define ("__builtin_fabsq=__builtin_fabsf128");
+  builtin_define ("__builtin_copysignq=__builtin_copysignf128");
+  builtin_define ("__builtin_nanq=__builtin_nanf128");
+  builtin_define ("__builtin_nansq=__builtin_nansf128");
+  builtin_define ("__builtin_infq=__builtin_inff128");
+  builtin_define ("__builtin_huge_valq=__builtin_huge_valf128");
+
   /* Native Data Sizes.  */
   builtin_define_with_int_value ("_LOONGARCH_SZINT", INT_TYPE_SIZE);
   builtin_define_with_int_value ("_LOONGARCH_SZLONG", LONG_TYPE_SIZE);
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index b37e070660f..230d7aac972 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -38,6 +38,7 @@ (define_c_enum "unspec" [
   UNSPEC_FMAX
   UNSPEC_FMIN
   UNSPEC_FCOPYSIGN
+  UNSPEC_COPYSIGNF128
   UNSPEC_FTINT
   UNSPEC_FTINTRM
   UNSPEC_FTINTRP
@@ -2008,6 +2009,59 @@ (define_insn "movfcc"
   ""
   "movgr2cf\t%0,$r0")
 
+;; Implement __builtin_fabs128 function.
+
+(define_expand "abstf2"
+  [(match_operand:TF 0 "register_operand")
+   (match_operand:TF 1 "register_operand")]
+  "TARGET_64BIT"
+{
+  loongarch_emit_move (operands[0], operands[1]);
+  emit_insn (gen_abstf_local (operands[0]));
+  DONE;
+})
+
+(define_insn "abstf_local"
+  [(set (match_operand:TF 0 "register_operand" "+r")
+	(abs:TF (match_dup 0)))]
+  "TARGET_64BIT"
+{
+  operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1);
+  return "bstrins.d\t%0,$r0,0x3f,0x3f";
+})
+
+;; Implement __builtin_copysignf128 function.
+
+(define_insn_and_split "copysigntf3"
+  [(set (match_operand:TF 0 "register_operand" "=&r")
+	(unspec:TF [(match_operand:TF 1 "register_operand" "r")
+		    (match_operand:TF 2 "register_operand" "r")]
+		    UNSPEC_COPYSIGNF128))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+ [(const_int 0)]
+{
+  rtx op0_lo = gen_rtx_REG (DImode,REGNO (operands[0]) + 0);
+  rtx op0_hi = gen_rtx_REG (DImode,REGNO (operands[0]) + 1);
+  rtx op1_lo = gen_rtx_REG (DImode,REGNO (operands[1]) + 0);
+  rtx op1_hi = gen_rtx_REG (DImode,REGNO (operands[1]) + 1);
+  rtx op2_hi = gen_rtx_REG (DImode,REGNO (operands[2]) + 1);
+
+  if (REGNO (operands[1]) == REGNO (operands[2]))
+    {
+      loongarch_emit_move (operands[0], operands[1]);
+      DONE;
+    }
+  else
+    {
+      loongarch_emit_move (op0_hi, op2_hi);
+      loongarch_emit_move (op0_lo, op1_lo);
+      emit_insn (gen_insvdi (op0_hi, GEN_INT (63), GEN_INT (0), op1_hi));
+      DONE;
+    }
+})
+
 ;; Conditional move instructions.
 
 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 400284b85f5..074f1ee33a0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1093,10 +1093,10 @@ types.
 As an extension, GNU C and GNU C++ support additional floating
 types, which are not supported by all targets.
 @itemize @bullet
-@item @code{__float128} is available on i386, x86_64, IA-64, and
-hppa HP-UX, as well as on PowerPC GNU/Linux targets that enable
+@item @code{__float128} is available on i386, x86_64, IA-64, LoongArch
+and hppa HP-UX, as well as on PowerPC GNU/Linux targets that enable
 the vector scalar (VSX) instruction set.  @code{__float128} supports
-the 128-bit floating type.  On i386, x86_64, PowerPC, and IA-64
+the 128-bit floating type.  On i386, x86_64, PowerPC, LoongArch and IA-64,
 other than HP-UX, @code{__float128} is an alias for @code{_Float128}.
 On hppa and IA-64 HP-UX, @code{__float128} is an alias for @code{long
 double}.
@@ -16657,6 +16657,20 @@ function you need to include @code{larchintrin.h}.
     void __break (imm0_32767)
 @end smallexample
 
+Additional built-in functions are available for LoongArch family
+processors to efficiently use 128-bit floating-point (__float128)
+values.
+
+The following are the basic built-in functions supported.
+@smallexample
+__float128 __builtin_fabsq (__float128);
+__float128 __builtin_copysignq (__float128, __float128);
+__float128 __builtin_infq (void);
+__float128 __builtin_huge_valq (void);
+__float128 __builtin_nanq (void);
+__float128 __builtin_nansq (void);
+@end smallexample
+
 @node MIPS DSP Built-in Functions
 @subsection MIPS DSP Built-in Functions
 
diff --git a/gcc/testsuite/gcc.target/loongarch/math-float-128.c b/gcc/testsuite/gcc.target/loongarch/math-float-128.c
new file mode 100644
index 00000000000..5eab3019278
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/math-float-128.c
@@ -0,0 +1,115 @@
+/* { dg-do compile } */
+/* { dg-options " -march=loongarch64 " } */
+/* { dg-final { scan-assembler-times {bstrins.d}  6} } */
+/* { dg-final { scan-assembler-not "my_fabsq2:.*\\bl\t%plt\\(__fabsq\\).*my_fabsq2" } } */
+/* { dg-final { scan-assembler-not "my_copysignq2:.*\\bl\t%plt\\(__copysignq\\).*my_copysignq2" } } */
+/* { dg-final { scan-assembler-not "my_nanq2:.*\\bl\t%plt\\(__builtin_nanq\\).*my_nanq2" } } */
+/* { dg-final { scan-assembler-not "my_nansq2:.*\\bl\t%plt\\(__builtin_nansq\\).*my_nansq2" } } */
+
+__float128
+my_fabsq1 (__float128 a)
+{
+  return __builtin_fabsq (a);
+}
+
+_Float128
+my_fabsq2 (_Float128 a)
+{
+  return __builtin_fabsq (a);
+}
+
+_Float128
+my_fabsf128 (_Float128 a)
+{
+  return __builtin_fabsf128 (a);
+}
+
+__float128
+my_copysignq1 (__float128 a, __float128 b)
+{
+  return __builtin_copysignq (a, b);
+}
+
+_Float128
+my_copysignq2 (_Float128 a, _Float128 b)
+{
+  return __builtin_copysignq (a, b);
+}
+
+_Float128
+my_copysignf128 (_Float128 a, _Float128 b)
+{
+  return __builtin_copysignf128 (a, b);
+}
+
+__float128
+my_infq1 (void)
+{
+  return __builtin_infq ();
+}
+
+_Float128
+my_infq2 (void)
+{
+  return __builtin_infq ();
+}
+
+_Float128
+my_inff128 (void)
+{
+  return __builtin_inff128 ();
+}
+
+__float128
+my_huge_valq1 (void)
+{
+  return __builtin_huge_valq ();
+}
+
+_Float128
+my_huge_valq2 (void)
+{
+  return __builtin_huge_valq ();
+}
+
+_Float128
+my_huge_valf128 (void)
+{
+  return __builtin_huge_valf128 ();
+}
+
+__float128
+my_nanq1 (void)
+{
+  return __builtin_nanq ("");
+}
+
+_Float128
+my_nanq2 (void)
+{
+  return __builtin_nanq ("");
+}
+
+_Float128
+my_nanf128 (void)
+{
+  return __builtin_nanf128 ("");
+}
+
+__float128
+my_nansq1 (void)
+{
+  return __builtin_nansq ("");
+}
+
+_Float128
+my_nansq2 (void)
+{
+  return __builtin_nansq ("");
+}
+
+_Float128
+my_nansf128 (void)
+{
+  return __builtin_nansf128 ("");
+}
