diff --git a/llvm/lib/Target/Mips/MipsCallLowering.cpp b/llvm/lib/Target/Mips/MipsCallLowering.cpp index 648dec5428d4..8babdbf902a8 100644 --- a/llvm/lib/Target/Mips/MipsCallLowering.cpp +++ b/llvm/lib/Target/Mips/MipsCallLowering.cpp @@ -36,15 +36,58 @@ bool MipsCallLowering::MipsHandler::assign(unsigned VReg, return true; } +bool MipsCallLowering::MipsHandler::assignVRegs(ArrayRef VRegs, + ArrayRef ArgLocs, + unsigned ArgLocsStartIndex) { + for (unsigned i = 0; i < VRegs.size(); ++i) + if (!assign(VRegs[i], ArgLocs[ArgLocsStartIndex + i])) + return false; + return true; +} + +void MipsCallLowering::MipsHandler::setMostSignificantFirst( + SmallVectorImpl &VRegs) { + if (MIRBuilder.getMF().getDataLayout().isLittleEndian()) + std::reverse(VRegs.begin(), VRegs.end()); +} + +bool MipsCallLowering::MipsHandler::handle( + ArrayRef ArgLocs, ArrayRef Args) { + SmallVector VRegs; + unsigned SplitLength; + const Function &F = MIRBuilder.getMF().getFunction(); + const DataLayout &DL = F.getParent()->getDataLayout(); + const MipsTargetLowering &TLI = *static_cast( + MIRBuilder.getMF().getSubtarget().getTargetLowering()); + + for (unsigned ArgsIndex = 0, ArgLocsIndex = 0; ArgsIndex < Args.size(); + ++ArgsIndex, ArgLocsIndex += SplitLength) { + EVT VT = TLI.getValueType(DL, Args[ArgsIndex].Ty); + SplitLength = TLI.getNumRegistersForCallingConv(F.getContext(), + F.getCallingConv(), VT); + if (SplitLength > 1) { + VRegs.clear(); + MVT RegisterVT = TLI.getRegisterTypeForCallingConv( + F.getContext(), F.getCallingConv(), VT); + for (unsigned i = 0; i < SplitLength; ++i) + VRegs.push_back(MRI.createGenericVirtualRegister(LLT{RegisterVT})); + + if (!handleSplit(VRegs, ArgLocs, ArgLocsIndex, Args[ArgsIndex].Reg)) + return false; + } else { + if (!assign(Args[ArgsIndex].Reg, ArgLocs[ArgLocsIndex])) + return false; + } + } + return true; +} + namespace { class IncomingValueHandler : public MipsCallLowering::MipsHandler { public: IncomingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI) : MipsHandler(MIRBuilder, MRI) {} - bool handle(ArrayRef ArgLocs, - ArrayRef Args); - private: void assignValueToReg(unsigned ValVReg, const CCValAssign &VA) override; @@ -53,6 +96,10 @@ private: void assignValueToAddress(unsigned ValVReg, const CCValAssign &VA) override; + bool handleSplit(SmallVectorImpl &VRegs, + ArrayRef ArgLocs, unsigned ArgLocsStartIndex, + unsigned ArgsReg) override; + virtual void markPhysRegUsed(unsigned PhysReg) { MIRBuilder.getMBB().addLiveIn(PhysReg); } @@ -128,12 +175,14 @@ void IncomingValueHandler::assignValueToAddress(unsigned ValVReg, buildLoad(ValVReg, VA); } -bool IncomingValueHandler::handle(ArrayRef ArgLocs, - ArrayRef Args) { - for (unsigned i = 0, ArgsSize = Args.size(); i < ArgsSize; ++i) { - if (!assign(Args[i].Reg, ArgLocs[i])) - return false; - } +bool IncomingValueHandler::handleSplit(SmallVectorImpl &VRegs, + ArrayRef ArgLocs, + unsigned ArgLocsStartIndex, + unsigned ArgsReg) { + if (!assignVRegs(VRegs, ArgLocs, ArgLocsStartIndex)) + return false; + setMostSignificantFirst(VRegs); + MIRBuilder.buildMerge(ArgsReg, VRegs); return true; } @@ -144,9 +193,6 @@ public: MachineInstrBuilder &MIB) : MipsHandler(MIRBuilder, MRI), MIB(MIB) {} - bool handle(ArrayRef ArgLocs, - ArrayRef Args); - private: void assignValueToReg(unsigned ValVReg, const CCValAssign &VA) override; @@ -155,6 +201,10 @@ private: void assignValueToAddress(unsigned ValVReg, const CCValAssign &VA) override; + bool handleSplit(SmallVectorImpl &VRegs, + ArrayRef ArgLocs, unsigned ArgLocsStartIndex, + unsigned ArgsReg) override; + unsigned extendRegister(unsigned ValReg, const CCValAssign &VA); MachineInstrBuilder &MIB; @@ -228,17 +278,20 @@ unsigned OutgoingValueHandler::extendRegister(unsigned ValReg, llvm_unreachable("unable to extend register"); } -bool OutgoingValueHandler::handle(ArrayRef ArgLocs, - ArrayRef Args) { - for (unsigned i = 0; i < Args.size(); ++i) { - if (!assign(Args[i].Reg, ArgLocs[i])) - return false; - } +bool OutgoingValueHandler::handleSplit(SmallVectorImpl &VRegs, + ArrayRef ArgLocs, + unsigned ArgLocsStartIndex, + unsigned ArgsReg) { + MIRBuilder.buildUnmerge(VRegs, ArgsReg); + setMostSignificantFirst(VRegs); + if (!assignVRegs(VRegs, ArgLocs, ArgLocsStartIndex)) + return false; + return true; } static bool isSupportedType(Type *T) { - if (T->isIntegerTy() && T->getScalarSizeInBits() <= 32) + if (T->isIntegerTy()) return true; if (T->isPointerTy()) return true; @@ -247,7 +300,9 @@ static bool isSupportedType(Type *T) { CCValAssign::LocInfo determineLocInfo(const MVT RegisterVT, const EVT VT, const ISD::ArgFlagsTy &Flags) { - if (VT.getSizeInBits() == RegisterVT.getSizeInBits()) + // > does not mean loss of information as type RegisterVT can't hold type VT, + // it means that type VT is split into multiple registers of type RegisterVT + if (VT.getSizeInBits() >= RegisterVT.getSizeInBits()) return CCValAssign::LocInfo::Full; if (Flags.isSExt()) return CCValAssign::LocInfo::SExt; @@ -304,12 +359,7 @@ bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, } SmallVector Outs; - subTargetRegTypeForCallingConv( - MIRBuilder, RetInfos, OrigArgIndices, - [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, - unsigned origIdx, unsigned partOffs) { - Outs.emplace_back(flags, vt, argvt, used, origIdx, partOffs); - }); + subTargetRegTypeForCallingConv(F, RetInfos, OrigArgIndices, Outs); SmallVector ArgLocs; MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, @@ -358,12 +408,7 @@ bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, } SmallVector Ins; - subTargetRegTypeForCallingConv( - MIRBuilder, ArgInfos, OrigArgIndices, - [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx, - unsigned partOffs) { - Ins.emplace_back(flags, vt, argvt, used, origIdx, partOffs); - }); + subTargetRegTypeForCallingConv(F, ArgInfos, OrigArgIndices, Ins); SmallVector ArgLocs; MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, @@ -440,12 +485,7 @@ bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, } SmallVector Outs; - subTargetRegTypeForCallingConv( - MIRBuilder, ArgInfos, OrigArgIndices, - [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx, - unsigned partOffs) { - Outs.emplace_back(flags, vt, argvt, used, origIdx, partOffs); - }); + subTargetRegTypeForCallingConv(F, ArgInfos, OrigArgIndices, Outs); SmallVector ArgLocs; MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, @@ -477,12 +517,7 @@ bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, splitToValueTypes(OrigRet, 0, ArgInfos, OrigRetIndices); SmallVector Ins; - subTargetRegTypeForCallingConv( - MIRBuilder, ArgInfos, OrigRetIndices, - [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, - unsigned origIdx, unsigned partOffs) { - Ins.emplace_back(flags, vt, argvt, used, origIdx, partOffs); - }); + subTargetRegTypeForCallingConv(F, ArgInfos, OrigRetIndices, Ins); SmallVector ArgLocs; MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, @@ -501,11 +536,10 @@ bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, return true; } +template void MipsCallLowering::subTargetRegTypeForCallingConv( - MachineIRBuilder &MIRBuilder, ArrayRef Args, - ArrayRef OrigArgIndices, const FunTy &PushBack) const { - MachineFunction &MF = MIRBuilder.getMF(); - const Function &F = MF.getFunction(); + const Function &F, ArrayRef Args, + ArrayRef OrigArgIndices, SmallVectorImpl &ISDArgs) const { const DataLayout &DL = F.getParent()->getDataLayout(); const MipsTargetLowering &TLI = *getTLI(); @@ -515,12 +549,20 @@ void MipsCallLowering::subTargetRegTypeForCallingConv( EVT VT = TLI.getValueType(DL, Arg.Ty); MVT RegisterVT = TLI.getRegisterTypeForCallingConv(F.getContext(), F.getCallingConv(), VT); + unsigned NumRegs = TLI.getNumRegistersForCallingConv( + F.getContext(), F.getCallingConv(), VT); - ISD::ArgFlagsTy Flags = Arg.Flags; - Flags.setOrigAlign(TLI.getABIAlignmentForCallingConv(Arg.Ty, DL)); + for (unsigned i = 0; i < NumRegs; ++i) { + ISD::ArgFlagsTy Flags = Arg.Flags; - PushBack(Flags, RegisterVT, VT, true, OrigArgIndices[ArgNo], 0); + if (i == 0) + Flags.setOrigAlign(TLI.getABIAlignmentForCallingConv(Arg.Ty, DL)); + else + Flags.setOrigAlign(1); + ISDArgs.emplace_back(Flags, RegisterVT, VT, true, OrigArgIndices[ArgNo], + 0); + } ++ArgNo; } } diff --git a/llvm/lib/Target/Mips/MipsCallLowering.h b/llvm/lib/Target/Mips/MipsCallLowering.h index 6481e4258cf1..389db3a3b681 100644 --- a/llvm/lib/Target/Mips/MipsCallLowering.h +++ b/llvm/lib/Target/Mips/MipsCallLowering.h @@ -31,13 +31,21 @@ public: virtual ~MipsHandler() = default; + bool handle(ArrayRef ArgLocs, + ArrayRef Args); + protected: - bool assign(unsigned VReg, const CCValAssign &VA); + bool assignVRegs(ArrayRef VRegs, ArrayRef ArgLocs, + unsigned Index); + + void setMostSignificantFirst(SmallVectorImpl &VRegs); MachineIRBuilder &MIRBuilder; MachineRegisterInfo &MRI; private: + bool assign(unsigned VReg, const CCValAssign &VA); + virtual unsigned getStackAddress(const CCValAssign &VA, MachineMemOperand *&MMO) = 0; @@ -45,6 +53,10 @@ public: virtual void assignValueToAddress(unsigned ValVReg, const CCValAssign &VA) = 0; + + virtual bool handleSplit(SmallVectorImpl &VRegs, + ArrayRef ArgLocs, + unsigned ArgLocsStartIndex, unsigned ArgsReg) = 0; }; MipsCallLowering(const MipsTargetLowering &TLI); @@ -60,18 +72,13 @@ public: ArrayRef OrigArgs) const override; private: - using FunTy = - std::function; - /// Based on registers available on target machine split or extend /// type if needed, also change pointer type to appropriate integer - /// type. Lambda will fill some info so we can tell MipsCCState to - /// assign physical registers. - void subTargetRegTypeForCallingConv(MachineIRBuilder &MIRBuilder, - ArrayRef Args, + /// type. + template + void subTargetRegTypeForCallingConv(const Function &F, ArrayRef Args, ArrayRef OrigArgIndices, - const FunTy &PushBack) const; + SmallVectorImpl &ISDArgs) const; /// Split structures and arrays, save original argument indices since /// Mips calling conv needs info about original argument type. diff --git a/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/split_args.ll b/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/split_args.ll new file mode 100644 index 000000000000..f51b72060de9 --- /dev/null +++ b/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/split_args.ll @@ -0,0 +1,106 @@ +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 + +define i64 @i64_reg(i64 %a) { + ; MIPS32-LABEL: name: i64_reg + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY1]](s32), [[COPY]](s32) + ; MIPS32: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[MV]](s64) + ; MIPS32: $v0 = COPY [[UV1]](s32) + ; MIPS32: $v1 = COPY [[UV]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 +entry: + ret i64 %a +} + +define i64 @i64_stack(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i64 %a) { + ; MIPS32-LABEL: name: i64_stack + ; MIPS32: fixedStack: + ; MIPS32-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 20, size: 4, alignment: 4, + ; MIPS32-DAG: - { id: [[STACK1:[0-9]+]], type: default, offset: 16, size: 4, alignment: 8, + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1, $a2, $a3 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY $a2 + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY $a3 + ; MIPS32: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.1 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.[[STACK1]], align 0) + ; MIPS32: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0 + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX1]](p0) :: (load 4 from %fixed-stack.[[STACK0]], align 0) + ; MIPS32: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[LOAD1]](s32), [[LOAD]](s32) + ; MIPS32: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[MV]](s64) + ; MIPS32: $v0 = COPY [[UV1]](s32) + ; MIPS32: $v1 = COPY [[UV]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 +entry: + ret i64 %a +} + +define i64 @i64_reg_allign(i32 %a0, i64 %a) { + ; MIPS32-LABEL: name: i64_reg_allign + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a2, $a3 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a2 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY $a3 + ; MIPS32: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY2]](s32), [[COPY1]](s32) + ; MIPS32: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[MV]](s64) + ; MIPS32: $v0 = COPY [[UV1]](s32) + ; MIPS32: $v1 = COPY [[UV]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 +entry: + ret i64 %a +} + +define i64 @i64_stack_allign(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %s16, i64 %a) { + ; MIPS32-LABEL: name: i64_stack_allign + ; MIPS32: fixedStack: + ; MIPS32-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 28, size: 4, alignment: 4, + ; MIPS32-DAG: - { id: [[STACK1:[0-9]+]], type: default, offset: 24, size: 4, alignment: 8, + ; MIPS32-DAG: - { id: [[STACK2:[0-9]+]], type: default, offset: 16, size: 4, alignment: 8, + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1, $a2, $a3 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY $a2 + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY $a3 + ; MIPS32: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.2 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.[[STACK2]], align 0) + ; MIPS32: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.1 + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX1]](p0) :: (load 4 from %fixed-stack.[[STACK1]], align 0) + ; MIPS32: [[FRAME_INDEX2:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0 + ; MIPS32: [[LOAD2:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX2]](p0) :: (load 4 from %fixed-stack.[[STACK0]], align 0) + ; MIPS32: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[LOAD2]](s32), [[LOAD1]](s32) + ; MIPS32: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[MV]](s64) + ; MIPS32: $v0 = COPY [[UV1]](s32) + ; MIPS32: $v1 = COPY [[UV]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 +entry: + ret i64 %a +} + +define i64 @i64_reg_stack(i32 %a0, i32 %a1, i32 %a2, i64 %a) { + ; MIPS32-LABEL: name: i64_reg_stack + ; MIPS32: fixedStack: + ; MIPS32-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 20, size: 4, alignment: 4, + ; MIPS32-DAG: - { id: [[STACK1:[0-9]+]], type: default, offset: 16, size: 4, alignment: 8, + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1, $a2 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY $a2 + ; MIPS32: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.1 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.[[STACK1]], align 0) + ; MIPS32: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0 + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX1]](p0) :: (load 4 from %fixed-stack.[[STACK0]], align 0) + ; MIPS32: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[LOAD1]](s32), [[LOAD]](s32) + ; MIPS32: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[MV]](s64) + ; MIPS32: $v0 = COPY [[UV1]](s32) + ; MIPS32: $v1 = COPY [[UV]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 +entry: + ret i64 %a +}