Commit d3297662 by Jaydeep Patil Committed by Jim Stichnoth

[SubZero] Implement GP to/from FP moves for MIPS

The patch implements mtc1/mfc1 instructions which are required for GP to/from FP registers moves. The patch also implements fptosi and sitofp for float and i32 types to test mtc1/mfc1 instructions. R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2316933002 . Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
parent 038a9b9e
...@@ -733,6 +733,22 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const { ...@@ -733,6 +733,22 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
// reg to reg // reg to reg
if (DestIsReg && SrcIsReg) { if (DestIsReg && SrcIsReg) {
const Type DstType = Dest->getType();
const Type SrcType = Src->getType();
// move GP to/from FP
if (DstType != SrcType) {
if (isScalarFloatingType(DstType)) {
Str << "\t"
"mtc1"
"\t";
getSrc(0)->emit(Func);
Str << ", ";
getDest()->emit(Func);
return;
}
ActualOpcode = "mfc1";
} else {
switch (Dest->getType()) { switch (Dest->getType()) {
case IceType_f32: case IceType_f32:
ActualOpcode = "mov.s"; ActualOpcode = "mov.s";
...@@ -744,17 +760,13 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const { ...@@ -744,17 +760,13 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
case IceType_i8: case IceType_i8:
case IceType_i16: case IceType_i16:
case IceType_i32: case IceType_i32:
Str << "\t" ActualOpcode = "move";
<< "move" break;
<< "\t";
getDest()->emit(Func);
Str << ", ";
getSrc(0)->emit(Func);
return;
default: default:
UnimplementedError(getFlags()); UnimplementedError(getFlags());
return; return;
} }
}
assert(ActualOpcode); assert(ActualOpcode);
Str << "\t" << ActualOpcode << "\t"; Str << "\t" << ActualOpcode << "\t";
......
...@@ -72,8 +72,11 @@ static inline GPRRegister getEncodedGPR(RegNumT RegNum) { ...@@ -72,8 +72,11 @@ static inline GPRRegister getEncodedGPR(RegNumT RegNum) {
} }
static inline bool isGPRReg(RegNumT RegNum) { static inline bool isGPRReg(RegNumT RegNum) {
return (int(Reg_GPR_First) <= int(RegNum)) && bool IsGPR = ((int(Reg_GPR_First) <= int(RegNum)) &&
(unsigned(RegNum) <= Reg_GPR_Last); (unsigned(RegNum) <= Reg_GPR_Last)) ||
((int(Reg_I64PAIR_First) <= int(RegNum)) &&
(unsigned(RegNum) <= Reg_I64PAIR_Last));
return IsGPR;
} }
static inline FPRRegister getEncodedFPR(RegNumT RegNum) { static inline FPRRegister getEncodedFPR(RegNumT RegNum) {
......
...@@ -1452,6 +1452,69 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) { ...@@ -1452,6 +1452,69 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
return; return;
bool Legalized = false; bool Legalized = false;
auto *SrcR = llvm::cast<Variable>(Src);
if (Dest->hasReg() && SrcR->hasReg()) {
// This might be a GP to/from FP move generated due to argument passing.
// Use mtc1/mfc1 instead of mov.[s/d] if src and dst registers are of
// different types.
const bool IsDstGPR = RegMIPS32::isGPRReg(Dest->getRegNum());
const bool IsSrcGPR = RegMIPS32::isGPRReg(SrcR->getRegNum());
const RegNumT SRegNum = SrcR->getRegNum();
const RegNumT DRegNum = Dest->getRegNum();
if (IsDstGPR != IsSrcGPR) {
if (IsDstGPR) {
// Dest is GPR and SrcR is FPR. Use mfc1.
if (typeWidthInBytes(Dest->getType()) == 8) {
// Split it into two mfc1 instructions
Variable *SrcGPRHi = Target->makeReg(
IceType_f32, RegMIPS32::get64PairFirstRegNum(SRegNum));
Variable *SrcGPRLo = Target->makeReg(
IceType_f32, RegMIPS32::get64PairSecondRegNum(SRegNum));
Variable *DstFPRHi = Target->makeReg(
IceType_i32, RegMIPS32::get64PairFirstRegNum(DRegNum));
Variable *DstFPRLo = Target->makeReg(
IceType_i32, RegMIPS32::get64PairSecondRegNum(DRegNum));
Target->_mov(DstFPRHi, SrcGPRLo);
Target->_mov(DstFPRLo, SrcGPRHi);
Legalized = true;
} else {
Variable *SrcGPR = Target->makeReg(IceType_f32, SRegNum);
Variable *DstFPR = Target->makeReg(IceType_i32, DRegNum);
Target->_mov(DstFPR, SrcGPR);
Legalized = true;
}
} else {
// Dest is FPR and SrcR is GPR. Use mtc1.
if (typeWidthInBytes(SrcR->getType()) == 8) {
// Split it into two mtc1 instructions
Variable *SrcGPRHi = Target->makeReg(
IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum));
Variable *SrcGPRLo = Target->makeReg(
IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum));
Variable *DstFPRHi = Target->makeReg(
IceType_f32, RegMIPS32::get64PairFirstRegNum(DRegNum));
Variable *DstFPRLo = Target->makeReg(
IceType_f32, RegMIPS32::get64PairSecondRegNum(DRegNum));
Target->_mov(DstFPRHi, SrcGPRLo);
Target->_mov(DstFPRLo, SrcGPRHi);
Legalized = true;
} else {
Variable *SrcGPR = Target->makeReg(IceType_i32, SRegNum);
Variable *DstFPR = Target->makeReg(IceType_f32, DRegNum);
Target->_mov(DstFPR, SrcGPR);
Legalized = true;
}
}
}
if (Legalized) {
if (MovInstr->isDestRedefined()) {
Target->_set_dest_redefined();
}
MovInstr->setDeleted();
return;
}
}
if (!Dest->hasReg()) { if (!Dest->hasReg()) {
auto *SrcR = llvm::cast<Variable>(Src); auto *SrcR = llvm::cast<Variable>(Src);
assert(SrcR->hasReg()); assert(SrcR->hasReg());
...@@ -1469,22 +1532,15 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) { ...@@ -1469,22 +1532,15 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
// case type of the SrcR is still FP thus we need to explicitly generate sw // case type of the SrcR is still FP thus we need to explicitly generate sw
// instead of swc1. // instead of swc1.
const RegNumT RegNum = SrcR->getRegNum(); const RegNumT RegNum = SrcR->getRegNum();
const bool isSrcGPReg = ((unsigned)RegNum >= RegMIPS32::Reg_A0 && const bool IsSrcGPReg = RegMIPS32::isGPRReg(SrcR->getRegNum());
(unsigned)RegNum <= RegMIPS32::Reg_A3) || if (SrcTy == IceType_f32 && IsSrcGPReg == true) {
((unsigned)RegNum >= RegMIPS32::Reg_A0A1 &&
(unsigned)RegNum <= RegMIPS32::Reg_A2A3);
if (SrcTy == IceType_f32 && isSrcGPReg == true) {
Variable *SrcGPR = Target->makeReg(IceType_i32, RegNum); Variable *SrcGPR = Target->makeReg(IceType_i32, RegNum);
Target->_sw(SrcGPR, Addr); Target->_sw(SrcGPR, Addr);
} else if (SrcTy == IceType_f64 && isSrcGPReg == true) { } else if (SrcTy == IceType_f64 && IsSrcGPReg == true) {
Variable *SrcGPRHi, *SrcGPRLo; Variable *SrcGPRHi =
if (RegNum == RegMIPS32::Reg_A0A1) { Target->makeReg(IceType_i32, RegMIPS32::get64PairFirstRegNum(RegNum));
SrcGPRLo = Target->makeReg(IceType_i32, RegMIPS32::Reg_A0); Variable *SrcGPRLo = Target->makeReg(
SrcGPRHi = Target->makeReg(IceType_i32, RegMIPS32::Reg_A1); IceType_i32, RegMIPS32::get64PairSecondRegNum(RegNum));
} else {
SrcGPRLo = Target->makeReg(IceType_i32, RegMIPS32::Reg_A2);
SrcGPRHi = Target->makeReg(IceType_i32, RegMIPS32::Reg_A3);
}
OperandMIPS32Mem *AddrHi = OperandMIPS32Mem::create( OperandMIPS32Mem *AddrHi = OperandMIPS32Mem::create(
Target->Func, DestTy, Base, Target->Func, DestTy, Base,
llvm::cast<ConstantInteger32>( llvm::cast<ConstantInteger32>(
...@@ -2411,15 +2467,33 @@ void TargetMIPS32::lowerCast(const InstCast *Instr) { ...@@ -2411,15 +2467,33 @@ void TargetMIPS32::lowerCast(const InstCast *Instr) {
_mov(Dest, DestR); _mov(Dest, DestR);
break; break;
} }
case InstCast::Fptosi: // case InstCast::Fptosi: {
if (Src0Ty == IceType_f32 && DestTy == IceType_i32) {
Variable *Src0R = legalizeToReg(Src0);
Variable *FTmp = makeReg(IceType_f32);
_trunc_w_s(FTmp, Src0R);
_mov(Dest, FTmp);
} else {
UnimplementedLoweringError(this, Instr); UnimplementedLoweringError(this, Instr);
}
break; break;
}
case InstCast::Fptoui: case InstCast::Fptoui:
UnimplementedLoweringError(this, Instr); UnimplementedLoweringError(this, Instr);
break; break;
case InstCast::Sitofp: // case InstCast::Sitofp: {
if (Src0Ty == IceType_i32 && DestTy == IceType_f32) {
Variable *Src0R = legalizeToReg(Src0);
Variable *FTmp1 = makeReg(IceType_f32);
Variable *FTmp2 = makeReg(IceType_f32);
_mov(FTmp1, Src0R);
_cvt_s_w(FTmp2, FTmp1);
_mov(Dest, FTmp2);
} else {
UnimplementedLoweringError(this, Instr); UnimplementedLoweringError(this, Instr);
}
break; break;
}
case InstCast::Uitofp: { case InstCast::Uitofp: {
UnimplementedLoweringError(this, Instr); UnimplementedLoweringError(this, Instr);
break; break;
......
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
; RUN: | %if --need=allow_dump --need=target_MIPS32 --command FileCheck %s \ ; RUN: | %if --need=allow_dump --need=target_MIPS32 --command FileCheck %s \
; RUN: --check-prefix=MIPS32 ; RUN: --check-prefix=MIPS32
; RUN: %if --need=allow_dump --need=target_MIPS32 --command %p2i \
; RUN: --filetype=asm --target mips32 -i %s --args -O2 --skip-unimplemented \
; RUN: | %if --need=allow_dump --need=target_MIPS32 --command FileCheck %s \
; RUN: --check-prefix=MIPS32O2
define internal float @fptrunc(double %a) { define internal float @fptrunc(double %a) {
entry: entry:
%conv = fptrunc double %a to float %conv = fptrunc double %a to float
...@@ -33,6 +38,8 @@ entry: ...@@ -33,6 +38,8 @@ entry:
; ARM32: vcvt.f32.f64 {{s[0-9]+}}, {{d[0-9]+}} ; ARM32: vcvt.f32.f64 {{s[0-9]+}}, {{d[0-9]+}}
; MIPS32-LABEL: fptrunc ; MIPS32-LABEL: fptrunc
; MIPS32: cvt.s.d ; MIPS32: cvt.s.d
; MIPS32O2-LABEL: fptrunc
; MIPS32O2: cvt.s.d
define internal double @fpext(float %a) { define internal double @fpext(float %a) {
entry: entry:
...@@ -46,6 +53,8 @@ entry: ...@@ -46,6 +53,8 @@ entry:
; ARM32: vcvt.f64.f32 {{d[0-9]+}}, {{s[0-9]+}} ; ARM32: vcvt.f64.f32 {{d[0-9]+}}, {{s[0-9]+}}
; MIPS32-LABEL: fpext ; MIPS32-LABEL: fpext
; MIPS32: cvt.d.s ; MIPS32: cvt.d.s
; MIPS32O2-LABEL: fpext
; MIPS32O2: cvt.d.s
define internal i64 @doubleToSigned64(double %a) { define internal i64 @doubleToSigned64(double %a) {
entry: entry:
...@@ -56,6 +65,10 @@ entry: ...@@ -56,6 +65,10 @@ entry:
; CHECK: call {{.*}} R_{{.*}} __Sz_fptosi_f64_i64 ; CHECK: call {{.*}} R_{{.*}} __Sz_fptosi_f64_i64
; ARM32-LABEL: doubleToSigned64 ; ARM32-LABEL: doubleToSigned64
; TODO(jpp): implement this test. ; TODO(jpp): implement this test.
; MIPS32-LABEL: doubleToSigned64
; MIPS32: jal __Sz_fptosi_f64_i64
; MIPS32O2-LABEL: doubleToSigned64
; MIPS32O2: jal __Sz_fptosi_f64_i64
define internal i64 @floatToSigned64(float %a) { define internal i64 @floatToSigned64(float %a) {
entry: entry:
...@@ -66,6 +79,10 @@ entry: ...@@ -66,6 +79,10 @@ entry:
; CHECK: call {{.*}} R_{{.*}} __Sz_fptosi_f32_i64 ; CHECK: call {{.*}} R_{{.*}} __Sz_fptosi_f32_i64
; ARM32-LABEL: floatToSigned64 ; ARM32-LABEL: floatToSigned64
; TODO(jpp): implement this test. ; TODO(jpp): implement this test.
; MIPS32-LABEL: floatToSigned64
; MIPS32: jal __Sz_fptosi_f32_i64
; MIPS32O2-LABEL: floatToSigned64
; MIPS32O2: jal __Sz_fptosi_f32_i64
define internal i64 @doubleToUnsigned64(double %a) { define internal i64 @doubleToUnsigned64(double %a) {
entry: entry:
...@@ -76,6 +93,10 @@ entry: ...@@ -76,6 +93,10 @@ entry:
; CHECK: call {{.*}} R_{{.*}} __Sz_fptoui_f64_i64 ; CHECK: call {{.*}} R_{{.*}} __Sz_fptoui_f64_i64
; ARM32-LABEL: doubleToUnsigned64 ; ARM32-LABEL: doubleToUnsigned64
; TODO(jpp): implement this test. ; TODO(jpp): implement this test.
; MIPS32-LABEL: doubleToUnsigned64
; MIPS32: jal __Sz_fptoui_f64_i64
; MIPS32O2-LABEL: doubleToUnsigned64
; MIPS32O2: jal __Sz_fptoui_f64_i64
define internal i64 @floatToUnsigned64(float %a) { define internal i64 @floatToUnsigned64(float %a) {
entry: entry:
...@@ -86,6 +107,10 @@ entry: ...@@ -86,6 +107,10 @@ entry:
; CHECK: call {{.*}} R_{{.*}} __Sz_fptoui_f32_i64 ; CHECK: call {{.*}} R_{{.*}} __Sz_fptoui_f32_i64
; ARM32-LABEL: floatToUnsigned64 ; ARM32-LABEL: floatToUnsigned64
; TODO(jpp): implement this test. ; TODO(jpp): implement this test.
; MIPS32-LABEL: floatToUnsigned64
; MIPS32: jal __Sz_fptoui_f32_i64
; MIPS32O2-LABEL: floatToUnsigned64
; MIPS32O2: jal __Sz_fptoui_f32_i64
define internal i32 @doubleToSigned32(double %a) { define internal i32 @doubleToSigned32(double %a) {
entry: entry:
...@@ -122,6 +147,11 @@ entry: ...@@ -122,6 +147,11 @@ entry:
; ARM32-LABEL: floatToSigned32 ; ARM32-LABEL: floatToSigned32
; ARM32-DAG: vcvt.s32.f32 [[REG:s[0-9]+]], {{s[0-9]+}} ; ARM32-DAG: vcvt.s32.f32 [[REG:s[0-9]+]], {{s[0-9]+}}
; ARM32-DAG: vmov {{r[0-9]+}}, [[REG]] ; ARM32-DAG: vmov {{r[0-9]+}}, [[REG]]
; MIPS32-LABEL: floatToSigned32
; MIPS32: trunc.w.s $f{{.*}}, $f{{.*}}
; MIPS32O2-LABEL: floatToSigned32
; MIPS32O2: trunc.w.s $[[REG:f[0-9]+]], $f{{.*}}
; MIPS32O2: mfc1 $v0, $[[REG]]
define internal i32 @doubleToUnsigned32(double %a) { define internal i32 @doubleToUnsigned32(double %a) {
entry: entry:
...@@ -382,6 +412,11 @@ entry: ...@@ -382,6 +412,11 @@ entry:
; ARM32-LABEL: signed32ToFloat ; ARM32-LABEL: signed32ToFloat
; ARM32-DAG: vmov [[SRC:s[0-9]+]], {{r[0-9]+}} ; ARM32-DAG: vmov [[SRC:s[0-9]+]], {{r[0-9]+}}
; ARM32-DAG: vcvt.f32.s32 {{s[0-9]+}}, [[SRC]] ; ARM32-DAG: vcvt.f32.s32 {{s[0-9]+}}, [[SRC]]
; MIPS32-LABEL: signed32ToFloat
; MIPS32: cvt.s.w $f{{.*}}, $f{{.*}}
; MIPS32O2-LABEL: signed32ToFloat
; MIPS32O2: mtc1 $a0, $[[REG:f[0-9]+]]
; MIPS32O2: cvt.s.w $f{{.*}}, $[[REG]]
define internal double @unsigned32ToDouble(i32 %a) { define internal double @unsigned32ToDouble(i32 %a) {
entry: entry:
......
...@@ -13,6 +13,13 @@ ...@@ -13,6 +13,13 @@
; RUN: | %if --need=target_MIPS32 --need=allow_dump \ ; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s ; RUN: --command FileCheck --check-prefix MIPS32 %s
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target mips32 -i %s --args -O2 --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32O2 %s
define internal float @loadFloat(i32 %a) { define internal float @loadFloat(i32 %a) {
entry: entry:
%__1 = inttoptr i32 %a to float* %__1 = inttoptr i32 %a to float*
...@@ -25,6 +32,8 @@ entry: ...@@ -25,6 +32,8 @@ entry:
; MIPS32-LABEL: loadFloat ; MIPS32-LABEL: loadFloat
; MIPS32: lwc1 $f{{.*}},0{{.*}} ; MIPS32: lwc1 $f{{.*}},0{{.*}}
; MIPS32O2-LABEL: loadFloat
; MIPS32O2: lwc1 $f{{.*}},0{{.*}}
define internal double @loadDouble(i32 %a) { define internal double @loadDouble(i32 %a) {
entry: entry:
...@@ -38,6 +47,8 @@ entry: ...@@ -38,6 +47,8 @@ entry:
; MIPS32-LABEL: loadDouble ; MIPS32-LABEL: loadDouble
; MIPS32: ldc1 $f{{.*}},0{{.*}} ; MIPS32: ldc1 $f{{.*}},0{{.*}}
; MIPS32O2-LABEL: loadDouble
; MIPS32O2: ldc1 $f{{.*}},0{{.*}}
define internal void @storeFloat(i32 %a, float %value) { define internal void @storeFloat(i32 %a, float %value) {
entry: entry:
...@@ -51,6 +62,9 @@ entry: ...@@ -51,6 +62,9 @@ entry:
; MIPS32-LABEL: storeFloat ; MIPS32-LABEL: storeFloat
; MIPS32: swc1 $f{{.*}},0{{.*}} ; MIPS32: swc1 $f{{.*}},0{{.*}}
; MIPS32O2-LABEL: storeFloat
; MIPS32O2: mtc1 a1,$f{{.*}}
; MIPS32O2: swc1 $f{{.*}},0(a0)
define internal void @storeDouble(i32 %a, double %value) { define internal void @storeDouble(i32 %a, double %value) {
entry: entry:
...@@ -65,6 +79,10 @@ entry: ...@@ -65,6 +79,10 @@ entry:
; MIPS32-LABEL: storeDouble ; MIPS32-LABEL: storeDouble
; MIPS32: ldc1 $f{{.*}},4{{.*}} ; MIPS32: ldc1 $f{{.*}},4{{.*}}
; MIPS32: sdc1 $f{{.*}},0{{.*}} ; MIPS32: sdc1 $f{{.*}},0{{.*}}
; MIPS32O2-LABEL: storeDouble
; MIPS32O2: mtc1 a3,$f{{.*}}
; MIPS32O2: mtc1 a2,$f{{.*}}
; MIPS32O2: sdc1 $f{{.*}},0(a0)
define internal void @storeFloatConst(i32 %a) { define internal void @storeFloatConst(i32 %a) {
entry: entry:
...@@ -80,6 +98,10 @@ entry: ...@@ -80,6 +98,10 @@ entry:
; MIPS32: lui {{.*}},{{.*}} ; MIPS32: lui {{.*}},{{.*}}
; MIPS32: lwc1 $f{{.*}},{{.*}} ; MIPS32: lwc1 $f{{.*}},{{.*}}
; MIPS32: swc1 $f{{.*}},0{{.*}} ; MIPS32: swc1 $f{{.*}},0{{.*}}
; MIPS32O2-LABEL: storeFloatConst
; MIPS32O2: lui {{.*}},{{.*}}
; MIPS32O2: lwc1 $f{{.*}},{{.*}}
; MIPS32O2: swc1 $f{{.*}},0{{.*}}
define internal void @storeDoubleConst(i32 %a) { define internal void @storeDoubleConst(i32 %a) {
entry: entry:
...@@ -95,3 +117,7 @@ entry: ...@@ -95,3 +117,7 @@ entry:
; MIPS32: lui {{.*}},{{.*}} ; MIPS32: lui {{.*}},{{.*}}
; MIPS32: ldc1 $f{{.*}},{{.*}} ; MIPS32: ldc1 $f{{.*}},{{.*}}
; MIPS32: sdc1 $f{{.*}},0{{.*}} ; MIPS32: sdc1 $f{{.*}},0{{.*}}
; MIPS32O2-LABEL: storeDoubleConst
; MIPS32O2: lui {{.*}},{{.*}}
; MIPS32O2: ldc1 $f{{.*}},{{.*}}
; MIPS32O2: sdc1 $f{{.*}},0{{.*}}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment