From df7eb585789eb03bf9581461edb6fbc93f66aeb7 Mon Sep 17 00:00:00 2001
From: zhaojiale <zhaojiale@loongson.cn>
Date: Fri, 27 Oct 2023 15:34:54 +0800
Subject: [PATCH] gallivm: fix gnome can't start bug

1.Because llvm-12(loongarch) on Euler has some bug, we workaround it in mesa.
  We close vector (-lsx) and add float (+d) feature manually.

2.The bl instruction will out of bounds when relocation isn't static.
  Setting to static, the bl instruction is replace with multiple instructions.
  We workaround it in mesa and set it manually.

Signed-off-by: zhaojiale <zhaojiale@loongson>
---
 meson.build                                   |  9 ++++++
 .../auxiliary/gallivm/lp_bld_debug.cpp        |  6 ++++
 src/gallium/auxiliary/gallivm/lp_bld_misc.cpp | 13 ++++++++-
 src/gallium/auxiliary/gallivm/lp_bld_misc.h   |  1 -
 src/gallium/drivers/llvmpipe/lp_screen.c      |  6 ++--
 src/gallium/include/pipe/p_config.h           |  6 ++++
 src/util/u_cpu_detect.c                       | 28 +++++++++++++++++++
 src/util/u_cpu_detect.h                       |  2 ++
 8 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/meson.build b/meson.build
index 3242bb7..310a7bb 100644
--- a/meson.build
+++ b/meson.build
@@ -1270,6 +1270,15 @@ else
   sse41_args = []
 endif
 
+if host_machine.cpu_family().startswith('loongarch64')
+  pre_args += '-DUSE_LSX'
+  with_lsx = true
+  lsx_args = ['-mlsx']
+else
+  with_lsx = false
+  lsx_args = []
+endif
+
 # Check for GCC style atomics
 dep_atomic = null_dep
 
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
index dda4c7d..c6ce22e 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
+++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
@@ -166,6 +166,12 @@ disassemble(const void* func, std::ostream &buffer)
       }
 #endif
 
+#if defined(PIPE_ARCH_LOONGARCH64)
+      if (Size == 4 && (*(uint32_t *)(bytes+pc) >> 26) == 0x13) {
+         break;
+      }
+#endif
+
       /*
        * Advance.
        */
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
index be288ab..6076057 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
+++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
@@ -376,7 +376,7 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
 
    llvm::SmallVector<std::string, 16> MAttrs;
 
-#if LLVM_VERSION_MAJOR >= 4 && (defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) || defined(PIPE_ARCH_ARM))
+#if LLVM_VERSION_MAJOR >= 4 && (defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) || defined(PIPE_ARCH_ARM) || defined(PIPE_ARCH_LOONGARCH64))
    /* llvm-3.3+ implements sys::getHostCPUFeatures for Arm
     * and llvm-3.7+ for x86, which allows us to enable/disable
     * code generation based on the results of cpuid on these
@@ -470,6 +470,12 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
    MAttrs.push_back("+fp64");
 #endif
 
+#if defined(PIPE_ARCH_LOONGARCH64)
+   MAttrs.push_back("+d");
+   MAttrs.push_back("-lsx");
+   builder.setRelocationModel(Reloc::Static);
+#endif
+
    builder.setMAttrs(MAttrs);
 
    if (gallivm_debug & (GALLIVM_DEBUG_IR | GALLIVM_DEBUG_ASM | GALLIVM_DEBUG_DUMP_BC)) {
@@ -535,6 +541,11 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
       MCPU = util_get_cpu_caps()->has_msa ? "mips64r5" : "mips64r2";
 #endif
 
+#if defined(PIPE_ARCH_LITTLE_ENDIAN) && defined(PIPE_ARCH_LOONGARCH64)
+   if (MCPU == "generic")
+      MCPU = "la464";
+#endif
+
    builder.setMCPU(MCPU);
    if (gallivm_debug & (GALLIVM_DEBUG_IR | GALLIVM_DEBUG_ASM | GALLIVM_DEBUG_DUMP_BC)) {
       debug_printf("llc -mcpu option: %s\n", MCPU.str().c_str());
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.h b/src/gallium/auxiliary/gallivm/lp_bld_misc.h
index fa0ce90..034f4e2 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_misc.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.h
@@ -64,7 +64,6 @@ gallivm_dispose_target_library_info(LLVMTargetLibraryInfoRef library_info);
 extern void
 lp_set_target_options(void);
 
-
 extern int
 lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
                                         struct lp_generated_code **OutCode,
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index 839902b..ffed792 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -895,10 +895,10 @@ static void update_cache_sha1_cpu(struct mesa_sha1 *ctx)
    const struct util_cpu_caps_t *cpu_caps = util_get_cpu_caps();
    /*
     * Don't need the cpu cache affinity stuff. The rest
-    * is contained in first 5 dwords.
+    * is contained in first 6 dwords.
     */
