Subzero, MIPS32: Floating point comparison This patch implements lowerFcmp, for lowering floating point comparison. R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2047043002 . Patch from Srdjan Obucina <Srdjan.Obucina@imgtec.com>.
diff --git a/src/IceInstMIPS32.cpp b/src/IceInstMIPS32.cpp index a1de835..c25fbe1 100644 --- a/src/IceInstMIPS32.cpp +++ b/src/IceInstMIPS32.cpp
@@ -69,6 +69,20 @@ template <> const char *InstMIPS32Addu::Opcode = "addu"; template <> const char *InstMIPS32And::Opcode = "and"; template <> const char *InstMIPS32Andi::Opcode = "andi"; +template <> const char *InstMIPS32C_eq_d::Opcode = "c.eq.d"; +template <> const char *InstMIPS32C_eq_s::Opcode = "c.eq.s"; +template <> const char *InstMIPS32C_ole_d::Opcode = "c.ole.d"; +template <> const char *InstMIPS32C_ole_s::Opcode = "c.ole.s"; +template <> const char *InstMIPS32C_olt_d::Opcode = "c.olt.d"; +template <> const char *InstMIPS32C_olt_s::Opcode = "c.olt.s"; +template <> const char *InstMIPS32C_ueq_d::Opcode = "c.ueq.d"; +template <> const char *InstMIPS32C_ueq_s::Opcode = "c.ueq.s"; +template <> const char *InstMIPS32C_ule_d::Opcode = "c.ule.d"; +template <> const char *InstMIPS32C_ule_s::Opcode = "c.ule.s"; +template <> const char *InstMIPS32C_ult_d::Opcode = "c.ult.d"; +template <> const char *InstMIPS32C_ult_s::Opcode = "c.ult.s"; +template <> const char *InstMIPS32C_un_d::Opcode = "c.un.d"; +template <> const char *InstMIPS32C_un_s::Opcode = "c.un.s"; template <> const char *InstMIPS32Cvt_d_l::Opcode = "cvt.d.l"; template <> const char *InstMIPS32Cvt_d_s::Opcode = "cvt.d.s"; template <> const char *InstMIPS32Cvt_d_w::Opcode = "cvt.d.w"; @@ -89,6 +103,8 @@ template <> const char *InstMIPS32Mflo::Opcode = "mflo"; template <> const char *InstMIPS32Mov_d::Opcode = "mov.d"; template <> const char *InstMIPS32Mov_s::Opcode = "mov.s"; +template <> const char *InstMIPS32Movf::Opcode = "movf"; +template <> const char *InstMIPS32Movt::Opcode = "movt"; template <> const char *InstMIPS32Mtc1::Opcode = "mtc1"; template <> const char *InstMIPS32Mthi::Opcode = "mthi"; template <> const char *InstMIPS32Mtlo::Opcode = "mtlo";
diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h index 29f4aaf..2254c33 100644 --- a/src/IceInstMIPS32.h +++ b/src/IceInstMIPS32.h
@@ -55,6 +55,7 @@ public: enum OperandKindMIPS32 { k__Start = Operand::kTarget, + kFCC, kMem, }; @@ -69,6 +70,40 @@ : Operand(static_cast<OperandKind>(Kind), Ty) {} }; +class OperandMIPS32FCC : public OperandMIPS32 { + OperandMIPS32FCC() = delete; + OperandMIPS32FCC(const OperandMIPS32FCC &) = delete; + OperandMIPS32FCC &operator=(const OperandMIPS32FCC &) = delete; + +public: + enum FCC { FCC0 = 0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 }; + static OperandMIPS32FCC *create(Cfg *Func, OperandMIPS32FCC::FCC FCC) { + return new (Func->allocate<OperandMIPS32FCC>()) OperandMIPS32FCC(FCC); + } + + void emit(const Cfg *Func) const override { + if (!BuildDefs::dump()) + return; + Ostream &Str = Func->getContext()->getStrEmit(); + Str << "$fcc" << static_cast<uint16_t>(FCC); + } + + static bool classof(const Operand *Operand) { + return Operand->getKind() == static_cast<OperandKind>(kFCC); + } + + void dump(const Cfg *Func, Ostream &Str) const override { + (void)Func; + (void)Str; + } + +private: + OperandMIPS32FCC(OperandMIPS32FCC::FCC FCC) + : OperandMIPS32(kFCC, IceType_i32), FCC(FCC){}; + + const OperandMIPS32FCC::FCC FCC; +}; + class OperandMIPS32Mem : public OperandMIPS32 { OperandMIPS32Mem() = delete; OperandMIPS32Mem(const OperandMIPS32Mem &) = delete; @@ -155,6 +190,20 @@ And, Andi, Br, + C_eq_d, + C_eq_s, + C_ole_d, + C_ole_s, + C_olt_d, + C_olt_s, + C_ueq_d, + C_ueq_s, + C_ule_d, + C_ule_s, + C_ult_d, + C_ult_s, + C_un_d, + C_un_s, Call, Cvt_d_l, Cvt_d_s, @@ -178,6 +227,8 @@ Mov, // actually a pseudo op for addi rd, rs, 0 Mov_d, Mov_s, + Movf, + Movt, Mtc1, Mthi, Mtlo, @@ -806,6 +857,56 @@ InstMIPS32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); }; +template <InstMIPS32::InstKindMIPS32 K> +class InstMIPS32FPCmp : public InstMIPS32 { + InstMIPS32FPCmp() = delete; + InstMIPS32FPCmp(const InstMIPS32FPCmp &) = delete; + InstMIPS32Call &operator=(const InstMIPS32FPCmp &) = delete; + +public: + static InstMIPS32FPCmp *create(Cfg *Func, Variable *Src0, Variable *Src1) { + return new (Func->allocate<InstMIPS32FPCmp>()) + InstMIPS32FPCmp(Func, Src0, Src1); + } + + void emit(const Cfg *Func) const override { + if (!BuildDefs::dump()) + return; + Ostream &Str = Func->getContext()->getStrEmit(); + assert(getSrcSize() == 2); + Str << "\t" << Opcode << "\t"; + getSrc(0)->emit(Func); + Str << ", "; + getSrc(1)->emit(Func); + } + + void emitIAS(const Cfg *Func) const override { + (void)Func; + llvm_unreachable("Not yet implemented"); + } + + void dump(const Cfg *Func) const override { + (void)Func; + if (!BuildDefs::dump()) + return; + Ostream &Str = Func->getContext()->getStrDump(); + dumpOpcode(Str, Opcode, getSrc(0)->getType()); + Str << " "; + dumpSources(Func); + } + + static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } + +private: + InstMIPS32FPCmp(Cfg *Func, Variable *Src0, Variable *Src1) + : InstMIPS32(Func, K, 2, nullptr) { + addSource(Src0); + addSource(Src1); + }; + + static const char *Opcode; +}; + template <InstMIPS32::InstKindMIPS32 K, bool Signed = false> class InstMIPS32Imm16 : public InstMIPS32 { InstMIPS32Imm16() = delete; @@ -877,6 +978,62 @@ const uint32_t Imm; }; +/// Conditional mov +template <InstMIPS32::InstKindMIPS32 K> +class InstMIPS32MovConditional : public InstMIPS32 { + InstMIPS32MovConditional() = delete; + InstMIPS32MovConditional(const InstMIPS32MovConditional &) = delete; + InstMIPS32MovConditional & + operator=(const InstMIPS32MovConditional &) = delete; + +public: + static InstMIPS32MovConditional *create(Cfg *Func, Variable *Dest, + Variable *Src, Operand *FCC) { + return new (Func->allocate<InstMIPS32MovConditional>()) + InstMIPS32MovConditional(Func, Dest, Src, FCC); + } + + void emit(const Cfg *Func) const override { + if (!BuildDefs::dump()) + return; + Ostream &Str = Func->getContext()->getStrEmit(); + assert(getSrcSize() == 2); + Str << "\t" << Opcode << "\t"; + getDest()->emit(Func); + Str << ", "; + getSrc(0)->emit(Func); + Str << ", "; + getSrc(1)->emit(Func); + } + + void emitIAS(const Cfg *Func) const override { + (void)Func; + llvm_unreachable("Not yet implemented"); + } + + void dump(const Cfg *Func) const override { + if (!BuildDefs::dump()) + return; + Ostream &Str = Func->getContext()->getStrDump(); + dumpDest(Func); + Str << " = "; + dumpOpcode(Str, Opcode, getDest()->getType()); + Str << " "; + dumpSources(Func); + } + static bool classof(const Inst *Inst) { return isClassof(Inst, K); } + +private: + InstMIPS32MovConditional(Cfg *Func, Variable *Dest, Variable *Src, + Operand *FCC) + : InstMIPS32(Func, K, 2, Dest) { + addSource(Src); + addSource(FCC); + } + + static const char *Opcode; +}; + using InstMIPS32Abs_d = InstMIPS32TwoAddrFPR<InstMIPS32::Abs_d>; using InstMIPS32Abs_s = InstMIPS32TwoAddrFPR<InstMIPS32::Abs_s>; using InstMIPS32Add = InstMIPS32ThreeAddrGPR<InstMIPS32::Add>; @@ -886,6 +1043,20 @@ using InstMIPS32Addiu = InstMIPS32Imm16<InstMIPS32::Addiu, true>; using InstMIPS32And = InstMIPS32ThreeAddrGPR<InstMIPS32::And>; using InstMIPS32Andi = InstMIPS32Imm16<InstMIPS32::Andi>; +using InstMIPS32C_eq_d = InstMIPS32FPCmp<InstMIPS32::C_eq_d>; +using InstMIPS32C_eq_s = InstMIPS32FPCmp<InstMIPS32::C_eq_s>; +using InstMIPS32C_ole_d = InstMIPS32FPCmp<InstMIPS32::C_ole_d>; +using InstMIPS32C_ole_s = InstMIPS32FPCmp<InstMIPS32::C_ole_s>; +using InstMIPS32C_olt_d = InstMIPS32FPCmp<InstMIPS32::C_olt_d>; +using InstMIPS32C_olt_s = InstMIPS32FPCmp<InstMIPS32::C_olt_s>; +using InstMIPS32C_ueq_d = InstMIPS32FPCmp<InstMIPS32::C_ueq_d>; +using InstMIPS32C_ueq_s = InstMIPS32FPCmp<InstMIPS32::C_ueq_s>; +using InstMIPS32C_ule_d = InstMIPS32FPCmp<InstMIPS32::C_ule_d>; +using InstMIPS32C_ule_s = InstMIPS32FPCmp<InstMIPS32::C_ule_s>; +using InstMIPS32C_ult_d = InstMIPS32FPCmp<InstMIPS32::C_ult_d>; +using InstMIPS32C_ult_s = InstMIPS32FPCmp<InstMIPS32::C_ult_s>; +using InstMIPS32C_un_d = InstMIPS32FPCmp<InstMIPS32::C_un_d>; +using InstMIPS32C_un_s = InstMIPS32FPCmp<InstMIPS32::C_un_s>; using InstMIPS32Cvt_d_s = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_s>; using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_l>; using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_w>; @@ -906,6 +1077,8 @@ using InstMIPS32Mflo = InstMIPS32UnaryopGPR<InstMIPS32::Mflo>; using InstMIPS32Mov_d = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_d>; using InstMIPS32Mov_s = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_s>; +using InstMIPS32Movf = InstMIPS32MovConditional<InstMIPS32::Movf>; +using InstMIPS32Movt = InstMIPS32MovConditional<InstMIPS32::Movt>; using InstMIPS32Mtc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mtc1>; using InstMIPS32Mthi = InstMIPS32UnaryopGPR<InstMIPS32::Mthi>; using InstMIPS32Mtlo = InstMIPS32UnaryopGPR<InstMIPS32::Mtlo>;
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp index 622af79..6f602c9 100644 --- a/src/IceTargetLoweringMIPS32.cpp +++ b/src/IceTargetLoweringMIPS32.cpp
@@ -2436,7 +2436,184 @@ } void TargetMIPS32::lowerFcmp(const InstFcmp *Instr) { - UnimplementedLoweringError(this, Instr); + Variable *Dest = Instr->getDest(); + if (isVectorType(Dest->getType())) { + UnimplementedLoweringError(this, Instr); + return; + } + + auto *Src0 = Instr->getSrc(0); + auto *Src1 = Instr->getSrc(1); + auto *Zero = getZero(); + + InstFcmp::FCond Cond = Instr->getCondition(); + auto *DestR = legalizeToReg(Dest); + auto *Src0R = legalizeToReg(Src0); + auto *Src1R = legalizeToReg(Src1); + const Type Src0Ty = Src0->getType(); + + Operand *FCC0 = OperandMIPS32FCC::create(getFunc(), OperandMIPS32FCC::FCC0); + + switch (Cond) { + default: { + UnimplementedLoweringError(this, Instr); + return; + } + case InstFcmp::False: { + Context.insert<InstFakeUse>(Src0R); + Context.insert<InstFakeUse>(Src1R); + _addiu(DestR, Zero, 0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Oeq: { + if (Src0Ty == IceType_f32) { + _c_eq_s(Src0R, Src1R); + } else { + _c_eq_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ogt: { + if (Src0Ty == IceType_f32) { + _c_ule_s(Src0R, Src1R); + } else { + _c_ule_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Oge: { + if (Src0Ty == IceType_f32) { + _c_ult_s(Src0R, Src1R); + } else { + _c_ult_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Olt: { + if (Src0Ty == IceType_f32) { + _c_olt_s(Src0R, Src1R); + } else { + _c_olt_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ole: { + if (Src0Ty == IceType_f32) { + _c_ole_s(Src0R, Src1R); + } else { + _c_ole_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::One: { + if (Src0Ty == IceType_f32) { + _c_ueq_s(Src0R, Src1R); + } else { + _c_ueq_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ord: { + if (Src0Ty == IceType_f32) { + _c_un_s(Src0R, Src1R); + } else { + _c_un_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ueq: { + if (Src0Ty == IceType_f32) { + _c_ueq_s(Src0R, Src1R); + } else { + _c_ueq_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ugt: { + if (Src0Ty == IceType_f32) { + _c_ole_s(Src0R, Src1R); + } else { + _c_ole_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Uge: { + if (Src0Ty == IceType_f32) { + _c_olt_s(Src0R, Src1R); + } else { + _c_olt_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ult: { + if (Src0Ty == IceType_f32) { + _c_ult_s(Src0R, Src1R); + } else { + _c_ult_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Ule: { + if (Src0Ty == IceType_f32) { + _c_ule_s(Src0R, Src1R); + } else { + _c_ule_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Une: { + if (Src0Ty == IceType_f32) { + _c_eq_s(Src0R, Src1R); + } else { + _c_eq_d(Src0R, Src1R); + } + _movt(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::Uno: { + if (Src0Ty == IceType_f32) { + _c_un_s(Src0R, Src1R); + } else { + _c_un_d(Src0R, Src1R); + } + _movf(DestR, Zero, FCC0); + _mov(Dest, DestR); + break; + } + case InstFcmp::True: { + Context.insert<InstFakeUse>(Src0R); + Context.insert<InstFakeUse>(Src1R); + _addiu(DestR, Zero, 1); + _mov(Dest, DestR); + break; + } + } } void TargetMIPS32::lower64Icmp(const InstIcmp *Instr) {
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h index 3a83b3d..5b722f6 100644 --- a/src/IceTargetLoweringMIPS32.h +++ b/src/IceTargetLoweringMIPS32.h
@@ -207,6 +207,62 @@ Context.insert<InstMIPS32Addiu>(Dest, Src, Imm); } + void _c_eq_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_eq_d>(Src0, Src1); + } + + void _c_eq_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_eq_s>(Src0, Src1); + } + + void _c_ole_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ole_d>(Src0, Src1); + } + + void _c_ole_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ole_s>(Src0, Src1); + } + + void _c_olt_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_olt_d>(Src0, Src1); + } + + void _c_olt_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_olt_s>(Src0, Src1); + } + + void _c_ueq_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ueq_d>(Src0, Src1); + } + + void _c_ueq_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ueq_s>(Src0, Src1); + } + + void _c_ule_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ule_d>(Src0, Src1); + } + + void _c_ule_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ule_s>(Src0, Src1); + } + + void _c_ult_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ult_d>(Src0, Src1); + } + + void _c_ult_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_ult_s>(Src0, Src1); + } + + void _c_un_d(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_un_d>(Src0, Src1); + } + + void _c_un_s(Variable *Src0, Variable *Src1) { + Context.insert<InstMIPS32C_un_s>(Src0, Src1); + } + void _cvt_d_l(Variable *Dest, Variable *Src) { Context.insert<InstMIPS32Cvt_d_l>(Dest, Src); } @@ -287,6 +343,14 @@ Context.insert<InstMIPS32Mov_s>(Dest, Src); } + void _movf(Variable *Src0, Variable *Src1, Operand *FCC) { + Context.insert<InstMIPS32Movf>(Src0, Src1, FCC); + } + + void _movt(Variable *Src0, Variable *Src1, Operand *FCC) { + Context.insert<InstMIPS32Movt>(Src0, Src1, FCC); + } + void _mfc1(Variable *Dest, Variable *Src) { Context.insert<InstMIPS32Mfc1>(Dest, Src); } @@ -483,6 +547,14 @@ return makeReg(IceType_i32, RegNum); } + Variable *F32Reg(RegNumT RegNum = RegNumT()) { + return makeReg(IceType_f32, RegNum); + } + + Variable *F64Reg(RegNumT RegNum = RegNumT()) { + return makeReg(IceType_f64, RegNum); + } + static Type stackSlotType(); Variable *copyToReg(Operand *Src, RegNumT RegNum = RegNumT());