https://github.com/zibi2 updated 
https://github.com/llvm/llvm-project/pull/206833

>From a0b48828f1a4b2b3709ba60b8ff129d97dbc62ab Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <[email protected]>
Date: Tue, 30 Jun 2026 16:25:39 -0400
Subject: [PATCH] [SystemZ] Fix signext/zeroext handling in XPLINK64 calling
 convention

For z/OS XPLINK64, the ABI specification mandates that scalar return
values are sign- or zero-extended to 64 bits, but makes no such
guarantee for arguments.  Other compilers (e.g. xlc) do not extend
argument values, so clang was incorrectly emitting a sign-extension
instruction (lgfr) on the callee side for every incoming promotable
integer argument, causing interoperability failures.

Fix:
- In ZOSXPLinkABIInfo::classifyArgumentType(), return getDirect() instead
  of getExtend() for promotable integer types.  This omits the signext/
  zeroext attribute from LLVM IR parameters, so the backend emits no
  extension instruction for incoming arguments (lgr plain copy).
- classifyReturnType() is unchanged: return values still use getExtend()
  because the spec does mandate extension there (lgfr/llgfr emitted).
- The backend CC_XPLINK_Promote_i32 custom handler, SystemZCCState class,
  and isFormalArgLowering machinery are removed; the simple
  CCIfExtend<CCPromoteToType<i64>> rule is restored in CC_SystemZ_XPLINK64
  since IR parameters no longer carry extension flags.

Tests updated:
- clang/test/CodeGen/SystemZ/zos-abi.c: parameter signatures no longer
  carry signext/zeroext; return types still do.
- llvm/test/CodeGen/SystemZ/call-zos-01.ll: pass_char/short/int now emit
  lgr (plain copy) instead of lgfr; pass_integrals0 instruction order
  updated to match.
- llvm/test/CodeGen/SystemZ/call-zos-vararg.ll: vararg integral call
  site emits lg + direct stg, no llgfr zero-extension.
---
 clang/lib/CodeGen/Targets/SystemZ.cpp         | 11 ++++++++--
 clang/test/CodeGen/SystemZ/zos-abi.c          | 22 +++++++++----------
 clang/test/CodeGen/pragma-export.cpp          |  8 +++----
 llvm/lib/Target/SystemZ/SystemZCallingConv.td |  1 +
 4 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp 
b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 37f6b3017f776..84ac63f0f0066 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -822,9 +822,16 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType 
Ty, bool IsNamedArg,
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
                                    RAA == CGCXXABI::RAA_DirectInMemory);
 
-  // Integers and enums are extended to full register width.
+  // Promotable integer arguments are passed without extension attributes.
+  // The XPLINK64 ABI specification mandates that scalar values are widened to
+  // 64 bits only for *return* values, not for arguments; other compilers (e.g.
+  // xlc) do not guarantee the upper bits are sign- or zero-extended on the
+  // caller side.  Omitting signext/zeroext here ensures the backend does not
+  // emit a redundant extension instruction on the callee side and avoids
+  // incorrect code when interoperating with xlc.  Return values still use
+  // getExtend() because the spec does mandate extension there.
   if (isPromotableIntegerTypeForABI(Ty))
-    return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+    return ABIArgInfo::getDirect(CGT.ConvertType(Ty));
 
   // For non-C calling conventions, compound types passed by address copy.
   if ((CallConv != llvm::CallingConv::C) && isCompoundType(Ty))
diff --git a/clang/test/CodeGen/SystemZ/zos-abi.c 
b/clang/test/CodeGen/SystemZ/zos-abi.c
index d7843d9bee089..0eb0e03b49e9d 100644
--- a/clang/test/CodeGen/SystemZ/zos-abi.c
+++ b/clang/test/CodeGen/SystemZ/zos-abi.c
@@ -22,22 +22,22 @@
 // Scalar types
 
 char pass_char(char arg) { return arg; }
-// CHECK-LABEL: define signext i8 @pass_char(i8 signext %{{.*}})
+// CHECK-LABEL: define signext i8 @pass_char(i8 %{{.*}})
 
 signed char pass_schar(signed char arg) { return arg; }
-// CHECK-LABEL: define signext i8 @pass_schar(i8 signext %{{.*}})
+// CHECK-LABEL: define signext i8 @pass_schar(i8 %{{.*}})
 
 unsigned char pass_uchar(unsigned char arg) { return arg; }
-// CHECK-LABEL: define zeroext i8 @pass_uchar(i8 zeroext %{{.*}})
+// CHECK-LABEL: define zeroext i8 @pass_uchar(i8 %{{.*}})
 
 short pass_short(short arg) { return arg; }
-// CHECK-LABEL: define signext i16 @pass_short(i16 signext %{{.*}})
+// CHECK-LABEL: define signext i16 @pass_short(i16 %{{.*}})
 
 int pass_int(int arg) { return arg; }
