[llvm] [SystemZ] Handle IR struct arguments correctly. (PR #169583)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 25 16:06:47 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-systemz
Author: Jonas Paulsson (JonPsson1)
<details>
<summary>Changes</summary>
Passing IR struct arguments is not illegal, although it is a break against the ABI. This has been left unhandled until interest emerged recently with #<!-- -->168460.
There where two problems that needed to be fixed:
- The size of the stack slot was previously computed by using the original type, but that doesn't work for a struct.
- All the members of a struct have the same OrigArgIndex, so it doesn't work to assume that following parts belong to a split argument until another OrigArgIndex is encountered.
I think it's safe to say that even though it is possible that this may have worked in some cases previously it has been quite broken and needs to be fixed. Here are some examples of generated code (main <> patch):
```
; Incorrectly handling the second element as being part of the first one.The
; loop with OrigArgIndex includes the second element as part of the first one
; since all the elements have the same OrigArgIndex.
%Ty2 = type {i128, i128}
define fastcc void @<!-- -->fun2(%Ty2 %A) {
store %Ty2 %A, ptr null
ret void
}
fun2: fun2:
.cfi_startproc .cfi_startproc
# %bb.0: # %bb.0:
lg %r0, 24(%r2) | lg %r0, 8(%r3)
lg %r1, 16(%r2) | lg %r1, 0(%r3)
lg %r3, 8(%r2) lg %r3, 8(%r2)
lg %r2, 0(%r2) lg %r2, 0(%r2)
stg %r0, 24 stg %r0, 24
stg %r1, 16 stg %r1, 16
stg %r3, 8 stg %r3, 8
stg %r2, 0 stg %r2, 0
br %r14 br %r14
```
```
; Same, but incorrect handling of the second i32 element, which should be
; passed in register.
%Ty3 = type {i128, i32}
define fastcc void @<!-- -->fun3(%Ty3 %A) {
store %Ty3 %A, ptr null
ret void
}
fun3: fun3:
.cfi_startproc .cfi_startproc
# %bb.0: # %bb.0:
lg %r0, 8(%r2) lg %r0, 8(%r2)
lg %r1, 0(%r2) lg %r1, 0(%r2)
l %r2, 16(%r2) | st %r3, 16
stg %r0, 8 stg %r0, 8
stg %r1, 0 stg %r1, 0
st %r2, 16 <
br %r14 br %r14
```
```
; Assertion `Ins[I].PartOffset == 0' fails as it is (unfortunately) set up by
; LowerArguments() to be relative the whole struct, i.e. 4 in this case.
%Ty4 = type {i32, i128}
define fastcc void @<!-- -->fun4(%Ty4 %A) {
store %Ty4 %A, ptr null
ret void
}
> fun4:
> .cfi_startproc
> # %bb.0:
> lg %r0, 8(%r3)
> lg %r1, 0(%r3)
> st %r2, 0
> stg %r0, 16
> stg %r1, 8
> br %r14
```
---
Full diff: https://github.com/llvm/llvm-project/pull/169583.diff
2 Files Affected:
- (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.cpp (+53-25)
- (added) llvm/test/CodeGen/SystemZ/args-22.ll (+321)
``````````diff
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index eb93024bed35c..ab22c0efa8454 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1970,6 +1970,28 @@ SDValue SystemZTargetLowering::joinRegisterPartsIntoValue(
return SDValue();
}
+// The first part of a split stack argument is at index I in Args (and
+// ArgLocs). Return the type of a part and the number of them by reference.
+template <class ArgTy>
+static bool analyzeArgSplit(const SmallVectorImpl<ArgTy> &Args,
+ SmallVector<CCValAssign, 16> &ArgLocs, unsigned I,
+ MVT &PartVT, unsigned &NumParts) {
+ if (!Args[I].Flags.isSplit())
+ return false;
+ assert(I < ArgLocs.size() && ArgLocs.size() == Args.size() &&
+ "ArgLocs havoc.");
+ PartVT = ArgLocs[I].getValVT();
+ NumParts = 1;
+ for (unsigned PartIdx = I + 1;; ++PartIdx) {
+ assert(PartIdx != ArgLocs.size() && "SplitEnd not found.");
+ assert(ArgLocs[PartIdx].getValVT() == PartVT && "Unsupported split.");
+ ++NumParts;
+ if (Args[PartIdx].Flags.isSplitEnd())
+ break;
+ }
+ return true;
+}
+
SDValue SystemZTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
@@ -2074,16 +2096,26 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
MachinePointerInfo()));
// If the original argument was split (e.g. i128), we need
// to load all parts of it here (using the same address).
- unsigned ArgIndex = Ins[I].OrigArgIndex;
- assert (Ins[I].PartOffset == 0);
- while (I + 1 != E && Ins[I + 1].OrigArgIndex == ArgIndex) {
- CCValAssign &PartVA = ArgLocs[I + 1];
- unsigned PartOffset = Ins[I + 1].PartOffset;
- SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue,
- DAG.getIntPtrConstant(PartOffset, DL));
- InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
- MachinePointerInfo()));
- ++I;
+ MVT PartVT;
+ unsigned NumParts;
+ if (analyzeArgSplit(Ins, ArgLocs, I, PartVT, NumParts)) {
+ // TODO: It is strange that while LowerCallTo() sets the PartOffset
+ // relative to the first split part LowerArguments() sets the offset
+ // from the beginning of the struct. So with {i32, i256}, the
+ // PartOffset for the i256 parts are differently handled. Try to
+ // remove that difference and use PartOffset directly here (instead
+ // of SplitBaseOffs).
+ unsigned SplitBaseOffs = Ins[I].PartOffset;
+ for (unsigned PartIdx = 1; PartIdx < NumParts; ++PartIdx) {
+ ++I;
+ CCValAssign &PartVA = ArgLocs[I];
+ unsigned PartOffset = Ins[I].PartOffset - SplitBaseOffs;
+ SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue,
+ DAG.getIntPtrConstant(PartOffset, DL));
+ InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
+ MachinePointerInfo()));
+ assert(PartOffset && "Offset should be non-zero.");
+ }
}
} else
InVals.push_back(convertLocVTToValVT(DAG, DL, VA, Chain, ArgValue));
@@ -2319,18 +2351,13 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
if (VA.getLocInfo() == CCValAssign::Indirect) {
// Store the argument in a stack slot and pass its address.
- unsigned ArgIndex = Outs[I].OrigArgIndex;
EVT SlotVT;
- if (I + 1 != E && Outs[I + 1].OrigArgIndex == ArgIndex) {
- // Allocate the full stack space for a promoted (and split) argument.
- Type *OrigArgType = CLI.Args[Outs[I].OrigArgIndex].Ty;
- EVT OrigArgVT = getValueType(MF.getDataLayout(), OrigArgType);
- MVT PartVT = getRegisterTypeForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
- unsigned N = getNumRegistersForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
- SlotVT = EVT::getIntegerVT(Ctx, PartVT.getSizeInBits() * N);
- } else {
+ MVT PartVT;
+ unsigned NumParts = 1;
+ if (analyzeArgSplit(Outs, ArgLocs, I, PartVT, NumParts))
+ SlotVT = EVT::getIntegerVT(Ctx, PartVT.getSizeInBits() * NumParts);
+ else
SlotVT = Outs[I].VT;
- }
SDValue SpillSlot = DAG.CreateStackTemporary(SlotVT);
int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
MemOpChains.push_back(
@@ -2338,18 +2365,19 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
MachinePointerInfo::getFixedStack(MF, FI)));
// If the original argument was split (e.g. i128), we need
// to store all parts of it here (and pass just one address).
- assert (Outs[I].PartOffset == 0);
- while (I + 1 != E && Outs[I + 1].OrigArgIndex == ArgIndex) {
- SDValue PartValue = OutVals[I + 1];
- unsigned PartOffset = Outs[I + 1].PartOffset;
+ assert(Outs[I].PartOffset == 0);
+ for (unsigned PartIdx = 1; PartIdx < NumParts; ++PartIdx) {
+ ++I;
+ SDValue PartValue = OutVals[I];
+ unsigned PartOffset = Outs[I].PartOffset;
SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot,
DAG.getIntPtrConstant(PartOffset, DL));
MemOpChains.push_back(
DAG.getStore(Chain, DL, PartValue, Address,
MachinePointerInfo::getFixedStack(MF, FI)));
+ assert(PartOffset && "Offset should be non-zero.");
assert((PartOffset + PartValue.getValueType().getStoreSize() <=
SlotVT.getStoreSize()) && "Not enough space for argument part!");
- ++I;
}
ArgValue = SpillSlot;
} else
diff --git a/llvm/test/CodeGen/SystemZ/args-22.ll b/llvm/test/CodeGen/SystemZ/args-22.ll
new file mode 100644
index 0000000000000..39f7ff5dffe4b
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/args-22.ll
@@ -0,0 +1,321 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z16 | FileCheck %s --check-prefix=VECTOR
+;
+; Test passing IR struct arguments, which do not adhere to the ABI but are
+; split up with each element passed like a separate argument.
+
+%Ty0 = type {i128}
+define fastcc void @fun0(%Ty0 %A) {
+; CHECK-LABEL: fun0:
+; CHECK: # %bb.0:
+; CHECK-NEXT: stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT: .cfi_offset %r14, -48
+; CHECK-NEXT: .cfi_offset %r15, -40
+; CHECK-NEXT: aghi %r15, -176
+; CHECK-NEXT: .cfi_def_cfa_offset 336
+; CHECK-NEXT: lg %r0, 8(%r2)
+; CHECK-NEXT: lg %r1, 0(%r2)
+; CHECK-NEXT: stg %r0, 168(%r15)
+; CHECK-NEXT: la %r2, 160(%r15)
+; CHECK-NEXT: stg %r1, 160(%r15)
+; CHECK-NEXT: basr %r14, %r1
+; CHECK-NEXT: lmg %r14, %r15, 288(%r15)
+; CHECK-NEXT: br %r14
+;
+; VECTOR-LABEL: fun0:
+; VECTOR: # %bb.0:
+; VECTOR-NEXT: stmg %r14, %r15, 112(%r15)
+; VECTOR-NEXT: .cfi_offset %r14, -48
+; VECTOR-NEXT: .cfi_offset %r15, -40
+; VECTOR-NEXT: aghi %r15, -176
+; VECTOR-NEXT: .cfi_def_cfa_offset 336
+; VECTOR-NEXT: vl %v0, 0(%r2), 3
+; VECTOR-NEXT: la %r2, 160(%r15)
+; VECTOR-NEXT: vst %v0, 160(%r15), 3
+; VECTOR-NEXT: basr %r14, %r1
+; VECTOR-NEXT: lmg %r14, %r15, 288(%r15)
+; VECTOR-NEXT: br %r14
+ call void undef(%Ty0 %A)
+ ret void
+}
+
+%Ty1 = type {i128, i128}
+define fastcc void @fun1(%Ty1 %A, %Ty1 %B) {
+; CHECK-LABEL: fun1:
+; CHECK: # %bb.0:
+; CHECK-NEXT: stmg %r13, %r15, 104(%r15)
+; CHECK-NEXT: .cfi_offset %r13, -56
+; CHECK-NEXT: .cfi_offset %r14, -48
+; CHECK-NEXT: .cfi_offset %r15, -40
+; CHECK-NEXT: aghi %r15, -224
+; CHECK-NEXT: .cfi_def_cfa_offset 384
+; CHECK-NEXT: lg %r0, 0(%r2)
+; CHECK-NEXT: lg %r1, 8(%r2)
+; CHECK-NEXT: lg %r2, 0(%r3)
+; CHECK-NEXT: lg %r3, 8(%r3)
+; CHECK-NEXT: lg %r14, 8(%r5)
+; CHECK-NEXT: lg %r5, 0(%r5)
+; CHECK-NEXT: lg %r13, 8(%r4)
+; CHECK-NEXT: lg %r4, 0(%r4)
+; CHECK-NEXT: stg %r14, 168(%r15)
+; CHECK-NEXT: stg %r5, 160(%r15)
+; CHECK-NEXT: stg %r13, 184(%r15)
+; CHECK-NEXT: stg %r4, 176(%r15)
+; CHECK-NEXT: stg %r3, 200(%r15)
+; CHECK-NEXT: stg %r2, 192(%r15)
+; CHECK-NEXT: stg %r1, 216(%r15)
+; CHECK-NEXT: la %r2, 208(%r15)
+; CHECK-NEXT: la %r3, 192(%r15)
+; CHECK-NEXT: la %r4, 176(%r15)
+; CHECK-NEXT: la %r5, 160(%r15)
+; CHECK-NEXT: stg %r0, 208(%r15)
+; CHECK-NEXT: basr %r14, %r1
+; CHECK-NEXT: lmg %r13, %r15, 328(%r15)
+; CHECK-NEXT: br %r14
+;
+; VECTOR-LABEL: fun1:
+; VECTOR: # %bb.0:
+; VECTOR-NEXT: stmg %r14, %r15, 112(%r15)
+; VECTOR-NEXT: .cfi_offset %r14, -48
+; VECTOR-NEXT: .cfi_offset %r15, -40
+; VECTOR-NEXT: aghi %r15, -224
+; VECTOR-NEXT: .cfi_def_cfa_offset 384
+; VECTOR-NEXT: vl %v0, 0(%r2), 3
+; VECTOR-NEXT: vl %v1, 0(%r3), 3
+; VECTOR-NEXT: vl %v2, 0(%r4), 3
+; VECTOR-NEXT: vl %v3, 0(%r5), 3
+; VECTOR-NEXT: la %r2, 208(%r15)
+; VECTOR-NEXT: la %r3, 192(%r15)
+; VECTOR-NEXT: la %r4, 176(%r15)
+; VECTOR-NEXT: la %r5, 160(%r15)
+; VECTOR-NEXT: vst %v3, 160(%r15), 3
+; VECTOR-NEXT: vst %v2, 176(%r15), 3
+; VECTOR-NEXT: vst %v1, 192(%r15), 3
+; VECTOR-NEXT: vst %v0, 208(%r15), 3
+; VECTOR-NEXT: basr %r14, %r1
+; VECTOR-NEXT: lmg %r14, %r15, 336(%r15)
+; VECTOR-NEXT: br %r14
+ call void undef(%Ty1 %A, %Ty1 %B)
+ ret void
+}
+
+%Ty2 = type {i256}
+define fastcc void @fun2(%Ty2 %A, %Ty2 %B) {
+; CHECK-LABEL: fun2:
+; CHECK: # %bb.0:
+; CHECK-NEXT: stmg %r13, %r15, 104(%r15)
+; CHECK-NEXT: .cfi_offset %r13, -56
+; CHECK-NEXT: .cfi_offset %r14, -48
+; CHECK-NEXT: .cfi_offset %r15, -40
+; CHECK-NEXT: aghi %r15, -224
+; CHECK-NEXT: .cfi_def_cfa_offset 384
+; CHECK-NEXT: lg %r0, 0(%r2)
+; CHECK-NEXT: lg %r1, 8(%r2)
+; CHECK-NEXT: lg %r4, 16(%r2)
+; CHECK-NEXT: lg %r2, 24(%r2)
+; CHECK-NEXT: lg %r5, 24(%r3)
+; CHECK-NEXT: lg %r14, 16(%r3)
+; CHECK-NEXT: lg %r13, 8(%r3)
+; CHECK-NEXT: lg %r3, 0(%r3)
+; CHECK-NEXT: stg %r5, 184(%r15)
+; CHECK-NEXT: stg %r14, 176(%r15)
+; CHECK-NEXT: stg %r13, 168(%r15)
+; CHECK-NEXT: stg %r3, 160(%r15)
+; CHECK-NEXT: stg %r2, 216(%r15)
+; CHECK-NEXT: stg %r4, 208(%r15)
+; CHECK-NEXT: stg %r1, 200(%r15)
+; CHECK-NEXT: la %r2, 192(%r15)
+; CHECK-NEXT: la %r3, 160(%r15)
+; CHECK-NEXT: stg %r0, 192(%r15)
+; CHECK-NEXT: basr %r14, %r1
+; CHECK-NEXT: lmg %r13, %r15, 328(%r15)
+; CHECK-NEXT: br %r14
+;
+; VECTOR-LABEL: fun2:
+; VECTOR: # %bb.0:
+; VECTOR-NEXT: stmg %r14, %r15, 112(%r15)
+; VECTOR-NEXT: .cfi_offset %r14, -48
+; VECTOR-NEXT: .cfi_offset %r15, -40
+; VECTOR-NEXT: aghi %r15, -224
+; VECTOR-NEXT: .cfi_def_cfa_offset 384
+; VECTOR-NEXT: vl %v0, 0(%r2), 3
+; VECTOR-NEXT: vl %v1, 16(%r2), 3
+; VECTOR-NEXT: vl %v2, 0(%r3), 3
+; VECTOR-NEXT: vl %v3, 16(%r3), 3
+; VECTOR-NEXT: la %r2, 192(%r15)
+; VECTOR-NEXT: la %r3, 160(%r15)
+; VECTOR-NEXT: vst %v3, 176(%r15), 3
+; VECTOR-NEXT: vst %v2, 160(%r15), 3
+; VECTOR-NEXT: vst %v1, 208(%r15), 3
+; VECTOR-NEXT: vst %v0, 192(%r15), 3
+; VECTOR-NEXT: basr %r14, %r1
+; VECTOR-NEXT: lmg %r14, %r15, 336(%r15)
+; VECTOR-NEXT: br %r14
+ call void undef(%Ty2 %A, %Ty2 %B)
+ ret void
+}
+
+%Ty3 = type {float, i256, i32, i128, i8}
+define fastcc void @fun3(%Ty3 %A) {
+; CHECK-LABEL: fun3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: stmg %r13, %r15, 104(%r15)
+; CHECK-NEXT: .cfi_offset %r13, -56
+; CHECK-NEXT: .cfi_offset %r14, -48
+; CHECK-NEXT: .cfi_offset %r15, -40
+; CHECK-NEXT: aghi %r15, -208
+; CHECK-NEXT: .cfi_def_cfa_offset 368
+; CHECK-NEXT: lg %r0, 0(%r2)
+; CHECK-NEXT: lg %r1, 8(%r2)
+; CHECK-NEXT: lg %r14, 16(%r2)
+; CHECK-NEXT: lg %r2, 24(%r2)
+; CHECK-NEXT: lg %r13, 0(%r4)
+; CHECK-NEXT: lg %r4, 8(%r4)
+; CHECK-NEXT: stc %r5, 64
+; CHECK-NEXT: st %r3, 40
+; CHECK-NEXT: ste %f0, 0
+; CHECK-NEXT: stg %r4, 56
+; CHECK-NEXT: stg %r13, 48
+; CHECK-NEXT: stg %r2, 32
+; CHECK-NEXT: stg %r14, 24
+; CHECK-NEXT: stg %r1, 16
+; CHECK-NEXT: stg %r0, 8
+; CHECK-NEXT: stg %r4, 168(%r15)
+; CHECK-NEXT: stg %r13, 160(%r15)
+; CHECK-NEXT: stg %r2, 200(%r15)
+; CHECK-NEXT: stg %r14, 192(%r15)
+; CHECK-NEXT: stg %r1, 184(%r15)
+; CHECK-NEXT: la %r2, 176(%r15)
+; CHECK-NEXT: la %r4, 160(%r15)
+; CHECK-NEXT: stg %r0, 176(%r15)
+; CHECK-NEXT: basr %r14, %r1
+; CHECK-NEXT: lmg %r13, %r15, 312(%r15)
+; CHECK-NEXT: br %r14
+;
+; VECTOR-LABEL: fun3:
+; VECTOR: # %bb.0:
+; VECTOR-NEXT: stmg %r14, %r15, 112(%r15)
+; VECTOR-NEXT: .cfi_offset %r14, -48
+; VECTOR-NEXT: .cfi_offset %r15, -40
+; VECTOR-NEXT: aghi %r15, -208
+; VECTOR-NEXT: .cfi_def_cfa_offset 368
+; VECTOR-NEXT: vl %v1, 0(%r4), 3
+; VECTOR-NEXT: vl %v2, 0(%r2), 3
+; VECTOR-NEXT: vl %v3, 16(%r2), 3
+; VECTOR-NEXT: la %r2, 176(%r15)
+; VECTOR-NEXT: la %r4, 160(%r15)
+; VECTOR-NEXT: stc %r5, 64
+; VECTOR-NEXT: st %r3, 40
+; VECTOR-NEXT: ste %f0, 0
+; VECTOR-NEXT: vst %v3, 24, 3
+; VECTOR-NEXT: vst %v2, 8, 3
+; VECTOR-NEXT: vst %v1, 48, 3
+; VECTOR-NEXT: vst %v1, 160(%r15), 3
+; VECTOR-NEXT: vst %v3, 192(%r15), 3
+; VECTOR-NEXT: vst %v2, 176(%r15), 3
+; VECTOR-NEXT: basr %r14, %r1
+; VECTOR-NEXT: lmg %r14, %r15, 320(%r15)
+; VECTOR-NEXT: br %r14
+ store %Ty3 %A, ptr null
+ call void undef(%Ty3 %A)
+ ret void
+}
+
+%Ty4 = type {i72, i128}
+define fastcc void @fun4(%Ty4 %A) {
+; CHECK-LABEL: fun4:
+; CHECK: # %bb.0:
+; CHECK-NEXT: stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT: .cfi_offset %r14, -48
+; CHECK-NEXT: .cfi_offset %r15, -40
+; CHECK-NEXT: aghi %r15, -192
+; CHECK-NEXT: .cfi_def_cfa_offset 352
+; CHECK-NEXT: lg %r0, 8(%r3)
+; CHECK-NEXT: lg %r1, 0(%r3)
+; CHECK-NEXT: lg %r3, 8(%r2)
+; CHECK-NEXT: lg %r4, 0(%r2)
+; CHECK-NEXT: stg %r0, 24
+; CHECK-NEXT: stg %r1, 16
+; CHECK-NEXT: stc %r3, 8
+; CHECK-NEXT: sllg %r2, %r4, 56
+; CHECK-NEXT: rosbg %r2, %r3, 8, 63, 56
+; CHECK-NEXT: stg %r2, 0
+; CHECK-NEXT: stg %r0, 168(%r15)
+; CHECK-NEXT: stg %r1, 160(%r15)
+; CHECK-NEXT: stg %r3, 184(%r15)
+; CHECK-NEXT: la %r2, 176(%r15)
+; CHECK-NEXT: la %r3, 160(%r15)
+; CHECK-NEXT: stg %r4, 176(%r15)
+; CHECK-NEXT: basr %r14, %r1
+; CHECK-NEXT: lmg %r14, %r15, 304(%r15)
+; CHECK-NEXT: br %r14
+;
+; VECTOR-LABEL: fun4:
+; VECTOR: # %bb.0:
+; VECTOR-NEXT: stmg %r14, %r15, 112(%r15)
+; VECTOR-NEXT: .cfi_offset %r14, -48
+; VECTOR-NEXT: .cfi_offset %r15, -40
+; VECTOR-NEXT: aghi %r15, -192
+; VECTOR-NEXT: .cfi_def_cfa_offset 352
+; VECTOR-NEXT: vl %v1, 0(%r2), 3
+; VECTOR-NEXT: vl %v0, 0(%r3), 3
+; VECTOR-NEXT: vsteb %v1, 8, 15
+; VECTOR-NEXT: vrepib %v2, 8
+; VECTOR-NEXT: vsrlb %v2, %v1, %v2
+; VECTOR-NEXT: la %r2, 176(%r15)
+; VECTOR-NEXT: la %r3, 160(%r15)
+; VECTOR-NEXT: vst %v0, 16, 3
+; VECTOR-NEXT: vsteg %v2, 0, 1
+; VECTOR-NEXT: vst %v0, 160(%r15), 3
+; VECTOR-NEXT: vst %v1, 176(%r15), 3
+; VECTOR-NEXT: basr %r14, %r1
+; VECTOR-NEXT: lmg %r14, %r15, 304(%r15)
+; VECTOR-NEXT: br %r14
+ store %Ty4 %A, ptr null
+ call void undef(%Ty4 %A)
+ ret void
+}
+
+%Ty5 = type {i128, i128}
+declare fastcc %Ty5 @foo5()
+define fastcc void @fun5() {
+; CHECK-LABEL: fun5:
+; CHECK: # %bb.0:
+; CHECK-NEXT: stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT: .cfi_offset %r14, -48
+; CHECK-NEXT: .cfi_offset %r15, -40
+; CHECK-NEXT: aghi %r15, -192
+; CHECK-NEXT: .cfi_def_cfa_offset 352
+; CHECK-NEXT: la %r2, 160(%r15)
+; CHECK-NEXT: brasl %r14, foo5 at PLT
+; CHECK-NEXT: lg %r0, 176(%r15)
+; CHECK-NEXT: lg %r1, 184(%r15)
+; CHECK-NEXT: lg %r2, 160(%r15)
+; CHECK-NEXT: lg %r3, 168(%r15)
+; CHECK-NEXT: stg %r0, 16
+; CHECK-NEXT: stg %r1, 24
+; CHECK-NEXT: stg %r2, 0
+; CHECK-NEXT: stg %r3, 8
+; CHECK-NEXT: lmg %r14, %r15, 304(%r15)
+; CHECK-NEXT: br %r14
+;
+; VECTOR-LABEL: fun5:
+; VECTOR: # %bb.0:
+; VECTOR-NEXT: stmg %r14, %r15, 112(%r15)
+; VECTOR-NEXT: .cfi_offset %r14, -48
+; VECTOR-NEXT: .cfi_offset %r15, -40
+; VECTOR-NEXT: aghi %r15, -192
+; VECTOR-NEXT: .cfi_def_cfa_offset 352
+; VECTOR-NEXT: la %r2, 160(%r15)
+; VECTOR-NEXT: brasl %r14, foo5 at PLT
+; VECTOR-NEXT: vl %v0, 160(%r15), 3
+; VECTOR-NEXT: vl %v1, 176(%r15), 3
+; VECTOR-NEXT: vst %v1, 16, 3
+; VECTOR-NEXT: vst %v0, 0, 3
+; VECTOR-NEXT: lmg %r14, %r15, 304(%r15)
+; VECTOR-NEXT: br %r14
+ %A = call %Ty5 @foo5()
+ store %Ty5 %A, ptr null
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/169583
More information about the llvm-commits
mailing list