[all-commits] [llvm/llvm-project] 4dce46: [SystemZ] XPLINK64: emit narrow sign/zero-extend i...

Zibi Sarbinowski via All-commits all-commits at lists.llvm.org
Wed Sep 9 10:25:24 PDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 4dce46202961f348bf51a15d73bfe8bcfe8feb28
      https://github.com/llvm/llvm-project/commit/4dce46202961f348bf51a15d73bfe8bcfe8feb28
  Author: Zibi Sarbinowski <zibi at ca.ibm.com>
  Date:   2026-09-09 (Wed, 09 Sep 2026)

  Changed paths:
    M llvm/lib/Target/SystemZ/SystemZCallingConv.td
    M llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
    M llvm/test/CodeGen/SystemZ/call-zos-01.ll
    M llvm/test/CodeGen/SystemZ/call-zos-vararg.ll
    A llvm/test/CodeGen/SystemZ/zos-xplink64-formal-sub64-extend.ll

  Log Message:
  -----------
  [SystemZ] XPLINK64: emit narrow sign/zero-extend instructions for sub-i32 formal args (#206833)

Previously, i8/i16 integer formal arguments with signext/zeroext
attributes were promoted to i64 via CC_XPLINK_Promote_i32 using
LocVT=i64, causing the DAG to select LGFR/LLGFR (word-sized extends) for
all sub-i64 types instead of the narrower byte/halfword forms required
for XL compiler binary compatibility.

Root cause: LLVM type-legalizes i8/i16 to i32 before the CC table runs,
so ValVT is always i32 by the time CC_XPLINK_Promote_i32 is called. The
pre-legalization original type (Ins[i].ArgVT) is the only way to
distinguish i8/i16 formals from i32 formals at that point.

Fix:

- Add ArgOrigVTs to SystemZCCState, populated in AnalyzeFormalArguments
from Ins[i].ArgVT (using MVT::Other as sentinel for non-simple EVTs),
with a getArgOrigVT(ValNo) accessor that returns MVT::Other safely when
called outside AnalyzeFormalArguments (e.g. from AnalyzeCallOperands).

- In CC_XPLINK_Promote_i32 with isFormalArgLowering=true: for original
i8/i16, keep LocVT=i32 (GR32 live-in) only when a GPR is still available
(probed via getFirstUnallocated([R1L,R2L,R3L])). When all GPRs are
taken, the arg goes to an 8-byte stack slot where the caller stores a
sign-extended i64 with the value in bytes 6–7; LocVT=i64 is used in that
case so the full 8 bytes are loaded correctly.

- In LowerFormalArguments: after convertLocVTToValVT, truncate from the
legalized i32 down to the true i8/i16 so the DAG folds the
truncate+extend into a narrow instruction. Guarded by isTargetXPLINK64()
and ArgVT.isSimple().

- Extend CCIfType from [i32] to [i8, i16, i32] in CC_SystemZ_XPLINK64.

Result — callee side:
| Type | Attribute | Before | After |
|------|-----------|--------|-------|
| `i8`  | `signext` | `LGFR` / `LGF`  | `LGBR` / `LGB`   |
| `i8`  | `zeroext` | `LLGFR` / `LLGF` | `LLGCR` / `LLGC` |
| `i16` | `signext` | `LGFR` / `LGF`  | `LGHR` / `LGH`   |
| `i16` | `zeroext` | `LLGFR` / `LLGF` | `LLGHR` / `LLGH` |
| `i32` | `signext` | `LGFR`           | `LGFR` (unchanged) |

Binary compatibility analysis:

The XPLINK64 ABI requires every caller to deliver a fully
sign/zero-extended 64-bit value in the argument register before the
call, regardless of the original type width. This patch only changes the
callee-side re-extension instruction; the caller side (LowerCall /
AnalyzeCallOperands) is unchanged and continues to emit LGFR/LLGFR for
outgoing sub-i32 arguments, or LGB/LGH/LLGC/LLGH when loading directly
from memory.

Because any ABI-compliant caller always delivers a full 64-bit
sign-extended value, bit 7 (for i8) or bit 15 (for i16) is always the
authoritative sign bit in the incoming register. Re-extending from that
bit with LGBR/LGHR yields the same result as LGFR from bit 31. The
matrix below covers all mixed-version combinations:

| Caller | Callee | Register value at call site | Callee re-extension |
Correct? |

|--------|--------|-----------------------------|---------------------|----------|
| Any (memory load) | new | `LGB`/`LGH` → full i64 | `LGBR`/`LGHR` | ✓
bit 7/15 intact |
| Open XL 1.1 | new | full GR64, no extend needed | `LGBR`/`LGHR` | ✓
ABI-compliant i64 |
| Open XL 2.2 | new | `LGFR` → full i64, bit 7 = sign | `LGBR`/`LGHR` |
✓ bit 7 intact |
| new | Open XL 2.2 | `LGFR` (caller side unchanged) | `LGFR` | ✓
identical to before |
| new | Open XL 1.1 | `LGFR` (caller side unchanged) | none (trusts
GR64) | ✓ GR64 is valid |
| Java/JNI | new | no extend (raw GR64 from JVM) | `LGBR`/`LGHR` | ✓ JVM
guarantees full i64 per JNI spec |
| new | Java/JNI | `LGFR` (caller side unchanged) | none | ✓ GR64 is
valid |


No binary incompatibility in any direction.

Adds lit test zos-xplink64-formal-sub64-extend.ll covering all five
integer types, the optnone spill path, and small struct coercion cases.
Updates call-zos-01.ll and call-zos-vararg.ll.



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list