return true;
}
-static bool isSupportedType(Type *T) {
+static bool isSupportedArgumentType(Type *T) {
if (T->isIntegerTy())
return true;
if (T->isPointerTy())
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,
MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA);
- if (Val != nullptr && !isSupportedType(Val->getType()))
+ if (Val != nullptr && !isSupportedReturnType(Val->getType()))
return false;
if (!VRegs.empty()) {
const Function &F = MF.getFunction();
const DataLayout &DL = MF.getDataLayout();
const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
- LLVMContext &Ctx = Val->getType()->getContext();
-
- SmallVector<EVT, 4> SplitEVTs;
- ComputeValueVTs(TLI, DL, Val->getType(), SplitEVTs);
- assert(VRegs.size() == SplitEVTs.size() &&
- "For each split Type there should be exactly one VReg.");
SmallVector<ArgInfo, 8> RetInfos;
SmallVector<unsigned, 8> 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<ISD::OutputArg, 8> Outs;
subTargetRegTypeForCallingConv(F, RetInfos, OrigArgIndices, Outs);
return true;
for (auto &Arg : F.args()) {
- if (!isSupportedType(Arg.getType()))
+ if (!isSupportedArgumentType(Arg.getType()))
return false;
}
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;
}
return false;
for (auto &Arg : Info.OrigArgs) {
- if (!isSupportedType(Arg.Ty))
+ if (!isSupportedArgumentType(Arg.Ty))
return false;
if (Arg.Flags[0].isByVal())
return false;
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<MipsTargetLowering>();
const MipsTargetMachine &TM =
static_cast<const MipsTargetMachine &>(MF.getTarget());
Entry.Ty = Arg.Ty;
FuncOrigArgs.push_back(Entry);
- splitToValueTypes(Arg, i, ArgInfos, OrigArgIndices);
+ ArgInfos.push_back(Arg);
+ OrigArgIndices.push_back(i);
++i;
}
ArgInfos.clear();
SmallVector<unsigned, 8> OrigRetIndices;
- splitToValueTypes(Info.OrigRet, 0, ArgInfos, OrigRetIndices);
+ splitToValueTypes(DL, Info.OrigRet, 0, ArgInfos, OrigRetIndices);
SmallVector<ISD::InputArg, 8> Ins;
subTargetRegTypeForCallingConv(F, ArgInfos, OrigRetIndices, Ins);
}
void MipsCallLowering::splitToValueTypes(
- const ArgInfo &OrigArg, unsigned OriginalIndex,
+ const DataLayout &DL, const ArgInfo &OrigArg, unsigned OriginalIndex,
SmallVectorImpl<ArgInfo> &SplitArgs,
SmallVectorImpl<unsigned> &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<EVT, 4> SplitEVTs;
+ SmallVector<Register, 4> SplitVRegs;
+ const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
+ 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);
+ }
}
/// 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<ArgInfo> &SplitArgs,
SmallVectorImpl<unsigned> &SplitArgsOrigIndices) const;
};
--- /dev/null
+; 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
+}
--- /dev/null
+; 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
+}