[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