diff options
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel/CallLowering.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 166 |
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, |