-   STATIC_ASSERT(offsetof(struct util_cpu_caps_t, num_L3_caches) == 5 * sizeof(uint32_t));
-   _mesa_sha1_update(ctx, cpu_caps, 5 * sizeof(uint32_t));
+   STATIC_ASSERT(offsetof(struct util_cpu_caps_t, num_L3_caches) == 6 * sizeof(uint32_t));
+   _mesa_sha1_update(ctx, cpu_caps, 6 * sizeof(uint32_t));
 }
 
 static void lp_disk_cache_create(struct llvmpipe_screen *screen)
diff --git a/src/gallium/include/pipe/p_config.h b/src/gallium/include/pipe/p_config.h
index 978aa45..cc55351 100644
--- a/src/gallium/include/pipe/p_config.h
+++ b/src/gallium/include/pipe/p_config.h
@@ -130,6 +130,12 @@
 #define  PIPE_ARCH_MIPS
 #endif
 
+#if defined(__loongarch64__) || defined(__loongarch64)
+#define PIPE_ARCH_LOONGARCH64
+#elif defined(__loongarch__)
+#define PIPE_ARCH_LOONGARCH
+#endif
+
 /*
  * Endian detection.
  */
diff --git a/src/util/u_cpu_detect.c b/src/util/u_cpu_detect.c
index 955d087..f8ce18e 100644
--- a/src/util/u_cpu_detect.c
+++ b/src/util/u_cpu_detect.c
@@ -456,6 +456,30 @@ check_os_mips64_support(void)
 }
 #endif /* PIPE_ARCH_MIPS64 */
 
+#if defined(PIPE_ARCH_LOONGARCH64)
+static void
+check_os_loongarch64_support(void)
+{
+#if defined(PIPE_OS_LINUX)
+    Elf64_auxv_t aux;
+    int fd;
+
+    fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC);
+    if (fd >= 0) {
+       while (read(fd, &aux, sizeof(Elf64_auxv_t)) == sizeof(Elf64_auxv_t)) {
+          if (aux.a_type == AT_HWCAP) {
+             uint64_t hwcap = aux.a_un.a_val;
+
+             util_cpu_caps.has_lsx = (hwcap >> 2) & 0;
+             util_cpu_caps.has_lasx = (hwcap >> 3) & 0;
+             break;
+          }
+       }
+       close (fd);
+    }
+#endif /* PIPE_OS_LINUX */
+}
+#endif
 
 static void
 get_cpu_topology(void)
@@ -813,6 +837,10 @@ util_cpu_detect_once(void)
    check_os_mips64_support();
 #endif /* PIPE_ARCH_MIPS64 */
 
+#if defined(PIPE_ARCH_LOONGARCH64)
+   check_os_loongarch64_support();
+#endif
+
    get_cpu_topology();
 
    if (debug_get_option_dump_cpu()) {
diff --git a/src/util/u_cpu_detect.h b/src/util/u_cpu_detect.h
index 59dd230..cd4319e 100644
--- a/src/util/u_cpu_detect.h
+++ b/src/util/u_cpu_detect.h
@@ -103,6 +103,8 @@ struct util_cpu_caps_t {
    unsigned has_daz:1;
    unsigned has_neon:1;
    unsigned has_msa:1;
+   unsigned has_lsx:1;
+   unsigned has_lasx:1;
 
    unsigned has_avx512f:1;
    unsigned has_avx512dq:1;
-- 
2.33.0

