From 2ff5a2bd0a7d14c675cbc5f0e11bf6916b960b20 Mon Sep 17 00:00:00 2001
From: Ami-zhang <96056515+Ami-zhang@users.noreply.github.com>
Date: Thu, 28 Sep 2023 15:20:27 +0800
Subject: [PATCH 1/9] [Driver] Support -fsanitize=cfi-icall on loongarch64
 (#67310)

(cherry picked from commit 55accc82bec48acae769b086ad9a5dc29da77f02)
---
 clang/lib/Driver/ToolChain.cpp | 3 ++-
 clang/test/Driver/fsanitize.c  | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 0146d8af3549..69811c095594 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1273,7 +1273,8 @@ SanitizerMask ToolChain::getSupportedSanitizers() const {
   if (getTriple().getArch() == llvm::Triple::x86 ||
       getTriple().getArch() == llvm::Triple::x86_64 ||
       getTriple().getArch() == llvm::Triple::arm || getTriple().isWasm() ||
-      getTriple().isAArch64() || getTriple().isRISCV())
+      getTriple().isAArch64() || getTriple().isRISCV() ||
+      getTriple().isLoongArch64())
     Res |= SanitizerKind::CFIICall;
   if (getTriple().getArch() == llvm::Triple::x86_64 ||
       getTriple().isAArch64(64) || getTriple().isRISCV())
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index 9442f6b91471..4a525d75ea11 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -600,6 +600,7 @@
 // RUN: %clang --target=aarch64_be -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
 // RUN: %clang --target=riscv32 -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
 // RUN: %clang --target=riscv64 -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
+// RUN: %clang --target=loongarch64 -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
 // CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-icall,cfi-mfcall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall
 // CHECK-CFI-NOMFCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-icall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall
 // CHECK-CFI-DCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast
-- 
2.20.1


From acfb50b03b0be3eda5282f26bad34ffc18595b30 Mon Sep 17 00:00:00 2001
From: Nathan Chancellor <nathan@kernel.org>
Date: Fri, 8 Sep 2023 10:54:35 -0700
Subject: [PATCH 2/9] [Clang][LoongArch] Generate _mcount instead of mcount
 (#65657)

When building the LoongArch Linux kernel without
`CONFIG_DYNAMIC_FTRACE`, the build fails to link because the mcount
symbol is `mcount`, not `_mcount` like GCC generates and the kernel
expects:

```
ld.lld: error: undefined symbol: mcount
>>> referenced by version.c
>>>               init/version.o:(early_hostname) in archive vmlinux.a
>>> referenced by do_mounts.c
>>>               init/do_mounts.o:(rootfs_init_fs_context) in archive vmlinux.a
>>> referenced by main.c
>>>               init/main.o:(__traceiter_initcall_level) in archive vmlinux.a
>>> referenced 97011 more times
>>> did you mean: _mcount
>>> defined in: vmlinux.a(arch/loongarch/kernel/mcount.o)
```

Set `MCountName` in `LoongArchTargetInfo` to `_mcount`, which resolves
the build failure.

(cherry picked from commit cc2b09bee017147527e7bd1eb5272f4f70a7b900)
---
 clang/lib/Basic/Targets/LoongArch.h | 1 +
 clang/test/CodeGen/mcount.c         | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h
index 8f4150b2539d..3313102492cb 100644
--- a/clang/lib/Basic/Targets/LoongArch.h
+++ b/clang/lib/Basic/Targets/LoongArch.h
@@ -40,6 +40,7 @@ public:
     LongDoubleWidth = 128;
     LongDoubleAlign = 128;
     LongDoubleFormat = &llvm::APFloat::IEEEquad();
+    MCountName = "_mcount";
     SuitableAlign = 128;
     WCharType = SignedInt;
     WIntType = UnsignedInt;
diff --git a/clang/test/CodeGen/mcount.c b/clang/test/CodeGen/mcount.c
index 8f994ab4e754..bdd609c1dfc5 100644
--- a/clang/test/CodeGen/mcount.c
+++ b/clang/test/CodeGen/mcount.c
@@ -7,6 +7,8 @@
 // RUN: %clang_cc1 -pg -triple x86_64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-DOUBLE-PREFIXED,NO-MCOUNT1 %s
 // RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-DOUBLE-PREFIXED,NO-MCOUNT1 %s
 // RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-DOUBLE-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple loongarch32 -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple loongarch64 -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
 // RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-DOUBLE-PREFIXED,NO-MCOUNT1 %s
 // RUN: %clang_cc1 -pg -triple mips-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
 // RUN: %clang_cc1 -pg -triple mipsel-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
-- 
2.20.1


From a841576d7a53d3d8fd61aa854af7d9c2dd204536 Mon Sep 17 00:00:00 2001
From: Weining Lu <luweining@loongson.cn>
Date: Thu, 26 Oct 2023 11:50:28 +0800
Subject: [PATCH 3/9] [LoongArch][test] Add some ABI regression tests for empty
 struct. NFC

How empty structs (not as fields of container struct) are passed in C++
is not explicitly documented in psABI. This patch adds some tests
showing the current handing of clang. Some of the results are different
from gcc. Following patch(es) will try to fix the mismatch.

(cherry picked from commit 8149066fa532d82ff62a0629d5a9fab6bd4da768)
---
 .../LoongArch/abi-lp64d-empty-structs.c       | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
index fb90bf556c19..d0daafac336e 100644
--- a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
@@ -81,9 +81,62 @@ struct s8 test_s8(struct s8 a) {
   return a;
 }
 
+/// Note: Below tests check how empty structs are passed while above tests check
+/// empty structs as fields of container struct are ignored when flattening
+/// structs to examine whether the container structs can be passed via FARs.
+
 // CHECK-C: define{{.*}} void @test_s9()
 // CHECK-CXX: define{{.*}} i64 @_Z7test_s92s9(i64 {{.*}})
 struct s9 { struct empty e; };
 struct s9 test_s9(struct s9 a) {
   return a;
 }
+
+// CHECK-C: define{{.*}} void @test_s10()
+// CHECK-CXX: define{{.*}} void @_Z8test_s103s10()
+struct s10 { };
+struct s10 test_s10(struct s10 a) {
+  return a;
+}
+
+// CHECK-C: define{{.*}} void @test_s11()
+// CHECK-CXX: define{{.*}} i64 @_Z8test_s113s11(i64 {{.*}})
+struct s11 { struct { } s; };
+struct s11 test_s11(struct s11 a) {
+  return a;
+}
+
+// CHECK-C: define{{.*}} void @test_s12()
+// CHECK-CXX: define{{.*}} void @_Z8test_s123s12()
+struct s12 { int i[0]; };
+struct s12 test_s12(struct s12 a) {
+  return a;
+}
+
+// CHECK-C: define{{.*}} void @test_s13()
+// CHECK-CXX: define{{.*}} void @_Z8test_s133s13()
+struct s13 { struct { } s[0]; };
+struct s13 test_s13(struct s13 a) {
+  return a;
+}
+
+// CHECK-C: define{{.*}} void @test_s14()
+// CHECK-CXX: define{{.*}} i64 @_Z8test_s143s14(i64 {{.*}})
+struct s14 { struct { } s[1]; };
+struct s14 test_s14(struct s14 a) {
+  return a;
+}
+
+// CHECK-C: define{{.*}} void @test_s15()
+// CHECK-CXX: define{{.*}} void @_Z8test_s153s15()
+struct s15 { int : 0; };
+struct s15 test_s15(struct s15 a) {
+  return a;
+}
+
+// CHECK-C: define{{.*}} void @test_s16()
+// CHECK-CXX: define{{.*}} void @_Z8test_s163s16()
+struct s16 { int : 1; };
+struct s16 test_s16(struct s16 a) {
+  return a;
+}
-- 
2.20.1


From 6248fa0fc405952a8b907624c27b2dd1ee86a962 Mon Sep 17 00:00:00 2001
From: Lu Weining <luweining@loongson.cn>
Date: Tue, 31 Oct 2023 21:18:06 +0800
Subject: [PATCH 4/9] [LoongArch] Fix ABI mismatch with gcc/g++ about empty
 structs passing (#70320)

How empty structs (not as fields of container struct) are passed in C++
is not explicitly documented in psABI. However, this patch fixes the
mismatch with g++.

Note that the unnamed bitfield case `struct { int : 1; }` in C is also
fixed. Previously clang regards it as an empty struct and then ignores
it when passing. Now size of the struct is counted; since it's size is
not 0, clang will not ignore it even in C.

While https://reviews.llvm.org/D156116 fixed the handling of empty
struct when considering eligibility of the container struct for the FP
calling convention ('flattening'), this patch fixes the handling of
passing the empty struct itself.

Fix https://github.com/llvm/llvm-project/issues/70319

(cherry picked from commit 9ca6bf3fb7b7df373723b3275730f101f9ff816b)
---
 clang/lib/CodeGen/Targets/LoongArch.cpp                | 10 ++++++----
 clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c |  8 ++++----
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp
index 7483bf6d6d1e..bc508a99da9c 100644
--- a/clang/lib/CodeGen/Targets/LoongArch.cpp
+++ b/clang/lib/CodeGen/Targets/LoongArch.cpp
@@ -308,12 +308,14 @@ ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
                                            CGCXXABI::RAA_DirectInMemory);
   }
 
-  // Ignore empty structs/unions.
-  if (isEmptyRecord(getContext(), Ty, true))
-    return ABIArgInfo::getIgnore();
-
   uint64_t Size = getContext().getTypeSize(Ty);
 
+  // Ignore empty struct or union whose size is zero, e.g. `struct { }` in C or
+  // `struct { int a[0]; }` in C++. In C++, `struct { }` is empty but it's size
+  // is 1 byte and g++ doesn't ignore it; clang++ matches this behaviour.
+  if (isEmptyRecord(getContext(), Ty, true) && Size == 0)
+    return ABIArgInfo::getIgnore();
+
   // Pass floating point values via FARs if possible.
   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
       FRLen >= Size && FARsLeft) {
diff --git a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
index d0daafac336e..281b7b15841a 100644
--- a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
@@ -93,7 +93,7 @@ struct s9 test_s9(struct s9 a) {
 }
 
 // CHECK-C: define{{.*}} void @test_s10()
-// CHECK-CXX: define{{.*}} void @_Z8test_s103s10()
+// CHECK-CXX: define{{.*}} i64 @_Z8test_s103s10(i64 {{.*}})
 struct s10 { };
 struct s10 test_s10(struct s10 a) {
   return a;
@@ -128,14 +128,14 @@ struct s14 test_s14(struct s14 a) {
 }
 
 // CHECK-C: define{{.*}} void @test_s15()
-// CHECK-CXX: define{{.*}} void @_Z8test_s153s15()
+// CHECK-CXX: define{{.*}} i64 @_Z8test_s153s15(i64 {{.*}})
 struct s15 { int : 0; };
 struct s15 test_s15(struct s15 a) {
   return a;
 }
 
-// CHECK-C: define{{.*}} void @test_s16()
-// CHECK-CXX: define{{.*}} void @_Z8test_s163s16()
+// CHECK-C: define{{.*}} i64 @test_s16(i64 {{.*}})
+// CHECK-CXX: define{{.*}} i64 @_Z8test_s163s16(i64 {{.*}})
 struct s16 { int : 1; };
 struct s16 test_s16(struct s16 a) {
   return a;
-- 
2.20.1


From 028d0d88cd73c724f954577dc90cbbc2873a6832 Mon Sep 17 00:00:00 2001
From: Weining Lu <luweining@loongson.cn>
Date: Thu, 2 Nov 2023 09:29:43 +0800
Subject: [PATCH 5/9] [LoongArch] Pre-commit test for issue #70890

(cherry picked from commit 749083b91f31f370cf64831d3e7e6215b6d51442)
---
 .../LoongArch/abi-lp64d-empty-unions.c        | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c

diff --git a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c
new file mode 100644
index 000000000000..b0607425336e
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple loongarch64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - | \
+// RUN:   FileCheck --check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -triple loongarch64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - -x c++ | \
+// RUN:   FileCheck --check-prefix=CHECK-CXX %s
+
+#include <stdint.h>
+
+// CHECK-C: define{{.*}} void @test1()
+// CHECK-CXX: define{{.*}} i64 @_Z5test12u1(i64{{[^,]*}})
+union u1 { };
+union u1 test1(union u1 a) {
+  return a;
+}
+
+struct s1 {
+  union u1 u;
+  int i;
+  float f;
+};
+
+// CHECK-C: define{{.*}} { i32, float } @test2(i32{{[^,]*}}, float{{[^,]*}})
+/// FIXME: This doesn't match g++.
+// CHECK-CXX: define{{.*}} { i32, float } @_Z5test22s1(i32{{[^,]*}}, float{{[^,]*}})
+struct s1 test2(struct s1 a) {
+  return a;
+}
-- 
2.20.1


From 8c4371c0e53635a23852d0dc7025b4c48495277b Mon Sep 17 00:00:00 2001
From: Lu Weining <luweining@loongson.cn>
Date: Sat, 4 Nov 2023 10:04:37 +0800
Subject: [PATCH 6/9] [LoongArch] Fix ABI mismatch with g++ when handling empty
 unions (#71025)

In g++, empty unions are not ignored like empty structs when flattening
structs to examine whether the structs can be passed via FARs in C++.
This patch aligns clang++ with g++.

Fix https://github.com/llvm/llvm-project/issues/70890.

(cherry picked from commit 4253fdc2c462da61cc0deb74a43265665720c828)
---
 clang/lib/CodeGen/Targets/LoongArch.cpp                | 7 ++++---
 clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c | 2 +-
 clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c  | 3 +--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp
index bc508a99da9c..63b9a1fdb988 100644
--- a/clang/lib/CodeGen/Targets/LoongArch.cpp
+++ b/clang/lib/CodeGen/Targets/LoongArch.cpp
@@ -170,10 +170,11 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
     // copy constructor are not eligible for the FP calling convention.
     if (getRecordArgABI(Ty, CGT.getCXXABI()))
       return false;
-    if (isEmptyRecord(getContext(), Ty, true, true))
-      return true;
     const RecordDecl *RD = RTy->getDecl();
-    // Unions aren't eligible unless they're empty (which is caught above).
+    if (isEmptyRecord(getContext(), Ty, true, true) &&
+        (!RD->isUnion() || !isa<CXXRecordDecl>(RD)))
+      return true;
+    // Unions aren't eligible unless they're empty in C (which is caught above).
     if (RD->isUnion())
       return false;
     const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
diff --git a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
index 281b7b15841a..2f7596f0ebdc 100644
--- a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
@@ -3,7 +3,7 @@
 // RUN: %clang_cc1 -triple loongarch64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - -x c++ | \
 // RUN:   FileCheck --check-prefix=CHECK-CXX %s
 
-// Fields containing empty structs or unions are ignored when flattening
+// Fields containing empty structs are ignored when flattening
 // structs to examine whether the structs can be passed via FARs, even in C++.
 // But there is an exception that non-zero-length array of empty structures are
 // not ignored in C++. These rules are not documented in psABI <https://www.github.com/loongson/la-abi-specs>
diff --git a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c
index b0607425336e..363e37efb646 100644
--- a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-unions.c
@@ -19,8 +19,7 @@ struct s1 {
 };
 
 // CHECK-C: define{{.*}} { i32, float } @test2(i32{{[^,]*}}, float{{[^,]*}})
-/// FIXME: This doesn't match g++.
-// CHECK-CXX: define{{.*}} { i32, float } @_Z5test22s1(i32{{[^,]*}}, float{{[^,]*}})
+// CHECK-CXX: define{{.*}} [2 x i64] @_Z5test22s1([2 x i64]{{[^,]*}})
 struct s1 test2(struct s1 a) {
   return a;
 }
-- 
2.20.1


From 8e855955a009ec398b9f7da88e980dae9d20c420 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i@maskray.me>
Date: Tue, 14 Nov 2023 00:43:40 -0800
Subject: [PATCH 7/9] [Driver] Default LoongArch to
 -fno-direct-access-external-data for non-PIC (#72221)

For -fno-pic, if an extern variable is defined in a DSO, a copy
relocation will be needed. However, loongarch*-linux does not and will
not support copy relocations.

Change Driver to default to -fno-direct-access-external-data for
LoongArch && non-PIC.
Keep Frontend conditions unchanged (-fdirect-access-external-data ||
-fno-direct-access-external-data && PIC>0 => direct access).

Fix #71645

(cherry picked from commit 47eeee297775347cbdb7624d6a766c2a3eec4a59)
---
 clang/lib/Driver/ToolChains/Clang.cpp            | 7 ++++++-
 clang/test/Driver/fdirect-access-external-data.c | 6 ++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6b5930990f11..b21aeaee7f5a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5632,10 +5632,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   // defaults to -fno-direct-access-external-data. Pass the option if different
   // from the default.
   if (Arg *A = Args.getLastArg(options::OPT_fdirect_access_external_data,
-                               options::OPT_fno_direct_access_external_data))
+                               options::OPT_fno_direct_access_external_data)) {
     if (A->getOption().matches(options::OPT_fdirect_access_external_data) !=
         (PICLevel == 0))
       A->render(Args, CmdArgs);
+  } else if (PICLevel == 0 && Triple.isLoongArch()) {
+    // Some targets default to -fno-direct-access-external-data even for
+    // -fno-pic.
+    CmdArgs.push_back("-fno-direct-access-external-data");
+  }
 
   if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) {
     CmdArgs.push_back("-fno-plt");
diff --git a/clang/test/Driver/fdirect-access-external-data.c b/clang/test/Driver/fdirect-access-external-data.c
index f132b1b088af..a6da776e6977 100644
--- a/clang/test/Driver/fdirect-access-external-data.c
+++ b/clang/test/Driver/fdirect-access-external-data.c
@@ -9,6 +9,12 @@
 // RUN: %clang -### -c -target aarch64 %s -fpic 2>&1 | FileCheck %s --check-prefix=DEFAULT
 // RUN: %clang -### -c -target aarch64 %s -fpic -fdirect-access-external-data 2>&1 | FileCheck %s --check-prefix=DIRECT
 
+/// loongarch* targets default to -fno-direct-access-external-data even for -fno-pic.
+// RUN: %clang -### -c --target=loongarch64 -fno-pic %s 2>&1 | FileCheck %s --check-prefix=INDIRECT
+// RUN: %clang -### -c --target=loongarch64 -fpie %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+// RUN: %clang -### -c --target=loongarch32 -fno-pic -fdirect-access-external-data %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+// RUN: %clang -### -c --target=loongarch32 -fpie -fdirect-access-external-data %s 2>&1 | FileCheck %s --check-prefix=DIRECT
+
 // DEFAULT-NOT: direct-access-external-data"
 // DIRECT:      "-fdirect-access-external-data"
 // INDIRECT:    "-fno-direct-access-external-data"
-- 
2.20.1


From 29409970a5c68e20022a05457127102a66abfead Mon Sep 17 00:00:00 2001
From: wanglei <wanglei@loongson.cn>
Date: Tue, 5 Mar 2024 19:44:28 +0800
Subject: [PATCH 8/9] [Clang][LoongArch] Precommit test for fix wrong return
 value type of __iocsrrd_h. NFC

(cherry picked from commit aeda1a6e800e0dd6c91c0332b4db95094ad5b301)
(cherry picked from commit a9ba36c7e7d7fa076f201843e3b826b6c6d7f5ef)
---
 clang/test/CodeGen/LoongArch/intrinsic-la32.c | 29 ++++++++++++++-----
 clang/test/CodeGen/LoongArch/intrinsic-la64.c | 21 ++++++++++++--
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la32.c b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
index 93d54f511a9c..6a8d99880be3 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la32.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
@@ -169,8 +169,8 @@ unsigned int cpucfg(unsigned int a) {
 
 // LA32-LABEL: @rdtime(
 // LA32-NEXT:  entry:
-// LA32-NEXT:    [[TMP0:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimeh.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1:[0-9]+]], !srcloc !2
-// LA32-NEXT:    [[TMP1:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimel.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1]], !srcloc !3
+// LA32-NEXT:    [[TMP0:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimeh.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1:[0-9]+]], !srcloc [[META2:![0-9]+]]
+// LA32-NEXT:    [[TMP1:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimel.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1]], !srcloc [[META3:![0-9]+]]
 // LA32-NEXT:    ret void
 //
 void rdtime() {
@@ -201,13 +201,28 @@ void loongarch_movgr2fcsr(int a) {
   __builtin_loongarch_movgr2fcsr(1, a);
 }
 
-// CHECK-LABEL: @cacop_w(
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A:%.*]], i32 1024)
-// CHECK-NEXT:    tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A]], i32 1024)
-// CHECK-NEXT:    ret void
+// LA32-LABEL: @cacop_w(
+// LA32-NEXT:  entry:
+// LA32-NEXT:    tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A:%.*]], i32 1024)
+// LA32-NEXT:    tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A]], i32 1024)
+// LA32-NEXT:    ret void
 //
 void cacop_w(unsigned long int a) {
   __cacop_w(1, a, 1024);
   __builtin_loongarch_cacop_w(1, a, 1024);
 }
+
+// LA32-LABEL: @iocsrrd_h_result(
+// LA32-NEXT:  entry:
+// LA32-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A:%.*]])
+// LA32-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A]])
+// LA32-NEXT:    [[CONV2:%.*]] = and i32 [[TMP0]], 255
+// LA32-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], [[CONV2]]
+// LA32-NEXT:    [[CONV4:%.*]] = trunc i32 [[ADD]] to i16
+// LA32-NEXT:    ret i16 [[CONV4]]
+//
+unsigned short iocsrrd_h_result(unsigned int a) {
+  unsigned short b = __iocsrrd_h(a);
+  unsigned short c = __builtin_loongarch_iocsrrd_h(a);
+  return b+c;
+}
diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
index a740882eef54..48b6a7a3d227 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -387,7 +387,7 @@ unsigned int cpucfg(unsigned int a) {
 
 // CHECK-LABEL: @rdtime_d(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = tail call { i64, i64 } asm sideeffect "rdtime.d $0, $1\0A\09", "=&r,=&r"() #[[ATTR1:[0-9]+]], !srcloc !2
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call { i64, i64 } asm sideeffect "rdtime.d $0, $1\0A\09", "=&r,=&r"() #[[ATTR1:[0-9]+]], !srcloc [[META2:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 void rdtime_d() {
@@ -396,8 +396,8 @@ void rdtime_d() {
 
 // CHECK-LABEL: @rdtime(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimeh.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1]], !srcloc !3
-// CHECK-NEXT:    [[TMP1:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimel.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1]], !srcloc !4
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimeh.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1]], !srcloc [[META3:![0-9]+]]
+// CHECK-NEXT:    [[TMP1:%.*]] = tail call { i32, i32 } asm sideeffect "rdtimel.w $0, $1\0A\09", "=&r,=&r"() #[[ATTR1]], !srcloc [[META4:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 void rdtime() {
@@ -427,3 +427,18 @@ void loongarch_movgr2fcsr(int a) {
   __movgr2fcsr(1, a);
   __builtin_loongarch_movgr2fcsr(1, a);
 }
+
+// CHECK-LABEL: @iocsrrd_h_result(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A:%.*]])
+// CHECK-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A]])
+// CHECK-NEXT:    [[CONV2:%.*]] = and i32 [[TMP0]], 255
+// CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], [[CONV2]]
+// CHECK-NEXT:    [[CONV4:%.*]] = trunc i32 [[ADD]] to i16
+// CHECK-NEXT:    ret i16 [[CONV4]]
+//
+unsigned short iocsrrd_h_result(unsigned int a) {
+  unsigned short b = __iocsrrd_h(a);
+  unsigned short c = __builtin_loongarch_iocsrrd_h(a);
+  return b+c;
+}
-- 
2.20.1


From 47425dfdd1582ec652aba1c289f3a80fe25c1a8c Mon Sep 17 00:00:00 2001
From: wanglei <wanglei@loongson.cn>
Date: Wed, 6 Mar 2024 10:03:28 +0800
Subject: [PATCH 9/9] [Clang][LoongArch] Fix wrong return value type of
 __iocsrrd_h (#84100)

relate:
https: //gcc.gnu.org/pipermail/gcc-patches/2024-February/645016.html
(cherry picked from commit 2f479b811274fede36535e34ecb545ac22e399c3)
(cherry picked from commit 9b9aee16d4dcf1b4af49988ebd7918fa4ce77e44)
---
 clang/lib/Headers/larchintrin.h               | 2 +-
 clang/test/CodeGen/LoongArch/intrinsic-la32.c | 8 ++++----
 clang/test/CodeGen/LoongArch/intrinsic-la64.c | 8 ++++----
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h
index c5c533ee0b8c..24dd29ce91ff 100644
--- a/clang/lib/Headers/larchintrin.h
+++ b/clang/lib/Headers/larchintrin.h
@@ -156,7 +156,7 @@ extern __inline unsigned char
   return (unsigned char)__builtin_loongarch_iocsrrd_b((unsigned int)_1);
 }
 
-extern __inline unsigned char
+extern __inline unsigned short
     __attribute__((__gnu_inline__, __always_inline__, __artificial__))
     __iocsrrd_h(unsigned int _1) {
   return (unsigned short)__builtin_loongarch_iocsrrd_h((unsigned int)_1);
diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la32.c b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
index 6a8d99880be3..eb3f8cbe7ac4 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la32.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
@@ -215,11 +215,11 @@ void cacop_w(unsigned long int a) {
 // LA32-LABEL: @iocsrrd_h_result(
 // LA32-NEXT:  entry:
 // LA32-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A:%.*]])
+// LA32-NEXT:    [[CONV_I:%.*]] = trunc i32 [[TMP0]] to i16
 // LA32-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A]])
-// LA32-NEXT:    [[CONV2:%.*]] = and i32 [[TMP0]], 255
-// LA32-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], [[CONV2]]
-// LA32-NEXT:    [[CONV4:%.*]] = trunc i32 [[ADD]] to i16
-// LA32-NEXT:    ret i16 [[CONV4]]
+// LA32-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// LA32-NEXT:    [[CONV3:%.*]] = add i16 [[TMP2]], [[CONV_I]]
+// LA32-NEXT:    ret i16 [[CONV3]]
 //
 unsigned short iocsrrd_h_result(unsigned int a) {
   unsigned short b = __iocsrrd_h(a);
diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
index 48b6a7a3d227..50ec358f546e 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -431,11 +431,11 @@ void loongarch_movgr2fcsr(int a) {
 // CHECK-LABEL: @iocsrrd_h_result(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A:%.*]])
+// CHECK-NEXT:    [[CONV_I:%.*]] = trunc i32 [[TMP0]] to i16
 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.loongarch.iocsrrd.h(i32 [[A]])
-// CHECK-NEXT:    [[CONV2:%.*]] = and i32 [[TMP0]], 255
-// CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], [[CONV2]]
-// CHECK-NEXT:    [[CONV4:%.*]] = trunc i32 [[ADD]] to i16
-// CHECK-NEXT:    ret i16 [[CONV4]]
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[CONV3:%.*]] = add i16 [[TMP2]], [[CONV_I]]
+// CHECK-NEXT:    ret i16 [[CONV3]]
 //
 unsigned short iocsrrd_h_result(unsigned int a) {
   unsigned short b = __iocsrrd_h(a);
-- 
2.20.1

