https://github.com/doac created https://github.com/llvm/llvm-project/pull/235662

32-bit unsigned integer division is done by first writing 0 to %y (the high 
bits for a 64-bit value) and then using the udiv instruction. This means that 
an inline assembly block that writes to %y could be placed between these two 
instructions as it is not possible mark %y as clobbered in either GCC or Clang. 
In GCC the two instructions for division are treated as one atomic unit and 
there the problem does not appear.

When compiling gmp an inline assembly block that wrote to %y got placed between 
the two instructions for the division and caused an error. (using leon5 
scheduling not upstreamed yet)

Always treating inline assembly as clobbering %y allows the code to work for 
both GCC and Clang.

Assisted-by: Claude

>From 9162292de74bdca4ea64a99177328b260e2bbd6f Mon Sep 17 00:00:00 2001
From: Daniel Cederman <[email protected]>
Date: Tue, 6 Oct 2026 11:01:14 +0200
Subject: [PATCH] [Clang][SPARC] Treat the Y register as clobbered by inline
 assembly

32-bit unsigned integer division is done by first writing 0 to %y
(the high bits for a 64-bit value) and then using the udiv
instruction. This means that an inline assembly block that
writes to %y could be placed between these two instructions as
it is not possible mark %y as clobbered in either GCC or Clang.
In GCC the two instructions for division are treated as one
atomic unit and there the problem does not appear.

When compiling gmp an inline assembly block that wrote to %y got
placed between the two instructions for the division and caused
an error.

Always treating inline assembly as clobbering %y allows the code
to work for both GCC and Clang.

Assisted-by: Claude
---
 clang/lib/Basic/Targets/Sparc.h                |  5 +----
 clang/test/CodeGen/Sparc/inline-asm-gcc-regs.c | 14 ++++++++++++--
 clang/test/CodeGen/Sparc/sparcv8-inline-asm.c  | 12 ++++++------
 clang/test/CodeGen/Sparc/sparcv9-inline-asm.c  | 10 +++++-----
 4 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h
index 2219ccf7c70a37..1206fb433c9b6c 100644
--- a/clang/lib/Basic/Targets/Sparc.h
+++ b/clang/lib/Basic/Targets/Sparc.h
@@ -77,10 +77,7 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public 
TargetInfo {
     }
     return false;
   }
-  std::string_view getClobbers() const override {
-    // FIXME: Implement!
-    return "";
-  }
+  std::string_view getClobbers() const override { return "~{y}"; }
 
   // No Sparc V7 for now, the backend doesn't support it anyway.
   enum CPUKind {
diff --git a/clang/test/CodeGen/Sparc/inline-asm-gcc-regs.c 
b/clang/test/CodeGen/Sparc/inline-asm-gcc-regs.c
index cf83b9afda4b29..4d523343ad75c7 100644
--- a/clang/test/CodeGen/Sparc/inline-asm-gcc-regs.c
+++ b/clang/test/CodeGen/Sparc/inline-asm-gcc-regs.c
@@ -1,13 +1,23 @@
 // RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm %s -o - | 
FileCheck %s
+// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | 
FileCheck %s
+
+// Every inline assembly statement clobbers the Y register, since code written
+// for GCC can write it without listing it.
+
+// CHECK-LABEL: @none
+// CHECK: call void asm sideeffect "nop", "~{y}"()
+void none() {
+  __asm__ __volatile__("nop");
+}
 
 // CHECK-LABEL: @icc
-// CHECK: call void asm sideeffect "nop", "~{icc}"()
+// CHECK: call void asm sideeffect "nop", "~{icc},~{y}"()
 void icc() {
   __asm__ __volatile__("nop" ::: "icc");
 }
 
 // CHECK-LABEL: @fcc
-// CHECK: call void asm sideeffect "nop", "~{fcc0},~{fcc1},~{fcc2},~{fcc3}"()
+// CHECK: call void asm sideeffect "nop", 
"~{fcc0},~{fcc1},~{fcc2},~{fcc3},~{y}"()
 void fcc() {
   __asm__ __volatile__("nop" ::: "fcc0", "fcc1", "fcc2", "fcc3");
 }
diff --git a/clang/test/CodeGen/Sparc/sparcv8-inline-asm.c 
b/clang/test/CodeGen/Sparc/sparcv8-inline-asm.c
index f690c9e432397c..ba89083155bf8c 100644
--- a/clang/test/CodeGen/Sparc/sparcv8-inline-asm.c
+++ b/clang/test/CodeGen/Sparc/sparcv8-inline-asm.c
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm %s -o - | 
FileCheck %s
 
 // CHECK: define{{.*}} float @fabsf(float noundef %a)
-// CHECK: %{{.*}} = call float asm sideeffect "fabss $1, $0;", "=e,f"(float 
%{{.*}})
+// CHECK: %{{.*}} = call float asm sideeffect "fabss $1, $0;", 
"=e,f,~{y}"(float %{{.*}})
 float fabsf(float a) {
   float res;
   __asm __volatile__("fabss  %1, %0;"
@@ -24,19 +24,19 @@ void test_gcc_registers(void) {
 
     // Test remapping register names in register ... asm("rN") statments.
 
-    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r14},{r14},{r14}"
+    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r14},{r14},{r14},~{y}"
     asm volatile("add %0,%1,%2" : : "r" (regO6), "r" (regSP), "r" (reg14));
 
-    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r30},{r30},{r30}"
+    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r30},{r30},{r30},~{y}"
     asm volatile("add %0,%1,%2" : : "r" (regI6), "r" (regFP), "r" (reg30));
 
