summaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel/CallLowering.cpp')
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CallLowering.cpp166
1 files changed, 131 insertions, 35 deletions
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
index 412cd0a21ad4..5efb3be0e53a 100644
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -36,6 +36,7 @@ void CallLowering::anchor() {}
static void
addFlagsUsingAttrFn(ISD::ArgFlagsTy &Flags,
const std::function<bool(Attribute::AttrKind)> &AttrFn) {
+ // TODO: There are missing flags. Add them here.
if (AttrFn(Attribute::SExt))
Flags.setSExt();
if (AttrFn(Attribute::ZExt))
@@ -48,6 +49,8 @@ addFlagsUsingAttrFn(ISD::ArgFlagsTy &Flags,
Flags.setNest();
if (AttrFn(Attribute::ByVal))
Flags.setByVal();
+ if (AttrFn(Attribute::ByRef))
+ Flags.setByRef();
if (AttrFn(Attribute::Preallocated))
Flags.setPreallocated();
if (AttrFn(Attribute::InAlloca))
@@ -220,17 +223,26 @@ void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx,
}
Align MemAlign = DL.getABITypeAlign(Arg.Ty);
- if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated()) {
+ if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated() ||
+ Flags.isByRef()) {
assert(OpIdx >= AttributeList::FirstArgIndex);
unsigned ParamIdx = OpIdx - AttributeList::FirstArgIndex;
Type *ElementTy = FuncInfo.getParamByValType(ParamIdx);
if (!ElementTy)
+ ElementTy = FuncInfo.getParamByRefType(ParamIdx);
+ if (!ElementTy)
ElementTy = FuncInfo.getParamInAllocaType(ParamIdx);
if (!ElementTy)
ElementTy = FuncInfo.getParamPreallocatedType(ParamIdx);
+
assert(ElementTy && "Must have byval, inalloca or preallocated type");
- Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
+
+ uint64_t MemSize = DL.getTypeAllocSize(ElementTy);
+ if (Flags.isByRef())
+ Flags.setByRefSize(MemSize);
+ else
+ Flags.setByValSize(MemSize);
// For ByVal, alignment should be passed from FE. BE will guess if
// this info is not there but there are cases it cannot get right.
@@ -471,13 +483,15 @@ static void buildCopyFromRegs(MachineIRBuilder &B, ArrayRef<Register> OrigRegs,
// Deal with vector with 64-bit elements decomposed to 32-bit
// registers. Need to create intermediate 64-bit elements.
SmallVector<Register, 8> EltMerges;
- int PartsPerElt = DstEltTy.getSizeInBits() / PartLLT.getSizeInBits();
-
- assert(DstEltTy.getSizeInBits() % PartLLT.getSizeInBits() == 0);
+ int PartsPerElt =
+ divideCeil(DstEltTy.getSizeInBits(), PartLLT.getSizeInBits());
+ LLT ExtendedPartTy = LLT::scalar(PartLLT.getSizeInBits() * PartsPerElt);
for (int I = 0, NumElts = LLTy.getNumElements(); I != NumElts; ++I) {
auto Merge =
- B.buildMergeLikeInstr(RealDstEltTy, Regs.take_front(PartsPerElt));
+ B.buildMergeLikeInstr(ExtendedPartTy, Regs.take_front(PartsPerElt));
+ if (ExtendedPartTy.getSizeInBits() > RealDstEltTy.getSizeInBits())
+ Merge = B.buildTrunc(RealDstEltTy, Merge);
// Fix the type in case this is really a vector of pointers.
MRI.setType(Merge.getReg(0), RealDstEltTy);
EltMerges.push_back(Merge.getReg(0));
@@ -574,6 +588,17 @@ static void buildCopyToRegs(MachineIRBuilder &B, ArrayRef<Register> DstRegs,
return;
}
+ if (SrcTy.isVector() && !PartTy.isVector() &&
+ SrcTy.getScalarSizeInBits() > PartTy.getSizeInBits()) {
+ LLT ExtTy =
+ LLT::vector(SrcTy.getElementCount(),
+ LLT::scalar(PartTy.getScalarSizeInBits() * DstRegs.size() /
+ SrcTy.getNumElements()));
+ auto Ext = B.buildAnyExt(ExtTy, SrcReg);
+ B.buildUnmerge(DstRegs, Ext);
+ return;
+ }
+
MachineRegisterInfo &MRI = *B.getMRI();
LLT DstTy = MRI.getType(DstRegs[0]);
LLT LCMTy = getCoverTy(SrcTy, PartTy);
@@ -743,6 +768,8 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
continue;
}
+ auto AllocaAddressSpace = MF.getDataLayout().getAllocaAddrSpace();
+
const MVT ValVT = VA.getValVT();
const MVT LocVT = VA.getLocVT();
@@ -751,6 +778,8 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
const LLT NewLLT = Handler.isIncomingArgumentHandler() ? LocTy : ValTy;
const EVT OrigVT = EVT::getEVT(Args[i].Ty);
const LLT OrigTy = getLLTForType(*Args[i].Ty, DL);
+ const LLT PointerTy = LLT::pointer(
+ AllocaAddressSpace, DL.getPointerSizeInBits(AllocaAddressSpace));
// Expected to be multiple regs for a single incoming arg.
// There should be Regs.size() ArgLocs per argument.
@@ -765,31 +794,76 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
// intermediate values.
Args[i].Regs.resize(NumParts);
- // For each split register, create and assign a vreg that will store
- // the incoming component of the larger value. These will later be
- // merged to form the final vreg.
- for (unsigned Part = 0; Part < NumParts; ++Part)
- Args[i].Regs[Part] = MRI.createGenericVirtualRegister(NewLLT);
+ // When we have indirect parameter passing we are receiving a pointer,
+ // that points to the actual value, so we need one "temporary" pointer.
+ if (VA.getLocInfo() == CCValAssign::Indirect) {
+ if (Handler.isIncomingArgumentHandler())
+ Args[i].Regs[0] = MRI.createGenericVirtualRegister(PointerTy);
+ } else {
+ // For each split register, create and assign a vreg that will store
+ // the incoming component of the larger value. These will later be
+ // merged to form the final vreg.
+ for (unsigned Part = 0; Part < NumParts; ++Part)
+ Args[i].Regs[Part] = MRI.createGenericVirtualRegister(NewLLT);
+ }
}
assert((j + (NumParts - 1)) < ArgLocs.size() &&
"Too many regs for number of args");
// Coerce into outgoing value types before register assignment.
- if (!Handler.isIncomingArgumentHandler() && OrigTy != ValTy) {
+ if (!Handler.isIncomingArgumentHandler() && OrigTy != ValTy &&
+ VA.getLocInfo() != CCValAssign::Indirect) {
assert(Args[i].OrigRegs.size() == 1);
buildCopyToRegs(MIRBuilder, Args[i].Regs, Args[i].OrigRegs[0], OrigTy,
ValTy, extendOpFromFlags(Args[i].Flags[0]));
}
+ bool IndirectParameterPassingHandled = false;
bool BigEndianPartOrdering = TLI->hasBigEndianPartOrdering(OrigVT, DL);
for (unsigned Part = 0; Part < NumParts; ++Part) {
+ assert((VA.getLocInfo() != CCValAssign::Indirect || Part == 0) &&
+ "Only the first parameter should be processed when "
+ "handling indirect passing!");
Register ArgReg = Args[i].Regs[Part];
// There should be Regs.size() ArgLocs per argument.
unsigned Idx = BigEndianPartOrdering ? NumParts - 1 - Part : Part;
CCValAssign &VA = ArgLocs[j + Idx];
const ISD::ArgFlagsTy Flags = Args[i].Flags[Part];
+ // We found an indirect parameter passing, and we have an
+ // OutgoingValueHandler as our handler (so we are at the call site or the
+ // return value). In this case, start the construction of the following
+ // GMIR, that is responsible for the preparation of indirect parameter
+ // passing:
+ //
+ // %1(indirectly passed type) = The value to pass
+ // %3(pointer) = G_FRAME_INDEX %stack.0
+ // G_STORE %1, %3 :: (store (s128), align 8)
+ //
+ // After this GMIR, the remaining part of the loop body will decide how
+ // to get the value to the caller and we break out of the loop.
+ if (VA.getLocInfo() == CCValAssign::Indirect &&
+ !Handler.isIncomingArgumentHandler()) {
+ Align AlignmentForStored = DL.getPrefTypeAlign(Args[i].Ty);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ // Get some space on the stack for the value, so later we can pass it
+ // as a reference.
+ int FrameIdx = MFI.CreateStackObject(OrigTy.getScalarSizeInBits(),
+ AlignmentForStored, false);
+ Register PointerToStackReg =
+ MIRBuilder.buildFrameIndex(PointerTy, FrameIdx).getReg(0);
+ MachinePointerInfo StackPointerMPO =
+ MachinePointerInfo::getFixedStack(MF, FrameIdx);
+ // Store the value in the previously created stack space.
+ MIRBuilder.buildStore(Args[i].OrigRegs[Part], PointerToStackReg,
+ StackPointerMPO,
+ inferAlignFromPtrInfo(MF, StackPointerMPO));
+
+ ArgReg = PointerToStackReg;
+ IndirectParameterPassingHandled = true;
+ }
+
if (VA.isMemLoc() && !Flags.isByVal()) {
// Individual pieces may have been spilled to the stack and others
// passed in registers.
@@ -799,14 +873,21 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
LLT MemTy = Handler.getStackValueStoreType(DL, VA, Flags);
MachinePointerInfo MPO;
- Register StackAddr = Handler.getStackAddress(
- MemTy.getSizeInBytes(), VA.getLocMemOffset(), MPO, Flags);
-
- Handler.assignValueToAddress(Args[i], Part, StackAddr, MemTy, MPO, VA);
- continue;
- }
-
- if (VA.isMemLoc() && Flags.isByVal()) {
+ Register StackAddr =
+ Handler.getStackAddress(VA.getLocInfo() == CCValAssign::Indirect
+ ? PointerTy.getSizeInBytes()
+ : MemTy.getSizeInBytes(),
+ VA.getLocMemOffset(), MPO, Flags);
+
+ // Finish the handling of indirect passing from the passers
+ // (OutgoingParameterHandler) side.
+ // This branch is needed, so the pointer to the value is loaded onto the
+ // stack.
+ if (VA.getLocInfo() == CCValAssign::Indirect)
+ Handler.assignValueToAddress(ArgReg, StackAddr, PointerTy, MPO, VA);
+ else
+ Handler.assignValueToAddress(Args[i], Part, StackAddr, MemTy, MPO, VA);
+ } else if (VA.isMemLoc() && Flags.isByVal()) {
assert(Args[i].Regs.size() == 1 &&
"didn't expect split byval pointer");
@@ -845,30 +926,45 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
DstMPO, DstAlign, SrcMPO, SrcAlign,
MemSize, VA);
}
- continue;
- }
-
- assert(!VA.needsCustom() && "custom loc should have been handled already");
-
- if (i == 0 && !ThisReturnRegs.empty() &&
- Handler.isIncomingArgumentHandler() &&
- isTypeIsValidForThisReturn(ValVT)) {
+ } else if (i == 0 && !ThisReturnRegs.empty() &&
+ Handler.isIncomingArgumentHandler() &&
+ isTypeIsValidForThisReturn(ValVT)) {
Handler.assignValueToReg(ArgReg, ThisReturnRegs[Part], VA);
- continue;
- }
-
- if (Handler.isIncomingArgumentHandler())
+ } else if (Handler.isIncomingArgumentHandler()) {
Handler.assignValueToReg(ArgReg, VA.getLocReg(), VA);
- else {
+ } else {
DelayedOutgoingRegAssignments.emplace_back([=, &Handler]() {
Handler.assignValueToReg(ArgReg, VA.getLocReg(), VA);
});
}
+
+ // Finish the handling of indirect parameter passing when receiving
+ // the value (we are in the called function or the caller when receiving
+ // the return value).
+ if (VA.getLocInfo() == CCValAssign::Indirect &&
+ Handler.isIncomingArgumentHandler()) {
+ Align Alignment = DL.getABITypeAlign(Args[i].Ty);
+ MachinePointerInfo MPO = MachinePointerInfo::getUnknownStack(MF);
+
+ // Since we are doing indirect parameter passing, we know that the value
+ // in the temporary register is not the value passed to the function,
+ // but rather a pointer to that value. Let's load that value into the
+ // virtual register where the parameter should go.
+ MIRBuilder.buildLoad(Args[i].OrigRegs[0], Args[i].Regs[0], MPO,
+ Alignment);
+
+ IndirectParameterPassingHandled = true;
+ }
+
+ if (IndirectParameterPassingHandled)
+ break;
}
// Now that all pieces have been assigned, re-pack the register typed values
- // into the original value typed registers.
- if (Handler.isIncomingArgumentHandler() && OrigVT != LocVT) {
+ // into the original value typed registers. This is only necessary, when
+ // the value was passed in multiple registers, not indirectly.
+ if (Handler.isIncomingArgumentHandler() && OrigVT != LocVT &&
+ !IndirectParameterPassingHandled) {
// Merge the split registers into the expected larger result vregs of
// the original call.
buildCopyFromRegs(MIRBuilder, Args[i].OrigRegs, Args[i].Regs, OrigTy,