Skip to content

Commit 52bbbf4

Browse files
committed
[SystemZ] Assign the full space for promoted and split outgoing args.
When a large "irregular" (e.g. i96) integer call argument is converted to indirect, 64-bit parts are stored to the stack. The full stack space (e.g. i128) was not allocated prior to this patch, but rather just the exact space of the original type. This caused neighboring values on the stack to be overwritten. Thanks to Josh Stone for reporting this. Review: Ulrich Weigand Fixes https://bugs.llvm.org/show_bug.cgi?id=49322 Differential Revision: https://reviews.llvm.org/D97514
1 parent 95540f9 commit 52bbbf4

File tree

2 files changed

+72
-4
lines changed

2 files changed

+72
-4
lines changed

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

+18-4
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
15471547
bool IsVarArg = CLI.IsVarArg;
15481548
MachineFunction &MF = DAG.getMachineFunction();
15491549
EVT PtrVT = getPointerTy(MF.getDataLayout());
1550+
LLVMContext &Ctx = *DAG.getContext();
15501551

15511552
// Detect unsupported vector argument and return types.
15521553
if (Subtarget.hasVector()) {
@@ -1556,7 +1557,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
15561557

15571558
// Analyze the operands of the call, assigning locations to each operand.
15581559
SmallVector<CCValAssign, 16> ArgLocs;
1559-
SystemZCCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
1560+
SystemZCCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, Ctx);
15601561
ArgCCInfo.AnalyzeCallOperands(Outs, CC_SystemZ);
15611562

15621563
// We don't support GuaranteedTailCallOpt, only automatically-detected
@@ -1581,14 +1582,25 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
15811582

15821583
if (VA.getLocInfo() == CCValAssign::Indirect) {
15831584
// Store the argument in a stack slot and pass its address.
1584-
SDValue SpillSlot = DAG.CreateStackTemporary(Outs[I].ArgVT);
1585+
unsigned ArgIndex = Outs[I].OrigArgIndex;
1586+
EVT SlotVT;
1587+
if (I + 1 != E && Outs[I + 1].OrigArgIndex == ArgIndex) {
1588+
// Allocate the full stack space for a promoted (and split) argument.
1589+
Type *OrigArgType = CLI.Args[Outs[I].OrigArgIndex].Ty;
1590+
EVT OrigArgVT = getValueType(MF.getDataLayout(), OrigArgType);
1591+
MVT PartVT = getRegisterTypeForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
1592+
unsigned N = getNumRegistersForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
1593+
SlotVT = EVT::getIntegerVT(Ctx, PartVT.getSizeInBits() * N);
1594+
} else {
1595+
SlotVT = Outs[I].ArgVT;
1596+
}
1597+
SDValue SpillSlot = DAG.CreateStackTemporary(SlotVT);
15851598
int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
15861599
MemOpChains.push_back(
15871600
DAG.getStore(Chain, DL, ArgValue, SpillSlot,
15881601
MachinePointerInfo::getFixedStack(MF, FI)));
15891602
// If the original argument was split (e.g. i128), we need
15901603
// to store all parts of it here (and pass just one address).
1591-
unsigned ArgIndex = Outs[I].OrigArgIndex;
15921604
assert (Outs[I].PartOffset == 0);
15931605
while (I + 1 != E && Outs[I + 1].OrigArgIndex == ArgIndex) {
15941606
SDValue PartValue = OutVals[I + 1];
@@ -1598,6 +1610,8 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
15981610
MemOpChains.push_back(
15991611
DAG.getStore(Chain, DL, PartValue, Address,
16001612
MachinePointerInfo::getFixedStack(MF, FI)));
1613+
assert((PartOffset + PartValue.getValueType().getStoreSize() <=
1614+
SlotVT.getStoreSize()) && "Not enough space for argument part!");
16011615
++I;
16021616
}
16031617
ArgValue = SpillSlot;
@@ -1691,7 +1705,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
16911705

16921706
// Assign locations to each value returned by this call.
16931707
SmallVector<CCValAssign, 16> RetLocs;
1694-
CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
1708+
CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, Ctx);
16951709
RetCCInfo.AnalyzeCallResult(Ins, RetCC_SystemZ);
16961710

16971711
// Copy all of the result registers out of their specified physreg.

llvm/test/CodeGen/SystemZ/args-11.ll

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; Test outgoing promoted arguments that are split (and passed by reference).
3+
;
4+
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
5+
6+
; The i96 arg is promoted to i128 and should get the full stack space.
7+
declare void @fn1(i96)
8+
define i32 @fn2() {
9+
; CHECK-LABEL: fn2:
10+
; CHECK: # %bb.0:
11+
; CHECK-NEXT: stmg %r14, %r15, 112(%r15)
12+
; CHECK-NEXT: .cfi_offset %r14, -48
13+
; CHECK-NEXT: .cfi_offset %r15, -40
14+
; CHECK-NEXT: aghi %r15, -184
15+
; CHECK-NEXT: .cfi_def_cfa_offset 344
16+
; CHECK-NEXT: mvhi 180(%r15), -1
17+
; CHECK-NEXT: mvghi 168(%r15), 0
18+
; CHECK-NEXT: la %r2, 160(%r15)
19+
; CHECK-NEXT: mvghi 160(%r15), 0
20+
; CHECK-NEXT: brasl %r14, fn1@PLT
21+
; CHECK-NEXT: l %r2, 180(%r15)
22+
; CHECK-NEXT: lmg %r14, %r15, 296(%r15)
23+
; CHECK-NEXT: br %r14
24+
%1 = alloca i32
25+
store i32 -1, i32* %1
26+
call void @fn1(i96 0)
27+
%2 = load i32, i32* %1
28+
ret i32 %2
29+
}
30+
31+
declare void @fn3(i136)
32+
define i32 @fn4() {
33+
; CHECK-LABEL: fn4:
34+
; CHECK: # %bb.0:
35+
; CHECK-NEXT: stmg %r14, %r15, 112(%r15)
36+
; CHECK-NEXT: .cfi_offset %r14, -48
37+
; CHECK-NEXT: .cfi_offset %r15, -40
38+
; CHECK-NEXT: aghi %r15, -192
39+
; CHECK-NEXT: .cfi_def_cfa_offset 352
40+
; CHECK-NEXT: mvhi 188(%r15), -1
41+
; CHECK-NEXT: mvghi 176(%r15), 0
42+
; CHECK-NEXT: mvghi 168(%r15), 0
43+
; CHECK-NEXT: la %r2, 160(%r15)
44+
; CHECK-NEXT: mvghi 160(%r15), 0
45+
; CHECK-NEXT: brasl %r14, fn3@PLT
46+
; CHECK-NEXT: l %r2, 188(%r15)
47+
; CHECK-NEXT: lmg %r14, %r15, 304(%r15)
48+
; CHECK-NEXT: br %r14
49+
%1 = alloca i32
50+
store i32 -1, i32* %1
51+
call void @fn3(i136 0)
52+
%2 = load i32, i32* %1
53+
ret i32 %2
54+
}

0 commit comments

Comments
 (0)