[clang] [compiler-rt] [llvm] Make -funwind-tables the default for SystemZ. (PR #139764)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 28 07:29:46 PDT 2025


https://github.com/anoopkg6 updated https://github.com/llvm/llvm-project/pull/139764

>From e0b15d83e04aebc8f7198af085c6fbe35f5ca7d4 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Tue, 13 May 2025 18:33:15 +0200
Subject: [PATCH 1/3] Make -funwind-tables the default for SystemZ.

---
 clang/lib/Driver/ToolChains/Gnu.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 8397f1121ec2c..73e372537927c 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -3103,6 +3103,7 @@ Generic_GCC::getDefaultUnwindTableLevel(const ArgList &Args) const {
   case llvm::Triple::ppc64le:
   case llvm::Triple::riscv32:
   case llvm::Triple::riscv64:
+  case llvm::Triple::systemz:
   case llvm::Triple::x86:
   case llvm::Triple::x86_64:
     return UnwindTableLevel::Asynchronous;

>From 1e0331d3cf7a93a7be2c3be211f555f19a482874 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Sat, 27 Sep 2025 23:14:37 +0200
Subject: [PATCH 2/3] Add Dataflow Sanitizer support for SystemZ.

---
 clang/lib/Driver/ToolChains/Linux.cpp         |  2 +-
 .../cmake/Modules/AllSupportedArchDefs.cmake  |  3 +-
 compiler-rt/lib/dfsan/dfsan_allocator.cpp     | 16 +++++++++
 compiler-rt/lib/dfsan/dfsan_custom.cpp        | 13 +++++++
 compiler-rt/lib/dfsan/dfsan_platform.h        | 14 ++++++++
 compiler-rt/test/dfsan/custom.cpp             |  2 +-
 compiler-rt/test/dfsan/lit.cfg.py             |  4 ++-
 compiler-rt/test/dfsan/pair.cpp               | 36 ++++++++++++-------
 compiler-rt/test/dfsan/struct.c               | 12 +++----
 .../Instrumentation/DataFlowSanitizer.cpp     | 29 ++++++++++++---
 10 files changed, 105 insertions(+), 26 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 16e35b08cfbd6..0a11f9605b755 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -819,7 +819,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
   Res |= SanitizerKind::KernelAddress;
   Res |= SanitizerKind::Vptr;
   Res |= SanitizerKind::SafeStack;
-  if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64)
+  if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64 || IsSystemZ)
     Res |= SanitizerKind::DataFlow;
   if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 ||
       IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64)
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index ca45d7bd2af7f..2bc695922ef2d 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -35,7 +35,8 @@ set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
     ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
     ${LOONGARCH64})
 set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM64_32})
-set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64})
+set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64}
+    ${S390X})
 set(ALL_RTSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
 
 if(ANDROID)
diff --git a/compiler-rt/lib/dfsan/dfsan_allocator.cpp b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
index 160b1a64d8f6f..700b2fccf9f6c 100644
--- a/compiler-rt/lib/dfsan/dfsan_allocator.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
@@ -44,9 +44,24 @@ struct DFsanMapUnmapCallback {
 // duplicated as MappingDesc::ALLOCATOR in dfsan_platform.h.
 #if defined(__aarch64__)
 const uptr kAllocatorSpace = 0xE00000000000ULL;
+#elif defined(__s390x__)
+const uptr kAllocatorSpace = 0x440000000000ULL;
 #else
 const uptr kAllocatorSpace = 0x700000000000ULL;
 #endif
+#if defined(__s390x__)
+const uptr kMaxAllowedMallocSize = 2UL << 30;  // 2G
+
+struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
+  static const uptr kSpaceBeg = kAllocatorSpace;
+  static const uptr kSpaceSize = 0x020000000000;  // 2T.
+  static const uptr kMetadataSize = sizeof(Metadata);
+  using SizeClassMap = DefaultSizeClassMap;
+  using MapUnmapCallback = DFsanMapUnmapCallback;
+  static const uptr kFlags = 0;
+  using AddressSpaceView = LocalAddressSpaceView;
+};
+#else
 const uptr kMaxAllowedMallocSize = 1ULL << 40;
 
 struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
@@ -59,6 +74,7 @@ struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
   using AddressSpaceView = LocalAddressSpaceView;
 };
 
+#endif
 typedef SizeClassAllocator64<AP64> PrimaryAllocator;
 
 typedef CombinedAllocator<PrimaryAllocator> Allocator;
diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp
index dbc00d7ac3ea3..b060e5c56edbe 100644
--- a/compiler-rt/lib/dfsan/dfsan_custom.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp
@@ -2332,7 +2332,20 @@ static int format_buffer(char *str, size_t size, const char *fmt,
         case 'g':
         case 'G':
           if (*(formatter.fmt_cur - 1) == 'L') {
+#if defined(__s390x__)
+            // SystemZ treats float128 argument as an aggregate type and copies
+            // shadow and Origin to passed argument temporary. But passed
+            // argument va_labels and va_origins are zero. Here. we get
+            // Shadow/Origin corresponding to in-memory argument and update
+            // va_labels and va_origins.
+            long double* arg = va_arg(ap, long double*);
+            *va_labels = *shadow_for(arg);
+            if (va_origins != nullptr)
+              *va_origins = *origin_for(arg);
+            retval = formatter.format(*arg);
+#else
             retval = formatter.format(va_arg(ap, long double));
+#endif
           } else {
             retval = formatter.format(va_arg(ap, double));
           }
diff --git a/compiler-rt/lib/dfsan/dfsan_platform.h b/compiler-rt/lib/dfsan/dfsan_platform.h
index 01f0de47d960d..7e6a1dafddb50 100644
--- a/compiler-rt/lib/dfsan/dfsan_platform.h
+++ b/compiler-rt/lib/dfsan/dfsan_platform.h
@@ -67,6 +67,20 @@ const MappingDesc kMemoryLayout[] = {
 };
 #    define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0xB00000000000ULL)
 #    define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x200000000000ULL)
+#  elif SANITIZER_LINUX && SANITIZER_S390_64
+const MappingDesc kMemoryLayout[] = {
+    {0x000000000000ULL, 0x040000000000ULL, MappingDesc::APP, "low memory"},
+    {0x040000000000ULL, 0x080000000000ULL, MappingDesc::INVALID, "invalid"},
+    {0x080000000000ULL, 0x180000000000ULL, MappingDesc::SHADOW, "shadow"},
+    {0x180000000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
+    {0x1C0000000000ULL, 0x2C0000000000ULL, MappingDesc::ORIGIN, "origin"},
+    {0x2C0000000000ULL, 0x440000000000ULL, MappingDesc::INVALID, "invalid"},
+    {0x440000000000ULL, 0x460000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
+    {0x460000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}};
+
+#    define MEM_TO_SHADOW(mem) \
+      ((((uptr)(mem)) & ~0xC00000000000ULL) + 0x080000000000ULL)
+#    define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x140000000000ULL)
 
 #  else
 // All of the following configurations are supported.
diff --git a/compiler-rt/test/dfsan/custom.cpp b/compiler-rt/test/dfsan/custom.cpp
index 873af5cd934e2..b4d6b186cb61e 100644
--- a/compiler-rt/test/dfsan/custom.cpp
+++ b/compiler-rt/test/dfsan/custom.cpp
@@ -2240,7 +2240,7 @@ void test_sscanf() {
   strcpy(input_buf, "-559038737");
   test_sscanf_chunk(-559038737, "%d", input_ptr, 1);
   strcpy(input_buf, "3735928559");
-  test_sscanf_chunk(3735928559, "%u", input_ptr, 1);
+  test_sscanf_chunk(3735928559, "%lu", input_ptr, 1);
   strcpy(input_buf, "12345");
   test_sscanf_chunk(12345, "%i", input_ptr, 1);
   strcpy(input_buf, "0751");
diff --git a/compiler-rt/test/dfsan/lit.cfg.py b/compiler-rt/test/dfsan/lit.cfg.py
index b26ff3e367942..edf11a5bed487 100644
--- a/compiler-rt/test/dfsan/lit.cfg.py
+++ b/compiler-rt/test/dfsan/lit.cfg.py
@@ -10,6 +10,8 @@
 
 # Setup default compiler flags used with -fsanitize=dataflow option.
 clang_dfsan_cflags = ["-fsanitize=dataflow"] + [config.target_cflags]
+if config.target_arch == "s390x":
+    clang_dfsan_cflags.append("-mbackchain")
 
 clang_dfsan_cxxflags = config.cxx_mode_flags + clang_dfsan_cflags
 
@@ -25,5 +27,5 @@ def build_invocation(compile_flags):
 config.suffixes = [".c", ".cpp"]
 
 # DataFlowSanitizer tests are currently supported on Linux only.
-if not (config.target_os in ["Linux"] and config.target_arch in ["aarch64", "x86_64", "loongarch64"]):
+if not (config.target_os in ["Linux"] and config.target_arch in ["aarch64", "x86_64", "loongarch64", "s390x"]):
     config.unsupported = True
diff --git a/compiler-rt/test/dfsan/pair.cpp b/compiler-rt/test/dfsan/pair.cpp
index 94bbfc72bc649..cb00339e81ec4 100644
--- a/compiler-rt/test/dfsan/pair.cpp
+++ b/compiler-rt/test/dfsan/pair.cpp
@@ -66,8 +66,10 @@ void test_simple_constructors() {
   int *ptr1 = pair1.first;
 
 #ifdef O0
-  assert(dfsan_read_label(&i1, sizeof(i1)) == 10);
-  assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 10);
+  assert(dfsan_read_label(&i1, sizeof(i1)) == 8 ||
+         dfsan_read_label(&i1, sizeof(i1)) == 10);
+  assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 2 ||
+         dfsan_read_label(&ptr1, sizeof(ptr1)) == 10);
 #else
   assert(dfsan_read_label(&i1, sizeof(i1)) == 8);
   assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 2);
@@ -78,8 +80,10 @@ void test_simple_constructors() {
   int *ptr2 = pair2.first;
 
 #ifdef O0
-  assert(dfsan_read_label(&i2, sizeof(i2)) == 10);
-  assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 10);
+  assert(dfsan_read_label(&i2, sizeof(i2)) == 8 ||
+         dfsan_read_label(&i2, sizeof(i2)) == 10);
+  assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 2 ||
+         dfsan_read_label(&ptr2, sizeof(ptr2)) == 10);
 #else
   assert(dfsan_read_label(&i2, sizeof(i2)) == 8);
   assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 2);
