[compiler-rt][builtins] Support builtins for LoongArch

Initial builtins for LoongArch.
Add loongarch64 to ALL_CRT_SUPPORTED_ARCH list.
Support fe_getround and fe_raise_inexact in builtins.

Differential Revision: https://reviews.llvm.org/D136338

GitOrigin-RevId: 6e6704b0dc2c8955c6aa3c69535c247ed154eac3
diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake
index a4f3a22..7f8e783 100644
--- a/cmake/Modules/CompilerRTUtils.cmake
+++ b/cmake/Modules/CompilerRTUtils.cmake
@@ -151,6 +151,7 @@
   check_symbol_exists(__aarch64__ "" __AARCH64)
   check_symbol_exists(__x86_64__ "" __X86_64)
   check_symbol_exists(__i386__ "" __I386)
+  check_symbol_exists(__loongarch__ "" __LOONGARCH)
   check_symbol_exists(__mips__ "" __MIPS)
   check_symbol_exists(__mips64__ "" __MIPS64)
   check_symbol_exists(__powerpc__ "" __PPC)
@@ -179,6 +180,14 @@
     endif()
   elseif(__I386)
     add_default_target_arch(i386)
+  elseif(__LOONGARCH)
+    if(CMAKE_SIZEOF_VOID_P EQUAL "4")
+      add_default_target_arch(loongarch32)
+    elseif(CMAKE_SIZEOF_VOID_P EQUAL "8")
+      add_default_target_arch(loongarch64)
+    else()
+      message(FATAL_ERROR "Unsupported pointer size for LoongArch")
+    endif()
   elseif(__MIPS64) # must be checked before __MIPS
     add_default_target_arch(mips64)
   elseif(__MIPS)
diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake
index f5d7385..ac97617 100644
--- a/cmake/base-config-ix.cmake
+++ b/cmake/base-config-ix.cmake
@@ -205,6 +205,8 @@
           test_target_arch(x86_64 "" "")
         endif()
       endif()
+    elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "loongarch64")
+      test_target_arch(loongarch64 "" "")
     elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc64le|ppc64le")
       test_target_arch(powerpc64le "" "-m64")
     elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc")
diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake
index 62e8281..0ecf411 100644
--- a/cmake/builtin-config-ix.cmake
+++ b/cmake/builtin-config-ix.cmake
@@ -50,6 +50,7 @@
 set(HEXAGON hexagon)
 set(X86 i386)
 set(X86_64 x86_64)
+set(LOONGARCH64 loongarch64)
 set(MIPS32 mips mipsel)
 set(MIPS64 mips64 mips64el)
 set(PPC32 powerpc powerpcspe)
@@ -72,7 +73,7 @@
   ${X86} ${X86_64} ${ARM32} ${ARM64} ${AVR}
   ${HEXAGON} ${MIPS32} ${MIPS64} ${PPC32} ${PPC64}
   ${RISCV32} ${RISCV64} ${SPARC} ${SPARCV9}
-  ${WASM32} ${WASM64} ${VE})
+  ${WASM32} ${WASM64} ${VE} ${LOONGARCH64})
 
 include(CompilerRTUtils)
 include(CompilerRTDarwinUtils)
diff --git a/cmake/crt-config-ix.cmake b/cmake/crt-config-ix.cmake
index 78d1a0d..066a0ed 100644
--- a/cmake/crt-config-ix.cmake
+++ b/cmake/crt-config-ix.cmake
@@ -23,6 +23,7 @@
 set(HEXAGON hexagon)
 set(X86 i386)
 set(X86_64 x86_64)
+set(LOONGARCH64 loongarch64)
 set(PPC32 powerpc powerpcspe)
 set(PPC64 powerpc64 powerpc64le)
 set(RISCV32 riscv32)
@@ -30,7 +31,7 @@
 set(VE ve)
 
 set(ALL_CRT_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32}