-     // CHECK: call void asm sideeffect "fadds $0,$1,$2", "{f20},{f20},{f20}"
+     // CHECK: call void asm sideeffect "fadds $0,$1,$2", 
"{f20},{f20},{f20},~{y}"
     asm volatile("fadds %0,%1,%2" : : "f" (fF20), "f" (fF20), "f"(fF20));
 
-    // CHECK: call void asm sideeffect "faddd $0,$1,$2", "{f20},{f20},{f20}"
+    // CHECK: call void asm sideeffect "faddd $0,$1,$2", 
"{f20},{f20},{f20},~{y}"
     asm volatile("faddd %0,%1,%2" : : "f" (dF20), "f" (dF20), "f"(dF20));
 
-    // CHECK: call void asm sideeffect "faddq $0,$1,$2", "{f20},{f20},{f20}"
+    // CHECK: call void asm sideeffect "faddq $0,$1,$2", 
"{f20},{f20},{f20},~{y}"
     asm volatile("faddq %0,%1,%2" : : "f" (qF20), "f" (qF20), "f"(qF20));
 
 }
diff --git a/clang/test/CodeGen/Sparc/sparcv9-inline-asm.c 
b/clang/test/CodeGen/Sparc/sparcv9-inline-asm.c
index 3a7ef0ea86e731..ce834e25bf378e 100644
--- a/clang/test/CodeGen/Sparc/sparcv9-inline-asm.c
+++ b/clang/test/CodeGen/Sparc/sparcv9-inline-asm.c
@@ -14,19 +14,19 @@ void test_gcc_registers(void) {
 
     // Test remapping register names in register ... asm("rN") statments.
 
-    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r14},{r14},{r14}"
+    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r14},{r14},{r14},~{y}"
     asm volatile("add %0,%1,%2" : : "r" (regO6), "r" (regSP), "r" (reg14));
 
-    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r30},{r30},{r30}"
+    // CHECK: call void asm sideeffect "add $0,$1,$2", "{r30},{r30},{r30},~{y}"
     asm volatile("add %0,%1,%2" : : "r" (regI6), "r" (regFP), "r" (reg30));
 
-    // CHECK: call void asm sideeffect "fadds $0,$1,$2", "{f20},{f20},{f20}"
+    // CHECK: call void asm sideeffect "fadds $0,$1,$2", 
"{f20},{f20},{f20},~{y}"
     asm volatile("fadds %0,%1,%2" : : "f" (fF20), "f" (fF20), "f"(fF20));
 
-    // CHECK: call void asm sideeffect "faddd $0,$1,$2", "{f40},{f40},{f40}"
+    // CHECK: call void asm sideeffect "faddd $0,$1,$2", 
"{f40},{f40},{f40},~{y}"
     asm volatile("faddd %0,%1,%2" : : "f" (dF40), "f" (dF40), "f"(dF40));
 
-    // CHECK: call void asm sideeffect "faddq $0,$1,$2", "{f40},{f40},{f40}"
+    // CHECK: call void asm sideeffect "faddq $0,$1,$2", 
"{f40},{f40},{f40},~{y}"
     asm volatile("faddq %0,%1,%2" : : "f" (qF40), "f" (qF40), "f"(qF40));
 
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to