@@ -90,8 +94,10 @@ void test_simple_constructors() {
   int *ptr3 = pair3.first;
 
 #ifdef O0
-  assert(dfsan_read_label(&i3, sizeof(i3)) == 10);
-  assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 10);
+  assert(dfsan_read_label(&i3, sizeof(i3)) == 8 ||
+         dfsan_read_label(&i3, sizeof(i3)) == 10);
+  assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 2 ||
+         dfsan_read_label(&ptr3, sizeof(ptr3)) == 10);
 #else
   assert(dfsan_read_label(&i3, sizeof(i3)) == 8);
   assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 2);
@@ -102,8 +108,10 @@ void test_simple_constructors() {
   int *ptr4 = pair4.first;
 
 #ifdef O0
-  assert(dfsan_read_label(&i4, sizeof(i4)) == 10);
-  assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 10);
+  assert(dfsan_read_label(&i4, sizeof(i4)) == 8 ||
+         dfsan_read_label(&i4, sizeof(i4)) == 10);
+  assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 2 ||
+         dfsan_read_label(&ptr4, sizeof(ptr4)) == 10);
 #else
   assert(dfsan_read_label(&i4, sizeof(i4)) == 8);
   assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 2);
@@ -140,8 +148,10 @@ void test_branches() {
     {
       std::pair<const char *, uint32_t> r = return_ptr_and_i32(q, res);
 #ifdef O0
-      assert(dfsan_read_label(&r.first, sizeof(r.first)) == 10);
-      assert(dfsan_read_label(&r.second, sizeof(r.second)) == 10);
+      assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2 ||
+             dfsan_read_label(&r.first, sizeof(r.first)) == 10);
+      assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8 ||
+             dfsan_read_label(&r.second, sizeof(r.second)) == 10);
 #else
       assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2);
       assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8);
@@ -151,8 +161,10 @@ void test_branches() {
     {
       std::pair<const char *, uint64_t> r = return_ptr_and_i64(q, res);
 #ifdef O0
-      assert(dfsan_read_label(&r.first, sizeof(r.first)) == 10);
-      assert(dfsan_read_label(&r.second, sizeof(r.second)) == 10);
+      assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2 ||
+             dfsan_read_label(&r.first, sizeof(r.first)) == 10);
+      assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8 ||
+             dfsan_read_label(&r.second, sizeof(r.second)) == 10);
 #else
       assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2);
       assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8);
