[clang] [llvm] [SystemZ] Do not extend integer arguments in z/OS XPLINK64 ABI (PR #206833)

Zibi Sarbinowski via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 31 08:36:56 PDT 2026


================

----------------
zibi2 wrote:

Here is a concrete cross-compiler test run on z/OS (clang caller, xlc callee):

```
PASS  int 2                       R2D = 0x0000000000000002
PASS  int -1                      R2D = 0x00000000ffffffff
PASS  int 0x7fffffff              R2D = 0x000000007fffffff
PASS  int 0                       R2D = 0x0000000000000000
PASS  int -2147483648             R2D = 0x0000000080000000
```

poison() pre-loads 0xDEADBEEF into the upper 32 bits of R1–R3 before each call. If clang wrote only R2L, the result for int -1 would be 0xDEADBEEFffffffff. It is 0x00000000ffffffff so clang zero-extends into the full 64-bit register.

<details>
<summary>caller.c (clang -m64)</summary>

```
/* passes known int values; clang is the thing under test */
extern void witness_r1(unsigned long long *out, int val);
extern void poison(void);
#define ZX(n) ((unsigned long long)(unsigned int)(n))
static void check(const char *label, int val, unsigned long long expected)
{
    unsigned long long got = 0;
    poison();
    witness_r1(&got, val);
    if (got == expected)
        printf("PASS  %-26s  R2D = 0x%016llx\n", label, got);
    else {
        printf("FAIL  %-26s  R2D = 0x%016llx  expected 0x%016llx\n",
               label, got, expected);
        failures++;
    }
}

int main(void)
{
    check("int 2",           2,           ZX(2));
    check("int -1",         -1,           ZX(-1));
    check("int 0x7fffffff",  0x7fffffff,  ZX(0x7fffffff));
    check("int 0",           0,           ZX(0));
    check("int -2147483648", -2147483648, ZX(-2147483648));
    printf("\n%s\n", failures ? "FAILED" : "ALL PASSED");
    return failures != 0;
}
```

</details><details>
<summary>witness.c (xlc -q64) — captures raw R2D before any prologue</summary>

```
/* parameter is unsigned long long, NOT int -- suppresses xlc's LGFR prologue */
void witness_r1(unsigned long long *out, unsigned long long val) {
    __asm(" stg 2,0(1)");   /* store raw R2D into *out */
}
```

</details> <details>
<summary>poison.c (xlc -q64) — pre-contaminates upper half</summary>

```
void poison(void) {
    __asm(" llihf 1,X'DEADBEEF'");
    __asm(" llihf 2,X'DEADBEEF'");
    __asm(" llihf 3,X'DEADBEEF'");
}
```
</details>

Without last commit the last sub-test would fail as follows:
`FAIL  int -2147483648             R2D = 0xffffffff80000000  expected 0x0000000080000000`

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


More information about the cfe-commits mailing list