-    ${PPC64} ${RISCV32} ${RISCV64} ${VE} ${HEXAGON})
+    ${PPC64} ${RISCV32} ${RISCV64} ${VE} ${HEXAGON} ${LOONGARCH64})
 
 include(CompilerRTUtils)
 
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 716ecec..fd3d395 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -620,6 +620,14 @@
   ${GENERIC_TF_SOURCES}
 )
 
+set(loongarch_SOURCES
+  loongarch/fp_mode.c
+  ${GENERIC_SOURCES}
+  ${GENERIC_TF_SOURCES}
+)
+set(loongarch64_SOURCES
+  ${loongarch_SOURCES}
+)
 
 set(mips_SOURCES ${GENERIC_SOURCES})
 set(mipsel_SOURCES ${mips_SOURCES})
diff --git a/lib/builtins/loongarch/fp_mode.c b/lib/builtins/loongarch/fp_mode.c
new file mode 100644
index 0000000..0e3d796
--- /dev/null
+++ b/lib/builtins/loongarch/fp_mode.c
@@ -0,0 +1,49 @@
+//=== lib/builtins/loongarch/fp_mode.c - Floaing-point mode utilities -*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "../fp_mode.h"
+
+#define LOONGARCH_TONEAREST  0x0000
+#define LOONGARCH_TOWARDZERO 0x0100
+#define LOONGARCH_UPWARD     0x0200
+#define LOONGARCH_DOWNWARD   0x0300
+
+#define LOONGARCH_RMODE_MASK (LOONGARCH_TONEAREST | LOONGARCH_TOWARDZERO | \
+                              LOONGARCH_UPWARD | LOONGARCH_DOWNWARD)
+
+#define LOONGARCH_INEXACT    0x10000
+
+CRT_FE_ROUND_MODE __fe_getround(void) {
+#if __loongarch_frlen != 0
+  int fcsr;
+  __asm__ __volatile__("movfcsr2gr %0, $fcsr0" : "=r" (fcsr));
+  fcsr &= LOONGARCH_RMODE_MASK;
+  switch (fcsr) {
+  case LOONGARCH_TOWARDZERO:
+    return CRT_FE_TOWARDZERO;
+  case LOONGARCH_DOWNWARD:
+    return CRT_FE_DOWNWARD;
+  case LOONGARCH_UPWARD:
+    return CRT_FE_UPWARD;
+  case LOONGARCH_TONEAREST:
+  default:
+    return CRT_FE_TONEAREST;
+  }
+#else
+  return CRT_FE_TONEAREST;
+#endif
+}
+
+int __fe_raise_inexact(void) {
+#if __loongarch_frlen != 0
+  int fcsr;
+  __asm__ __volatile__("movfcsr2gr %0, $fcsr0" : "=r" (fcsr));
+  __asm__ __volatile__(
+      "movgr2fcsr $fcsr0, %0" :: "r" (fcsr | LOONGARCH_INEXACT));
+#endif
+  return 0;
+}
diff --git a/test/builtins/Unit/addtf3_test.c b/test/builtins/Unit/addtf3_test.c
index 82a8020..fe2e2c8 100644
--- a/test/builtins/Unit/addtf3_test.c
+++ b/test/builtins/Unit/addtf3_test.c
@@ -66,7 +66,8 @@
         return 1;
 
 #if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \
-    defined(i386) || defined(__x86_64__)
+    defined(i386) || defined(__x86_64__) || (defined(__loongarch__) && \
+    __loongarch_frlen != 0)
     // Rounding mode tests on supported architectures
     const long double m = 1234.0L, n = 0.01L;
 
diff --git a/test/builtins/Unit/subtf3_test.c b/test/builtins/Unit/subtf3_test.c
index c06a0ba..377ae95 100644
--- a/test/builtins/Unit/subtf3_test.c
+++ b/test/builtins/Unit/subtf3_test.c
@@ -59,7 +59,8 @@
         return 1;
 
 #if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \
-    defined(i386) || defined(__x86_64__)
+    defined(i386) || defined(__x86_64__) || (defined(__loongarch__) && \
+    __loongarch_frlen != 0)
     // Rounding mode tests on supported architectures
     const long double m = 1234.02L, n = 0.01L;