diff --git a/compiler-rt/test/dfsan/struct.c b/compiler-rt/test/dfsan/struct.c
index 7ba0016f7beee..48285e022a98a 100644
--- a/compiler-rt/test/dfsan/struct.c
+++ b/compiler-rt/test/dfsan/struct.c
@@ -48,8 +48,8 @@ int main(void) {
   dfsan_label i1_label = dfsan_read_label(&i1, sizeof(i1));
   dfsan_label ptr1_label = dfsan_read_label(&ptr1, sizeof(ptr1));
 #if defined(O0)
-  assert(i1_label == (i_label | ptr_label));
-  assert(ptr1_label == (i_label | ptr_label));
+  assert(i1_label == i_label || i1_label == (i_label | ptr_label));
+  assert(ptr1_label == ptr_label || ptr1_label == (i_label | ptr_label));
 #else
   assert(i1_label == i_label);
   assert(ptr1_label == ptr_label);
@@ -62,8 +62,8 @@ int main(void) {
   dfsan_label i2_label = dfsan_read_label(&i2, sizeof(i2));
   dfsan_label ptr2_label = dfsan_read_label(&ptr2, sizeof(ptr2));
 #if defined(O0)
-  assert(i2_label == (i_label | ptr_label));
-  assert(ptr2_label == (i_label | ptr_label));
+  assert(i2_label == i_label || i2_label == (i_label | ptr_label));
+  assert(ptr2_label == ptr_label || ptr2_label == (i_label | ptr_label));
 #else
   assert(i2_label == i_label);
   assert(ptr2_label == ptr_label);
@@ -76,8 +76,8 @@ int main(void) {
   dfsan_label i3_label = dfsan_read_label(&i3, sizeof(i3));
   dfsan_label ptr3_label = dfsan_read_label(&ptr3, sizeof(ptr3));
 #if defined(O0)
-  assert(i3_label == (i_label | ptr_label));
-  assert(ptr3_label == (i_label | ptr_label));
+  assert(i3_label == i_label || i3_label == (i_label | ptr_label));
+  assert(ptr3_label == ptr_label || ptr3_label == (i_label | ptr_label));
 #else
   assert(i3_label == i_label);
   assert(ptr3_label == ptr_label);
diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
index 61fef1387d82a..64b3f5c812b3b 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -313,6 +313,14 @@ const MemoryMapParams Linux_LoongArch64_MemoryMapParams = {
     0x100000000000, // OriginBase
 };
 
+// s390x Linux
+const MemoryMapParams Linux_S390X_MemoryMapParams = {
+    0xC00000000000, // AndMask
+    0,              // XorMask (not used)
+    0x080000000000, // ShadowBase
+    0x1C0000000000, // OriginBase
+};
+
 namespace {
 
 class DFSanABIList {
@@ -1141,6 +1149,9 @@ bool DataFlowSanitizer::initializeModule(Module &M) {
   case Triple::loongarch64:
     MapParams = &Linux_LoongArch64_MemoryMapParams;
     break;
+  case Triple::systemz:
+    MapParams = &Linux_S390X_MemoryMapParams;
+    break;
   default:
     report_fatal_error("unsupported architecture");
   }
@@ -1951,8 +1962,12 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
 Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
                                            BasicBlock::iterator Pos) {
   IRBuilder<> IRB(Pos->getParent(), Pos);
-  Value *ShadowOffset = getShadowOffset(Addr, IRB);
-  return getShadowAddress(Addr, Pos, ShadowOffset);
+  Value *ShadowAddr = getShadowOffset(Addr, IRB);
+  uint64_t ShadowBase = MapParams->ShadowBase;
+  if (ShadowBase != 0)
+    ShadowAddr =
+        IRB.CreateAdd(ShadowAddr, ConstantInt::get(IntptrTy, ShadowBase));
+  return getShadowAddress(Addr, Pos, ShadowAddr);
 }
 
 Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2,
@@ -2181,8 +2196,14 @@ std::pair<Value *, Value *> DFSanFunction::loadShadowFast(
       // and then the entire shadow for the second origin pointer (which will be
       // chosen by combineOrigins() iff the least-significant half of the wide
       // shadow was empty but the other half was not).
-      Value *WideShadowLo = IRB.CreateShl(
-          WideShadow, ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2));
+      Value *WideShadowLo =
+          F->getParent()->getDataLayout().isLittleEndian()
+              ? IRB.CreateShl(
+                    WideShadow,
+                    ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2))
+              : IRB.CreateAnd(
+                    WideShadow,
+                    ConstantInt::get(WideShadowTy, 0xFFFFFFFF00000000ULL));
       Shadows.push_back(WideShadow);
       Origins.push_back(DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr));
 

>From 25e54cdc6dc709645368d6589bba19ddccb9605a Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Sun, 28 Sep 2025 16:28:44 +0200
Subject: [PATCH 3/3] Fix for python code formatter, darker issue.

---
 compiler-rt/test/dfsan/lit.cfg.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/test/dfsan/lit.cfg.py b/compiler-rt/test/dfsan/lit.cfg.py
index edf11a5bed487..1b4ca6a258bba 100644
--- a/compiler-rt/test/dfsan/lit.cfg.py
+++ b/compiler-rt/test/dfsan/lit.cfg.py
@@ -27,5 +27,8 @@ def build_invocation(compile_flags):
 config.suffixes = [".c", ".cpp"]
 
 # DataFlowSanitizer tests are currently supported on Linux only.
-if not (config.target_os in ["Linux"] and config.target_arch in ["aarch64", "x86_64", "loongarch64", "s390x"]):
+if not (
+    config.target_os in ["Linux"]
+    and config.target_arch in ["aarch64", "x86_64", "loongarch64", "s390x"]
+):
     config.unsupported = True



More information about the llvm-commits mailing list