summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/PowerPC/PPCISelLowering.cpp')
-rw-r--r--llvm/lib/Target/PowerPC/PPCISelLowering.cpp107
1 files changed, 85 insertions, 22 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 85731436c24..881d6d71a19 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -6831,6 +6831,9 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
if (ArgFlags.isNest())
report_fatal_error("Nest arguments are unimplemented.");
+ if (ValVT.isVector() || LocVT.isVector())
+ report_fatal_error("Vector arguments are unimplemented on AIX.");
+
const PPCSubtarget &Subtarget = static_cast<const PPCSubtarget &>(
State.getMachineFunction().getSubtarget());
const bool IsPPC64 = Subtarget.isPPC64();
@@ -6875,18 +6878,33 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
// This includes f64 in 64-bit mode for ABI compatibility.
State.AllocateStack(IsPPC64 ? 8 : StoreSize, 4);
if (unsigned Reg = State.AllocateReg(FPR))
- State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, MVT::f64, LocInfo));
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
else
report_fatal_error("Handling of placing parameters on the stack is "
"unimplemented!");
- // f32 reserves 1 GPR in both PPC32 and PPC64.
- // f64 reserves 2 GPRs in PPC32 and 1 GPR in PPC64.
- for (unsigned i = 0; i < StoreSize; i += PtrByteSize)
- State.AllocateReg(IsPPC64 ? GPR_64 : GPR_32);
+ // AIX requires that GPRs are reserved for float arguments.
+ // Successfully reserved GPRs are only initialized for vararg calls.
+ MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32;
+ for (unsigned I = 0; I < StoreSize; I += PtrByteSize) {
+ if (unsigned Reg = State.AllocateReg(IsPPC64 ? GPR_64 : GPR_32)) {
+ if (State.isVarArg()) {
+ // Custom handling is required for:
+ // f64 in PPC32 needs to be split into 2 GPRs.
+ // f32 in PPC64 needs to occupy only lower 32 bits of 64-bit GPR.
+ State.addLoc(
+ CCValAssign::getCustomReg(ValNo, ValVT, Reg, RegVT, LocInfo));
+ }
+ } else if (State.isVarArg()) {
+ report_fatal_error("Handling of placing parameters on the stack is "
+ "unimplemented!");
+ }
+ }
+
return false;
}
}
+ return true;
}
static const TargetRegisterClass *getRegClassForSVT(MVT::SimpleValueType SVT,
@@ -7013,7 +7031,7 @@ SDValue PPCTargetLowering::LowerCall_AIX(
CallConv == CallingConv::Cold ||
CallConv == CallingConv::Fast) && "Unexpected calling convention!");
- if (isVarArg || isPatchPoint)
+ if (isPatchPoint)
report_fatal_error("This call type is unimplemented on AIX.");
const PPCSubtarget& Subtarget =
@@ -7032,7 +7050,8 @@ SDValue PPCTargetLowering::LowerCall_AIX(
// [SP][CR][LR][2 x reserved][TOC].
// The LSA is 24 bytes (6x4) in PPC32 and 48 bytes (6x8) in PPC64.
const unsigned LinkageSize = Subtarget.getFrameLowering()->getLinkageSize();
- const unsigned PtrByteSize = Subtarget.isPPC64() ? 8 : 4;
+ const bool IsPPC64 = Subtarget.isPPC64();
+ const unsigned PtrByteSize = IsPPC64 ? 8 : 4;
CCInfo.AllocateStack(LinkageSize, PtrByteSize);
CCInfo.AnalyzeCallOperands(Outs, CC_AIX);
@@ -7052,26 +7071,70 @@ SDValue PPCTargetLowering::LowerCall_AIX(
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
- for (CCValAssign &VA : ArgLocs) {
+ for (unsigned I = 0, E = ArgLocs.size(); I != E;) {
+ CCValAssign &VA = ArgLocs[I++];
+
+ if (VA.isMemLoc())
+ report_fatal_error("Handling of placing parameters on the stack is "
+ "unimplemented!");
+ if (!VA.isRegLoc())
+ report_fatal_error(
+ "Unexpected non-register location for function call argument.");
+
SDValue Arg = OutVals[VA.getValNo()];
- switch (VA.getLocInfo()) {
- default: report_fatal_error("Unexpected argument extension type.");
- case CCValAssign::Full: break;
- case CCValAssign::ZExt:
- Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
- break;
- case CCValAssign::SExt:
- Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
- break;
+ if (!VA.needsCustom()) {
+ switch (VA.getLocInfo()) {
+ default:
+ report_fatal_error("Unexpected argument extension type.");
+ case CCValAssign::Full:
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ }
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+
+ continue;
}
- if (VA.isRegLoc())
- RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ // Custom handling is used for GPR initializations for vararg float
+ // arguments.
+ assert(isVarArg && VA.getValVT().isFloatingPoint() &&
+ VA.getLocVT().isInteger() &&
+ "Unexpected custom register handling for calling convention.");
- if (VA.isMemLoc())
- report_fatal_error("Handling of placing parameters on the stack is "
- "unimplemented!");
+ SDValue ArgAsInt =
+ DAG.getBitcast(MVT::getIntegerVT(VA.getValVT().getSizeInBits()), Arg);
+
+ if (Arg.getValueType().getStoreSize() == VA.getLocVT().getStoreSize())
+ // f32 in 32-bit GPR
+ // f64 in 64-bit GPR
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgAsInt));
+ else if (Arg.getValueType().getSizeInBits() < VA.getLocVT().getSizeInBits())
+ // f32 in 64-bit GPR.
+ RegsToPass.push_back(std::make_pair(
+ VA.getLocReg(), DAG.getZExtOrTrunc(ArgAsInt, dl, VA.getLocVT())));
+ else {
+ // f64 in two 32-bit GPRs
+ // The 2 GPRs are marked custom and expected to be adjacent in ArgLocs.
+ assert(Arg.getValueType() == MVT::f64 && isVarArg && !IsPPC64 &&
+ "Unexpected custom register for argument!");
+ CCValAssign &GPR1 = VA;
+ SDValue MSWAsI64 = DAG.getNode(ISD::SRL, dl, MVT::i64, ArgAsInt,
+ DAG.getConstant(32, dl, MVT::i8));
+ RegsToPass.push_back(std::make_pair(
+ GPR1.getLocReg(), DAG.getZExtOrTrunc(MSWAsI64, dl, MVT::i32)));
+ assert(I != E && "A second custom GPR is expected!");
+ CCValAssign &GPR2 = ArgLocs[I++];
+ assert(GPR2.isRegLoc() && GPR2.getValNo() == GPR1.getValNo() &&
+ GPR2.needsCustom() && "A second custom GPR is expected!");
+ RegsToPass.push_back(std::make_pair(
+ GPR2.getLocReg(), DAG.getZExtOrTrunc(ArgAsInt, dl, MVT::i32)));
+ }
}
// For indirect calls, we need to save the TOC base to the stack for
OpenPOWER on IntegriCloud