Index: lib/Target/Mips/MipsCallLowering.h =================================================================== --- lib/Target/Mips/MipsCallLowering.h +++ lib/Target/Mips/MipsCallLowering.h @@ -82,7 +82,8 @@ /// Split structures and arrays, save original argument indices since /// Mips calling convention needs info about original argument type. - void splitToValueTypes(const ArgInfo &OrigArg, unsigned OriginalIndex, + void splitToValueTypes(const DataLayout &DL, const ArgInfo &OrigArg, + unsigned OriginalIndex, SmallVectorImpl &SplitArgs, SmallVectorImpl &SplitArgsOrigIndices) const; }; Index: lib/Target/Mips/MipsCallLowering.cpp =================================================================== --- lib/Target/Mips/MipsCallLowering.cpp +++ lib/Target/Mips/MipsCallLowering.cpp @@ -365,6 +365,8 @@ return true; if (T->isFloatingPointTy()) return true; + if (T->isAggregateType()) + return true; return false; } @@ -412,21 +414,13 @@ const Function &F = MF.getFunction(); const DataLayout &DL = MF.getDataLayout(); const MipsTargetLowering &TLI = *getTLI(); - LLVMContext &Ctx = Val->getType()->getContext(); - - SmallVector SplitEVTs; - ComputeValueVTs(TLI, DL, Val->getType(), SplitEVTs); - assert(VRegs.size() == SplitEVTs.size() && - "For each split Type there should be exactly one VReg."); SmallVector RetInfos; SmallVector OrigArgIndices; - for (unsigned i = 0; i < SplitEVTs.size(); ++i) { - ArgInfo CurArgInfo = ArgInfo{VRegs[i], SplitEVTs[i].getTypeForEVT(Ctx)}; - setArgFlags(CurArgInfo, AttributeList::ReturnIndex, DL, F); - splitToValueTypes(CurArgInfo, 0, RetInfos, OrigArgIndices); - } + ArgInfo ArgRetInfo(VRegs, Val->getType()); + setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F); + splitToValueTypes(DL, ArgRetInfo, 0, RetInfos, OrigArgIndices); SmallVector Outs; subTargetRegTypeForCallingConv(F, RetInfos, OrigArgIndices, Outs); @@ -469,7 +463,7 @@ for (auto &Arg : F.args()) { ArgInfo AInfo(VRegs[i], Arg.getType()); setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F); - splitToValueTypes(AInfo, i, ArgInfos, OrigArgIndices); + splitToValueTypes(DL, AInfo, i, ArgInfos, OrigArgIndices); ++i; } @@ -549,6 +543,7 @@ MachineFunction &MF = MIRBuilder.getMF(); const Function &F = MF.getFunction(); + const DataLayout &DL = MF.getDataLayout(); const MipsTargetLowering &TLI = *getTLI(); const MipsTargetMachine &TM = static_cast(MF.getTarget()); @@ -588,7 +583,7 @@ Entry.Ty = Arg.Ty; FuncOrigArgs.push_back(Entry); - splitToValueTypes(Arg, i, ArgInfos, OrigArgIndices); + splitToValueTypes(DL, Arg, i, ArgInfos, OrigArgIndices); ++i; } @@ -639,7 +634,7 @@ ArgInfos.clear(); SmallVector OrigRetIndices; - splitToValueTypes(Info.OrigRet, 0, ArgInfos, OrigRetIndices); + splitToValueTypes(DL, Info.OrigRet, 0, ArgInfos, OrigRetIndices); SmallVector Ins; subTargetRegTypeForCallingConv(F, ArgInfos, OrigRetIndices, Ins); @@ -693,12 +688,21 @@ } void MipsCallLowering::splitToValueTypes( - const ArgInfo &OrigArg, unsigned OriginalIndex, + const DataLayout &DL, const ArgInfo &OrigArg, unsigned OriginalIndex, SmallVectorImpl &SplitArgs, SmallVectorImpl &SplitArgsOrigIndices) const { - // TODO : perform structure and array split. For now we only deal with - // types that pass isSupportedType check. - SplitArgs.push_back(OrigArg); - SplitArgsOrigIndices.push_back(OriginalIndex); + SmallVector SplitEVTs; + SmallVector SplitVRegs; + const MipsTargetLowering &TLI = *getTLI(); + LLVMContext &Ctx = OrigArg.Ty->getContext(); + + ComputeValueVTs(TLI, DL, OrigArg.Ty, SplitEVTs); + + for (unsigned i = 0; i < SplitEVTs.size(); ++i) { + ArgInfo Info = ArgInfo{OrigArg.Regs[i], SplitEVTs[i].getTypeForEVT(Ctx)}; + Info.Flags = OrigArg.Flags; + SplitArgs.push_back(Info); + SplitArgsOrigIndices.push_back(OriginalIndex); + } } Index: test/CodeGen/Mips/GlobalISel/irtranslator/aggregate_struct_return.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/irtranslator/aggregate_struct_return.ll @@ -0,0 +1,108 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 + +define { float, float } @ret_complex_float(i32 inreg %a.coerce0, i32 inreg %a.coerce1) { + ; MIPS32-LABEL: name: ret_complex_float + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.retval + ; MIPS32: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1.a + ; MIPS32: [[COPY2:%[0-9]+]]:_(p0) = COPY [[FRAME_INDEX1]](p0) + ; MIPS32: G_STORE [[COPY]](s32), [[COPY2]](p0) :: (store 4 into %ir.1) + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 + ; MIPS32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX1]], [[C]](s32) + ; MIPS32: G_STORE [[COPY1]](s32), [[GEP]](p0) :: (store 4 into %ir.2) + ; MIPS32: [[COPY3:%[0-9]+]]:_(p0) = COPY [[FRAME_INDEX1]](p0) + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[COPY3]](p0) :: (load 4 from %ir.a.realp) + ; MIPS32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX1]], [[C]](s32) + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[GEP1]](p0) :: (load 4 from %ir.a.imagp) + ; MIPS32: [[COPY4:%[0-9]+]]:_(p0) = COPY [[FRAME_INDEX]](p0) + ; MIPS32: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX]], [[C]](s32) + ; MIPS32: G_STORE [[LOAD]](s32), [[COPY4]](p0) :: (store 4 into %ir.retval.realp) + ; MIPS32: G_STORE [[LOAD1]](s32), [[GEP2]](p0) :: (store 4 into %ir.retval.imagp) + ; MIPS32: [[LOAD2:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %ir.retval) + ; MIPS32: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX]], [[C]](s32) + ; MIPS32: [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load 4 from %ir.retval + 4) + ; MIPS32: $f0 = COPY [[LOAD2]](s32) + ; MIPS32: $f2 = COPY [[LOAD3]](s32) + ; MIPS32: RetRA implicit $f0, implicit $f2 +entry: + %retval = alloca { float, float }, align 4 + %a = alloca { float, float }, align 4 + %0 = bitcast { float, float }* %a to { i32, i32 }* + %1 = getelementptr inbounds { i32, i32 }, { i32, i32 }* %0, i32 0, i32 0 + store i32 %a.coerce0, i32* %1, align 4 + %2 = getelementptr inbounds { i32, i32 }, { i32, i32 }* %0, i32 0, i32 1 + store i32 %a.coerce1, i32* %2, align 4 + %a.realp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 0 + %a.real = load float, float* %a.realp, align 4 + %a.imagp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 1 + %a.imag = load float, float* %a.imagp, align 4 + %retval.realp = getelementptr inbounds { float, float }, { float, float }* %retval, i32 0, i32 0 + %retval.imagp = getelementptr inbounds { float, float }, { float, float }* %retval, i32 0, i32 1 + store float %a.real, float* %retval.realp, align 4 + store float %a.imag, float* %retval.imagp, align 4 + %3 = load { float, float }, { float, float }* %retval, align 4 + ret { float, float } %3 +} + +define { double, double } @ret_complex_double(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %a.coerce2, i32 inreg %a.coerce3) { + ; MIPS32-LABEL: name: ret_complex_double + ; 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 %stack.0.retval + ; MIPS32: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1.a + ; MIPS32: [[COPY4:%[0-9]+]]:_(p0) = COPY [[FRAME_INDEX1]](p0) + ; MIPS32: G_STORE [[COPY]](s32), [[COPY4]](p0) :: (store 4 into %ir.1, align 8) + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 + ; MIPS32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX1]], [[C]](s32) + ; MIPS32: G_STORE [[COPY1]](s32), [[GEP]](p0) :: (store 4 into %ir.2) + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 + ; MIPS32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX1]], [[C1]](s32) + ; MIPS32: G_STORE [[COPY2]](s32), [[GEP1]](p0) :: (store 4 into %ir.3, align 8) + ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 12 + ; MIPS32: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX1]], [[C2]](s32) + ; MIPS32: G_STORE [[COPY3]](s32), [[GEP2]](p0) :: (store 4 into %ir.4) + ; MIPS32: [[COPY5:%[0-9]+]]:_(p0) = COPY [[FRAME_INDEX1]](p0) + ; MIPS32: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY5]](p0) :: (load 8 from %ir.a.realp) + ; MIPS32: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX1]], [[C1]](s32) + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP3]](p0) :: (load 8 from %ir.a.imagp) + ; MIPS32: [[COPY6:%[0-9]+]]:_(p0) = COPY [[FRAME_INDEX]](p0) + ; MIPS32: [[GEP4:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX]], [[C1]](s32) + ; MIPS32: G_STORE [[LOAD]](s64), [[COPY6]](p0) :: (store 8 into %ir.retval.realp) + ; MIPS32: G_STORE [[LOAD1]](s64), [[GEP4]](p0) :: (store 8 into %ir.retval.imagp) + ; MIPS32: [[LOAD2:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX]](p0) :: (load 8 from %ir.retval) + ; MIPS32: [[GEP5:%[0-9]+]]:_(p0) = G_GEP [[FRAME_INDEX]], [[C1]](s32) + ; MIPS32: [[LOAD3:%[0-9]+]]:_(s64) = G_LOAD [[GEP5]](p0) :: (load 8 from %ir.retval + 8) + ; MIPS32: $d0 = COPY [[LOAD2]](s64) + ; MIPS32: $d1 = COPY [[LOAD3]](s64) + ; MIPS32: RetRA implicit $d0, implicit $d1 +entry: + %retval = alloca { double, double }, align 8 + %a = alloca { double, double }, align 8 + %0 = bitcast { double, double }* %a to { i32, i32, i32, i32 }* + %1 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 0 + store i32 %a.coerce0, i32* %1, align 8 + %2 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 1 + store i32 %a.coerce1, i32* %2, align 4 + %3 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 2 + store i32 %a.coerce2, i32* %3, align 8 + %4 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 3 + store i32 %a.coerce3, i32* %4, align 4 + %a.realp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 0 + %a.real = load double, double* %a.realp, align 8 + %a.imagp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 1 + %a.imag = load double, double* %a.imagp, align 8 + %retval.realp = getelementptr inbounds { double, double }, { double, double }* %retval, i32 0, i32 0 + %retval.imagp = getelementptr inbounds { double, double }, { double, double }* %retval, i32 0, i32 1 + store double %a.real, double* %retval.realp, align 8 + store double %a.imag, double* %retval.imagp, align 8 + %5 = load { double, double }, { double, double }* %retval, align 8 + ret { double, double } %5 +} Index: test/CodeGen/Mips/GlobalISel/llvm-ir/aggregate_struct_return.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/llvm-ir/aggregate_struct_return.ll @@ -0,0 +1,84 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 + +define { float, float } @ret_complex_float(i32 inreg %a.coerce0, i32 inreg %a.coerce1) { +; MIPS32-LABEL: ret_complex_float: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: addiu $sp, $sp, -16 +; MIPS32-NEXT: .cfi_def_cfa_offset 16 +; MIPS32-NEXT: addiu $1, $sp, 8 +; MIPS32-NEXT: addiu $2, $sp, 0 +; MIPS32-NEXT: sw $4, 0($2) +; MIPS32-NEXT: sw $5, 4($2) +; MIPS32-NEXT: lw $3, 0($2) +; MIPS32-NEXT: lw $2, 4($2) +; MIPS32-NEXT: sw $3, 0($1) +; MIPS32-NEXT: sw $2, 4($1) +; MIPS32-NEXT: lwc1 $f0, 0($1) +; MIPS32-NEXT: lwc1 $f2, 4($1) +; MIPS32-NEXT: addiu $sp, $sp, 16 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %retval = alloca { float, float }, align 4 + %a = alloca { float, float }, align 4 + %0 = bitcast { float, float }* %a to { i32, i32 }* + %1 = getelementptr inbounds { i32, i32 }, { i32, i32 }* %0, i32 0, i32 0 + store i32 %a.coerce0, i32* %1, align 4 + %2 = getelementptr inbounds { i32, i32 }, { i32, i32 }* %0, i32 0, i32 1 + store i32 %a.coerce1, i32* %2, align 4 + %a.realp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 0 + %a.real = load float, float* %a.realp, align 4 + %a.imagp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 1 + %a.imag = load float, float* %a.imagp, align 4 + %retval.realp = getelementptr inbounds { float, float }, { float, float }* %retval, i32 0, i32 0 + %retval.imagp = getelementptr inbounds { float, float }, { float, float }* %retval, i32 0, i32 1 + store float %a.real, float* %retval.realp, align 4 + store float %a.imag, float* %retval.imagp, align 4 + %3 = load { float, float }, { float, float }* %retval, align 4 + ret { float, float } %3 +} + +define { double, double } @ret_complex_double(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %a.coerce2, i32 inreg %a.coerce3) { +; MIPS32-LABEL: ret_complex_double: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: addiu $sp, $sp, -32 +; MIPS32-NEXT: .cfi_def_cfa_offset 32 +; MIPS32-NEXT: addiu $1, $sp, 16 +; MIPS32-NEXT: addiu $2, $sp, 0 +; MIPS32-NEXT: sw $4, 0($2) +; MIPS32-NEXT: sw $5, 4($2) +; MIPS32-NEXT: sw $6, 8($2) +; MIPS32-NEXT: sw $7, 12($2) +; MIPS32-NEXT: ldc1 $f0, 0($2) +; MIPS32-NEXT: ldc1 $f2, 8($2) +; MIPS32-NEXT: sdc1 $f0, 0($1) +; MIPS32-NEXT: sdc1 $f2, 8($1) +; MIPS32-NEXT: ldc1 $f0, 0($1) +; MIPS32-NEXT: ldc1 $f2, 8($1) +; MIPS32-NEXT: addiu $sp, $sp, 32 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %retval = alloca { double, double }, align 8 + %a = alloca { double, double }, align 8 + %0 = bitcast { double, double }* %a to { i32, i32, i32, i32 }* + %1 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 0 + store i32 %a.coerce0, i32* %1, align 8 + %2 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 1 + store i32 %a.coerce1, i32* %2, align 4 + %3 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 2 + store i32 %a.coerce2, i32* %3, align 8 + %4 = getelementptr inbounds { i32, i32, i32, i32 }, { i32, i32, i32, i32 }* %0, i32 0, i32 3 + store i32 %a.coerce3, i32* %4, align 4 + %a.realp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 0 + %a.real = load double, double* %a.realp, align 8 + %a.imagp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 1 + %a.imag = load double, double* %a.imagp, align 8 + %retval.realp = getelementptr inbounds { double, double }, { double, double }* %retval, i32 0, i32 0 + %retval.imagp = getelementptr inbounds { double, double }, { double, double }* %retval, i32 0, i32 1 + store double %a.real, double* %retval.realp, align 8 + store double %a.imag, double* %retval.imagp, align 8 + %5 = load { double, double }, { double, double }* %retval, align 8 + ret { double, double } %5 +}