Skip to content

Commit c218664

Browse files
cebowlermandlebug
authored andcommitted
[PowerPC][AIX] Implement by-val caller arguments in a single register.
This is the first of a series of patches that adds caller support for by-value arguments. This patch add support for arguments that are passed in a single GPR. There are 3 limitation cases: -The by-value argument is larger than a single register. -There are no remaining GPRs even though the by-value argument would otherwise fit in a single GPR. -The by-value argument requires alignment greater than register width. Future patches will be required to add support for these cases as well as for the callee handling (in LowerFormalArguments_AIX) that corresponds to this work. Differential Revision: https://reviews.llvm.org/D75863
1 parent 3481062 commit c218664

File tree

7 files changed

+480
-26
lines changed

7 files changed

+480
-26
lines changed

llvm/lib/Target/PowerPC/PPCISelLowering.cpp

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6841,9 +6841,6 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
68416841
if (ValVT == MVT::f128)
68426842
report_fatal_error("f128 is unimplemented on AIX.");
68436843

6844-
if (ArgFlags.isByVal())
6845-
report_fatal_error("Passing structure by value is unimplemented.");
6846-
68476844
if (ArgFlags.isNest())
68486845
report_fatal_error("Nest arguments are unimplemented.");
68496846

@@ -6857,6 +6854,29 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
68576854
PPC::X3, PPC::X4, PPC::X5, PPC::X6,
68586855
PPC::X7, PPC::X8, PPC::X9, PPC::X10};
68596856

