Index: llvm/trunk/lib/Target/Mips/MipsCallLowering.h =================================================================== --- llvm/trunk/lib/Target/Mips/MipsCallLowering.h +++ llvm/trunk/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: llvm/trunk/lib/Target/Mips/MipsCallLowering.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsCallLowering.cpp +++ llvm/trunk/lib/Target/Mips/MipsCallLowering.cpp @@ -358,7 +358,7 @@ return true; } -static bool isSupportedType(Type *T) { +static bool isSupportedArgumentType(Type *T) { if (T->isIntegerTy()) return true; if (T->isPointerTy()) @@ -368,6 +368,18 @@ return false; } +static bool isSupportedReturnType(Type *T) { + if (T->isIntegerTy()) + return true; + if (T->isPointerTy()) + return true; + if (T->isFloatingPointTy()) + return true; + if (T->isAggregateType()) + return true; + return false; +} + static CCValAssign::LocInfo determineLocInfo(const MVT RegisterVT, const EVT VT, const ISD::ArgFlagsTy &Flags) { // > does not mean loss of information as type RegisterVT can't hold type VT, @@ -404,7 +416,7 @@ MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA); - if (Val != nullptr && !isSupportedType(Val->getType())) + if (Val != nullptr && !isSupportedReturnType(Val->getType())) return false; if (!VRegs.empty()) { @@ -412,21 +424,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); @@ -455,7 +459,7 @@ return true; for (auto &Arg : F.args()) { - if (!isSupportedType(Arg.getType())) + if (!isSupportedArgumentType(Arg.getType())) return false; } @@ -469,7 +473,8 @@ for (auto &Arg : F.args()) { ArgInfo AInfo(VRegs[i], Arg.getType()); setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F); - splitToValueTypes(AInfo, i, ArgInfos, OrigArgIndices); + ArgInfos.push_back(AInfo); + OrigArgIndices.push_back(i); ++i; } @@ -536,7 +541,7 @@ return false; for (auto &Arg : Info.OrigArgs) { - if (!isSupportedType(Arg.Ty)) + if (!isSupportedArgumentType(Arg.Ty)) return false; if (Arg.Flags[0].isByVal()) return false; @@ -544,11 +549,12 @@ return false; } - if (!Info.OrigRet.Ty->isVoidTy() && !isSupportedType(Info.OrigRet.Ty)) + if (!Info.OrigRet.Ty->isVoidTy() && !isSupportedReturnType(Info.OrigRet.Ty)) return false; 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 +594,8 @@ Entry.Ty = Arg.Ty; FuncOrigArgs.push_back(Entry); - splitToValueTypes(Arg, i, ArgInfos, OrigArgIndices); + ArgInfos.push_back(Arg); + OrigArgIndices.push_back(i); ++i; } @@ -639,7 +646,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 +700,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: llvm/trunk/test/CodeGen/Mips/GlobalISel/irtranslator/aggregate_struct_return.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/GlobalISel/irtranslator/aggregate_struct_return.ll +++ llvm/trunk/test/CodeGen/Mips/GlobalISel/irtranslator/aggregate_struct_return.ll @@ -0,0 +1,132 @@ +; 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 } @add_complex_float({ float, float }* %a, { float, float }* %b) { + ; MIPS32-LABEL: name: add_complex_float + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(p0) = COPY $a1 + ; MIPS32: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF + ; MIPS32: [[COPY2:%[0-9]+]]:_(p0) = COPY [[COPY]](p0) + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[COPY2]](p0) :: (load 4 from %ir..realp) + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 + ; MIPS32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s32) + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[GEP]](p0) :: (load 4 from %ir..imagp) + ; MIPS32: [[COPY3:%[0-9]+]]:_(p0) = COPY [[COPY1]](p0) + ; MIPS32: [[LOAD2:%[0-9]+]]:_(s32) = G_LOAD [[COPY3]](p0) :: (load 4 from %ir..realp1) + ; MIPS32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C]](s32) + ; MIPS32: [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP1]](p0) :: (load 4 from %ir..imagp3) + ; MIPS32: [[FADD:%[0-9]+]]:_(s32) = G_FADD [[LOAD]], [[LOAD2]] + ; MIPS32: [[FADD1:%[0-9]+]]:_(s32) = G_FADD [[LOAD1]], [[LOAD3]] + ; MIPS32: $f0 = COPY [[FADD]](s32) + ; MIPS32: $f2 = COPY [[FADD1]](s32) + ; MIPS32: RetRA implicit $f0, implicit $f2 +entry: + %.realp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 0 + %.real = load float, float* %.realp, align 4 + %.imagp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 1 + %.imag = load float, float* %.imagp, align 4 + %.realp1 = getelementptr inbounds { float, float }, { float, float }* %b, i32 0, i32 0 + %.real2 = load float, float* %.realp1, align 4 + %.imagp3 = getelementptr inbounds { float, float }, { float, float }* %b, i32 0, i32 1 + %.imag4 = load float, float* %.imagp3, align 4 + %add.r = fadd float %.real, %.real2 + %add.i = fadd float %.imag, %.imag4 + %.fca.0.insert = insertvalue { float, float } undef, float %add.r, 0 + %.fca.1.insert = insertvalue { float, float } %.fca.0.insert, float %add.i, 1 + ret { float, float } %.fca.1.insert +} + +define { double, double } @add_complex_double({ double, double }* %a, { double, double }* %b) { + ; MIPS32-LABEL: name: add_complex_double + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(p0) = COPY $a1 + ; MIPS32: [[DEF:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF + ; MIPS32: [[COPY2:%[0-9]+]]:_(p0) = COPY [[COPY]](p0) + ; MIPS32: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY2]](p0) :: (load 8 from %ir..realp) + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 + ; MIPS32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s32) + ; MIPS32: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8 from %ir..imagp) + ; MIPS32: [[COPY3:%[0-9]+]]:_(p0) = COPY [[COPY1]](p0) + ; MIPS32: [[LOAD2:%[0-9]+]]:_(s64) = G_LOAD [[COPY3]](p0) :: (load 8 from %ir..realp1) + ; MIPS32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[COPY1]], [[C]](s32) + ; MIPS32: [[LOAD3:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir..imagp3) + ; MIPS32: [[FADD:%[0-9]+]]:_(s64) = G_FADD [[LOAD]], [[LOAD2]] + ; MIPS32: [[FADD1:%[0-9]+]]:_(s64) = G_FADD [[LOAD1]], [[LOAD3]] + ; MIPS32: $d0 = COPY [[FADD]](s64) + ; MIPS32: $d1 = COPY [[FADD1]](s64) + ; MIPS32: RetRA implicit $d0, implicit $d1 +entry: + %.realp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 0 + %.real = load double, double* %.realp, align 8 + %.imagp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 1 + %.imag = load double, double* %.imagp, align 8 + %.realp1 = getelementptr inbounds { double, double }, { double, double }* %b, i32 0, i32 0 + %.real2 = load double, double* %.realp1, align 8 + %.imagp3 = getelementptr inbounds { double, double }, { double, double }* %b, i32 0, i32 1 + %.imag4 = load double, double* %.imagp3, align 8 + %add.r = fadd double %.real, %.real2 + %add.i = fadd double %.imag, %.imag4 + %.fca.0.insert = insertvalue { double, double } undef, double %add.r, 0 + %.fca.1.insert = insertvalue { double, double } %.fca.0.insert, double %add.i, 1 + ret { double, double } %.fca.1.insert +} + +declare { float, float } @ret_complex_float() +define void @call_ret_complex_float({ float, float }* %z) { + ; MIPS32-LABEL: name: call_ret_complex_float + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: ADJCALLSTACKDOWN 16, 0, implicit-def $sp, implicit $sp + ; MIPS32: JAL @ret_complex_float, csr_o32, implicit-def $ra, implicit-def $sp, implicit-def $f0, implicit-def $f2 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $f0 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY $f2 + ; MIPS32: ADJCALLSTACKUP 16, 0, implicit-def $sp, implicit $sp + ; MIPS32: [[COPY3:%[0-9]+]]:_(p0) = COPY [[COPY]](p0) + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 + ; MIPS32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s32) + ; MIPS32: G_STORE [[COPY1]](s32), [[COPY3]](p0) :: (store 4 into %ir..realp) + ; MIPS32: G_STORE [[COPY2]](s32), [[GEP]](p0) :: (store 4 into %ir..imagp) + ; MIPS32: RetRA +entry: + %call = call { float, float } @ret_complex_float() + %0 = extractvalue { float, float } %call, 0 + %1 = extractvalue { float, float } %call, 1 + %.realp = getelementptr inbounds { float, float }, { float, float }* %z, i32 0, i32 0 + %.imagp = getelementptr inbounds { float, float }, { float, float }* %z, i32 0, i32 1 + store float %0, float* %.realp, align 4 + store float %1, float* %.imagp, align 4 + ret void +} + +declare { double, double } @ret_complex_double() +define void @call_ret_complex_double({ double, double }* %z) { + ; MIPS32-LABEL: name: call_ret_complex_double + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: ADJCALLSTACKDOWN 16, 0, implicit-def $sp, implicit $sp + ; MIPS32: JAL @ret_complex_double, csr_o32, implicit-def $ra, implicit-def $sp, implicit-def $d0, implicit-def $d1 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s64) = COPY $d0 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s64) = COPY $d1 + ; MIPS32: ADJCALLSTACKUP 16, 0, implicit-def $sp, implicit $sp + ; MIPS32: [[COPY3:%[0-9]+]]:_(p0) = COPY [[COPY]](p0) + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 + ; MIPS32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s32) + ; MIPS32: G_STORE [[COPY1]](s64), [[COPY3]](p0) :: (store 8 into %ir..realp) + ; MIPS32: G_STORE [[COPY2]](s64), [[GEP]](p0) :: (store 8 into %ir..imagp) + ; MIPS32: RetRA +entry: + %call = call { double, double } @ret_complex_double() + %0 = extractvalue { double, double } %call, 0 + %1 = extractvalue { double, double } %call, 1 + %.realp = getelementptr inbounds { double, double }, { double, double }* %z, i32 0, i32 0 + %.imagp = getelementptr inbounds { double, double }, { double, double }* %z, i32 0, i32 1 + store double %0, double* %.realp, align 8 + store double %1, double* %.imagp, align 8 + ret void +} Index: llvm/trunk/test/CodeGen/Mips/GlobalISel/llvm-ir/aggregate_struct_return.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/GlobalISel/llvm-ir/aggregate_struct_return.ll +++ llvm/trunk/test/CodeGen/Mips/GlobalISel/llvm-ir/aggregate_struct_return.ll @@ -0,0 +1,114 @@ +; 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 } @add_complex_float({ float, float }* %a, { float, float }* %b) { +; MIPS32-LABEL: add_complex_float: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lwc1 $f0, 0($4) +; MIPS32-NEXT: lwc1 $f1, 4($4) +; MIPS32-NEXT: lwc1 $f2, 0($5) +; MIPS32-NEXT: lwc1 $f3, 4($5) +; MIPS32-NEXT: add.s $f0, $f0, $f2 +; MIPS32-NEXT: add.s $f2, $f1, $f3 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %.realp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 0 + %.real = load float, float* %.realp, align 4 + %.imagp = getelementptr inbounds { float, float }, { float, float }* %a, i32 0, i32 1 + %.imag = load float, float* %.imagp, align 4 + %.realp1 = getelementptr inbounds { float, float }, { float, float }* %b, i32 0, i32 0 + %.real2 = load float, float* %.realp1, align 4 + %.imagp3 = getelementptr inbounds { float, float }, { float, float }* %b, i32 0, i32 1 + %.imag4 = load float, float* %.imagp3, align 4 + %add.r = fadd float %.real, %.real2 + %add.i = fadd float %.imag, %.imag4 + %.fca.0.insert = insertvalue { float, float } undef, float %add.r, 0 + %.fca.1.insert = insertvalue { float, float } %.fca.0.insert, float %add.i, 1 + ret { float, float } %.fca.1.insert +} + +define { double, double } @add_complex_double({ double, double }* %a, { double, double }* %b) { +; MIPS32-LABEL: add_complex_double: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: ldc1 $f0, 0($4) +; MIPS32-NEXT: ldc1 $f2, 8($4) +; MIPS32-NEXT: ldc1 $f4, 0($5) +; MIPS32-NEXT: ldc1 $f6, 8($5) +; MIPS32-NEXT: add.d $f0, $f0, $f4 +; MIPS32-NEXT: add.d $f2, $f2, $f6 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %.realp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 0 + %.real = load double, double* %.realp, align 8 + %.imagp = getelementptr inbounds { double, double }, { double, double }* %a, i32 0, i32 1 + %.imag = load double, double* %.imagp, align 8 + %.realp1 = getelementptr inbounds { double, double }, { double, double }* %b, i32 0, i32 0 + %.real2 = load double, double* %.realp1, align 8 + %.imagp3 = getelementptr inbounds { double, double }, { double, double }* %b, i32 0, i32 1 + %.imag4 = load double, double* %.imagp3, align 8 + %add.r = fadd double %.real, %.real2 + %add.i = fadd double %.imag, %.imag4 + %.fca.0.insert = insertvalue { double, double } undef, double %add.r, 0 + %.fca.1.insert = insertvalue { double, double } %.fca.0.insert, double %add.i, 1 + ret { double, double } %.fca.1.insert +} + +declare { float, float } @ret_complex_float() +define void @call_ret_complex_float({ float, float }* %z) { +; MIPS32-LABEL: call_ret_complex_float: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: addiu $sp, $sp, -24 +; MIPS32-NEXT: .cfi_def_cfa_offset 24 +; MIPS32-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill +; MIPS32-NEXT: .cfi_offset 31, -4 +; MIPS32-NEXT: sw $4, 16($sp) # 4-byte Folded Spill +; MIPS32-NEXT: jal ret_complex_float +; MIPS32-NEXT: nop +; MIPS32-NEXT: lw $1, 16($sp) # 4-byte Folded Reload +; MIPS32-NEXT: swc1 $f0, 0($1) +; MIPS32-NEXT: swc1 $f2, 4($1) +; MIPS32-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload +; MIPS32-NEXT: addiu $sp, $sp, 24 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %call = call { float, float } @ret_complex_float() + %0 = extractvalue { float, float } %call, 0 + %1 = extractvalue { float, float } %call, 1 + %.realp = getelementptr inbounds { float, float }, { float, float }* %z, i32 0, i32 0 + %.imagp = getelementptr inbounds { float, float }, { float, float }* %z, i32 0, i32 1 + store float %0, float* %.realp, align 4 + store float %1, float* %.imagp, align 4 + ret void +} + +declare { double, double } @ret_complex_double() +define void @call_ret_complex_double({ double, double }* %z) { +; MIPS32-LABEL: call_ret_complex_double: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: addiu $sp, $sp, -24 +; MIPS32-NEXT: .cfi_def_cfa_offset 24 +; MIPS32-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill +; MIPS32-NEXT: .cfi_offset 31, -4 +; MIPS32-NEXT: sw $4, 16($sp) # 4-byte Folded Spill +; MIPS32-NEXT: jal ret_complex_double +; MIPS32-NEXT: nop +; MIPS32-NEXT: lw $1, 16($sp) # 4-byte Folded Reload +; MIPS32-NEXT: sdc1 $f0, 0($1) +; MIPS32-NEXT: sdc1 $f2, 8($1) +; MIPS32-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload +; MIPS32-NEXT: addiu $sp, $sp, 24 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %call = call { double, double } @ret_complex_double() + %0 = extractvalue { double, double } %call, 0 + %1 = extractvalue { double, double } %call, 1 + %.realp = getelementptr inbounds { double, double }, { double, double }* %z, i32 0, i32 0 + %.imagp = getelementptr inbounds { double, double }, { double, double }* %z, i32 0, i32 1 + store double %0, double* %.realp, align 8 + store double %1, double* %.imagp, align 8 + ret void +}