-// CHECK-LABEL: define signext i32 @pass_int(i32 signext %{{.*}})
+// CHECK-LABEL: define signext i32 @pass_int(i32 %{{.*}})
 
 long pass_long(long arg) { return arg; }
-// CHECK-LABEL: define signext i64 @pass_long(i64 signext %{{.*}})
+// CHECK-LABEL: define signext i64 @pass_long(i64 %{{.*}})
 
 long long pass_longlong(long long arg) { return arg; }
 // CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}})
@@ -53,7 +53,7 @@ long double pass_longdouble(long double arg) { return arg; }
 
 enum Color { Red, Blue };
 enum Color pass_enum(enum Color arg) { return arg; }
-// CHECK-LABEL: define zeroext i32 @pass_enum(i32 zeroext %{{.*}})
+// CHECK-LABEL: define zeroext i32 @pass_enum(i32 %{{.*}})
 
 #ifdef TEST_VEC
 vector unsigned int pass_vector(vector unsigned int arg) { return arg; };
@@ -472,19 +472,19 @@ struct Bad4  pass_Bad4(struct Bad4 arg) { return arg; }
 // ==================================================================
 union tu_char { char a; } __attribute__((transparent_union));
 union tu_char pass_tu_char(union tu_char arg) { return arg; }
-// CHECK-LABEL: define{{.*}} i8 @pass_tu_char(i8 signext %{{.*}})
+// CHECK-LABEL: define{{.*}} i8 @pass_tu_char(i8 %{{.*}})
 
 union tu_short { short a; } __attribute__((transparent_union));
 union tu_short pass_tu_short(union tu_short arg) { return arg; }
-// CHECK-LABEL: define{{.*}} i16 @pass_tu_short(i16 signext %{{.*}})
+// CHECK-LABEL: define{{.*}} i16 @pass_tu_short(i16 %{{.*}})
 
 union tu_int { int a; } __attribute__((transparent_union));
 union tu_int pass_tu_int(union tu_int arg) { return arg; }
-// CHECK-LABEL: define{{.*}} i32 @pass_tu_int(i32 signext %{{.*}})
+// CHECK-LABEL: define{{.*}} i32 @pass_tu_int(i32 %{{.*}})
 
 union tu_long { long a; } __attribute__((transparent_union));
 union tu_long pass_tu_long(union tu_long arg) { return arg; }
-// CHECK-LABEL: define{{.*}} i64 @pass_tu_long(i64 signext %{{.*}})
+// CHECK-LABEL: define{{.*}} i64 @pass_tu_long(i64 %{{.*}})
 
 union tu_ptr { void *a; } __attribute__((transparent_union));
 union tu_ptr pass_tu_ptr(union tu_ptr arg) { return arg; }
diff --git a/clang/test/CodeGen/pragma-export.cpp 
b/clang/test/CodeGen/pragma-export.cpp
index 531afbd659234..f70e64ea7a4ca 100644
--- a/clang/test/CodeGen/pragma-export.cpp
+++ b/clang/test/CodeGen/pragma-export.cpp
@@ -53,10 +53,10 @@ void f10(int) {}
 // CHECK: define hidden void @f0()
 // CHECK: define void @f1()
 // CHECK: define hidden void @_Z2f2dd(double noundef %0, double noundef %1)
-// CHECK: define void @f2(i32 noundef signext %0)
-// CHECK: define hidden void @_Z2f2ii(i32 noundef signext %0, i32 noundef 
signext %1)
+// CHECK: define void @f2(i32 noundef %0)
+// CHECK: define hidden void @_Z2f2ii(i32 noundef %0, i32 noundef %1)
 // CHECK: define hidden void @f3(double noundef %0)
-// CHECK: define hidden void @_Z2f3id(i32 noundef signext %0, double noundef 
%1)
+// CHECK: define hidden void @_Z2f3id(i32 noundef %0, double noundef %1)
 // CHECK: define hidden void @_Z2f3dd(double noundef %0, double noundef %1)
 // CHECK: define hidden void @f2b()
 // CHECK: define hidden void @_Z2t0v()
@@ -65,5 +65,5 @@ void f10(int) {}
 // CHECK: define hidden void @_ZN2N02f5Ev()
 // CHECK: define hidden void @_ZN2N03f5aEv()
 // CHECK: define void @f10(double noundef %0)
-// CHECK: define hidden void @_Z3f10i(i32 noundef signext %0)
+// CHECK: define hidden void @_Z3f10i(i32 noundef %0)
 
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td 
b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index 69202e3fcbc57..df5c02917b16b 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -216,6 +216,7 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
   // XPLINK64 ABI compliant code widens integral types smaller than i64
   // to i64 before placing the parameters either on the stack or in registers.
   CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,
+
   // Promote f32 to f64 and bitcast to i64, if it needs to be passed in GPRs.
   // Although we assign the f32 vararg to be bitcast, it will first be promoted
   // to an f64 within convertValVTToLocVT().

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

Reply via email to