6857+
if (ArgFlags.isByVal()) {
6858+
if (ArgFlags.getNonZeroByValAlign() > PtrByteSize)
6859+
report_fatal_error("Pass-by-value arguments with alignment greater than "
6860+
"register width are not supported.");
6861+
6862+
const unsigned ByValSize = ArgFlags.getByValSize();
6863+
6864+
// An empty aggregate parameter takes up no storage and no registers.
6865+
if (ByValSize == 0)
6866+
return false;
6867+
6868+
if (ByValSize <= PtrByteSize) {
6869+
State.AllocateStack(PtrByteSize, PtrByteSize);
6870+
if (unsigned Reg = State.AllocateReg(IsPPC64 ? GPR_64 : GPR_32)) {
6871+
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, RegVT, LocInfo));
6872+
return false;
6873+
}
6874+
}
6875+
6876+
report_fatal_error(
6877+
"Pass-by-value arguments are only supported in a single register.");
6878+
}
6879+
68606880
// Arguments always reserve parameter save area.
68616881
switch (ValVT.SimpleTy) {
68626882
default:
@@ -7130,9 +7150,59 @@ SDValue PPCTargetLowering::LowerCall_AIX(
71307150
CCValAssign &VA = ArgLocs[I++];
71317151

71327152
SDValue Arg = OutVals[VA.getValNo()];
7153+
ISD::ArgFlagsTy Flags = Outs[VA.getValNo()].Flags;
7154+
const MVT LocVT = VA.getLocVT();
7155+
const MVT ValVT = VA.getValVT();
7156+
7157+
if (Flags.isByVal()) {
7158+
const unsigned ByValSize = Flags.getByValSize();
7159+
assert(
7160+
VA.isRegLoc() && ByValSize > 0 && ByValSize <= PtrByteSize &&
7161+
"Pass-by-value arguments are only supported in a single register.");
7162+
7163+
// Loads must be a power-of-2 size and cannot be larger than the
7164+
// ByValSize. For example: a 7 byte by-val arg requires 4, 2 and 1 byte
7165+
// loads.
7166+
SDValue RegVal;
7167+
for (unsigned Bytes = 0; Bytes != ByValSize;) {
7168+
unsigned N = PowerOf2Floor(ByValSize - Bytes);
7169+
const MVT VT =
7170+
N == 1 ? MVT::i8
7171+
: ((N == 2) ? MVT::i16 : (N == 4 ? MVT::i32 : MVT::i64));
7172+
7173+
SDValue LoadAddr = Arg;
7174+
if (Bytes != 0) {
7175+
// Adjust the load offset by the number of bytes read so far.
7176+
SDNodeFlags Flags;
7177+
Flags.setNoUnsignedWrap(true);
7178+
LoadAddr = DAG.getNode(ISD::ADD, dl, LocVT, Arg,
7179+
DAG.getConstant(Bytes, dl, LocVT), Flags);
7180+
}
7181+
SDValue Load = DAG.getExtLoad(ISD::ZEXTLOAD, dl, PtrVT, Chain, LoadAddr,
7182+
MachinePointerInfo(), VT);
7183+
MemOpChains.push_back(Load.getValue(1));
71337184

7134-
if (!VA.isRegLoc() && !VA.isMemLoc())
7135-
report_fatal_error("Unexpected ___location for function call argument.");
7185+
Bytes += N;
7186+
assert(LocVT.getSizeInBits() >= (Bytes * 8));
7187+
if (unsigned NumSHLBits = LocVT.getSizeInBits() - (Bytes * 8)) {
7188+
// By-val arguments are passed left-justfied in register.
7189+
EVT ShiftAmountTy =
7190+
getShiftAmountTy(Load->getValueType(0), DAG.getDataLayout());
7191+
SDValue SHLAmt = DAG.getConstant(NumSHLBits, dl, ShiftAmountTy);
7192+
SDValue ShiftedLoad =
7193+
DAG.getNode(ISD::SHL, dl, Load.getValueType(), Load, SHLAmt);
7194+
RegVal = RegVal ? DAG.getNode(ISD::OR, dl, LocVT, RegVal, ShiftedLoad)
7195+
: ShiftedLoad;
7196+
} else {
7197+
assert(!RegVal && Bytes == ByValSize &&
7198+
"Pass-by-value argument handling unexpectedly incomplete.");
7199+
RegVal = Load;
7200+
}
7201+
}
7202+
7203+
RegsToPass.push_back(std::make_pair(VA.getLocReg(), RegVal));
7204+
continue;
7205+
}
71367206

71377207
switch (VA.getLocInfo()) {
71387208
default:
@@ -7165,20 +7235,20 @@ SDValue PPCTargetLowering::LowerCall_AIX(
71657235
// Custom handling is used for GPR initializations for vararg float
71667236
// arguments.
71677237
assert(VA.isRegLoc() && VA.needsCustom() && CFlags.IsVarArg &&
7168-
VA.getValVT().isFloatingPoint() && VA.getLocVT().isInteger() &&
7238+
ValVT.isFloatingPoint() && LocVT.isInteger() &&
71697239
"Unexpected register handling for calling convention.");
71707240

71717241
SDValue ArgAsInt =
7172-
DAG.getBitcast(MVT::getIntegerVT(VA.getValVT().getSizeInBits()), Arg);
7242+
DAG.getBitcast(MVT::getIntegerVT(ValVT.getSizeInBits()), Arg);
71737243

7174-
if (Arg.getValueType().getStoreSize() == VA.getLocVT().getStoreSize())
7244+
if (Arg.getValueType().getStoreSize() == LocVT.getStoreSize())
71757245
// f32 in 32-bit GPR
71767246
// f64 in 64-bit GPR
71777247
RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgAsInt));
7178-
else if (Arg.getValueType().getSizeInBits() < VA.getLocVT().getSizeInBits())
7248+
else if (Arg.getValueType().getSizeInBits() < LocVT.getSizeInBits())
71797249
// f32 in 64-bit GPR.
71807250
RegsToPass.push_back(std::make_pair(
7181-
VA.getLocReg(), DAG.getZExtOrTrunc(ArgAsInt, dl, VA.getLocVT())));
7251+
VA.getLocReg(), DAG.getZExtOrTrunc(ArgAsInt, dl, LocVT)));
71827252
else {
71837253
// f64 in two 32-bit GPRs
71847254
// The 2 GPRs are marked custom and expected to be adjacent in ArgLocs.

llvm/test/CodeGen/PowerPC/aix-byval-param.ll

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
2+
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
3+
4+
%struct.S = type { [9 x i8] }
5+
6+
define void @bar() {
7+
entry:
8+
%s1 = alloca %struct.S, align 1
9+
%agg.tmp = alloca %struct.S, align 1
10+
call void @foo(%struct.S* byval(%struct.S) align 1 %agg.tmp)
11+
ret void
12+
}
13+
14+
declare void @foo(%struct.S* byval(%struct.S) align 1)
15+
16+
; CHECK: LLVM ERROR: Pass-by-value arguments are only supported in a single register.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
2+
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
3+
4+
%struct.S = type { [1 x i8] }
5+
6+
define void @bar() {
7+
entry:
8+
%s1 = alloca %struct.S, align 1
9+
%agg.tmp = alloca %struct.S, align 1
10+
call void @foo(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, %struct.S* byval(%struct.S) align 1 %agg.tmp)
11+
ret void
12+
}
13+
14+
declare void @foo(i32, i32, i32, i32, i32, i32, i32, i32, %struct.S* byval(%struct.S) align 1)
15+
16+
; CHECK: LLVM ERROR: Pass-by-value arguments are only supported in a single register.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
2+
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
3+
4+
%struct.S = type { [1 x i8] }
5+
6+
define void @bar() {
7+
entry:
8+
%s1 = alloca %struct.S, align 32
9+
%agg.tmp = alloca %struct.S, align 32
10+
call void @foo(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, %struct.S* byval(%struct.S) align 32 %agg.tmp)
11+
ret void
12+
}
13+
14+
declare void @foo(i32, i32, i32, i32, i32, i32, i32, i32, %struct.S* byval(%struct.S) align 32)
15+
16+
; CHECK: LLVM ERROR: Pass-by-value arguments with alignment greater than register width are not supported.

0 commit comments

Comments
 (0)