diff --git a/lib/Backend/arm/LowerMD.cpp b/lib/Backend/arm/LowerMD.cpp index 5ce463376cb..caafe723e45 100644 --- a/lib/Backend/arm/LowerMD.cpp +++ b/lib/Backend/arm/LowerMD.cpp @@ -2874,9 +2874,161 @@ LowererMD::GenerateFastCmSrEqConst(IR::Instr *instr) return false; } -bool LowererMD::GenerateFastCmXxI4(IR::Instr *instr) +void LowererMD::GenerateFastCmXxI4(IR::Instr *instr) { - return this->GenerateFastCmXxTaggedInt(instr); + this->GenerateFastCmXx(instr); +} + +void LowererMD::GenerateFastCmXxR8(IR::Instr * instr) +{ + this->GenerateFastCmXx(instr); +} + +void LowererMD::GenerateFastCmXx(IR::Instr *instr) +{ + // For float src: + // LDIMM dst, trueResult + // FCMP src1, src2 + // - BVS $done (NaN check iff B.cond is BNE) + // B.cond $done + // LDIMM dst, falseResult + // $done + + // For Int src: + // LDIMM dst, trueResult + // CMP src1, src2 + // B.cond $done + // LDIMM dst, falseResult + // $done: + + IR::Opnd * src1 = instr->UnlinkSrc1(); + IR::Opnd * src2 = instr->UnlinkSrc2(); + IR::Opnd * dst = instr->UnlinkDst(); + bool isIntDst = dst->AsRegOpnd()->m_sym->IsInt32(); + bool isFloatSrc = src1->IsFloat(); + Assert(!isFloatSrc || src2->IsFloat()); + Assert(!src1->IsInt64() || src2->IsInt64()); + Assert(!isFloatSrc || AutoSystemInfo::Data.SSE2Available()); + Assert(src1->IsRegOpnd()); + IR::Opnd * opndTrue; + IR::Opnd * opndFalse; + IR::Instr * newInstr; + IR::LabelInstr * done = IR::LabelInstr::New(Js::OpCode::Label, m_func); + + if (dst->IsEqual(src1)) + { + IR::RegOpnd *newSrc1 = IR::RegOpnd::New(src1->GetType(), m_func); + Lowerer::InsertMove(newSrc1, src1, instr); + src1 = newSrc1; + } + + if (dst->IsEqual(src2)) + { + IR::RegOpnd *newSrc2 = IR::RegOpnd::New(src1->GetType(), m_func); + Lowerer::InsertMove(newSrc2, src2, instr); + src2 = newSrc2; + } + + if (isIntDst) + { + opndTrue = IR::IntConstOpnd::New(1, TyInt32, this->m_func); + opndFalse = IR::IntConstOpnd::New(0, TyInt32, this->m_func); + } + else + { + opndTrue = this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue); + opndFalse = this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse); + } + + Lowerer::InsertMove(dst, opndTrue, instr); + + // CMP src1, src2 + newInstr = IR::Instr::New(isFloatSrc ? Js::OpCode::VCMPF64 : Js::OpCode::CMP, this->m_func); + newInstr->SetSrc1(src1); + newInstr->SetSrc2(src2); + instr->InsertBefore(newInstr); + LowererMD::Legalize(newInstr); + + if (isFloatSrc) + { + instr->InsertBefore(IR::Instr::New(Js::OpCode::VMRS, this->m_func)); + } + + bool addNaNCheck = false; + Js::OpCode opcode = Js::OpCode::InvalidOpCode; + + switch (instr->m_opcode) + { + case Js::OpCode::CmEq_A: + case Js::OpCode::CmSrEq_A: + case Js::OpCode::CmEq_I4: + opcode = Js::OpCode::BEQ; + break; + + case Js::OpCode::CmNeq_A: + case Js::OpCode::CmSrNeq_A: + case Js::OpCode::CmNeq_I4: + opcode = Js::OpCode::BNE; + addNaNCheck = isFloatSrc; + break; + + case Js::OpCode::CmGt_A: + case Js::OpCode::CmGt_I4: + opcode = Js::OpCode::BGT; + break; + + case Js::OpCode::CmGe_A: + case Js::OpCode::CmGe_I4: + opcode = Js::OpCode::BGE; + break; + + case Js::OpCode::CmLt_A: + case Js::OpCode::CmLt_I4: + //Can't use BLT as is set when the operands are unordered (NaN). + opcode = isFloatSrc ? Js::OpCode::BCC : Js::OpCode::BLT; + break; + + case Js::OpCode::CmLe_A: + case Js::OpCode::CmLe_I4: + //Can't use BLE as it is set when the operands are unordered (NaN). + opcode = isFloatSrc ? Js::OpCode::BLS : Js::OpCode::BLE; + break; + + case Js::OpCode::CmUnGt_A: + case Js::OpCode::CmUnGt_I4: + opcode = Js::OpCode::BHI; + break; + + case Js::OpCode::CmUnGe_A: + case Js::OpCode::CmUnGe_I4: + opcode = Js::OpCode::BCS; + break; + + case Js::OpCode::CmUnLt_A: + case Js::OpCode::CmUnLt_I4: + opcode = Js::OpCode::BCC; + break; + + case Js::OpCode::CmUnLe_A: + case Js::OpCode::CmUnLe_I4: + opcode = Js::OpCode::BLS; + break; + + default: Assert(false); + } + + if (addNaNCheck) + { + newInstr = IR::BranchInstr::New(Js::OpCode::BVS, done, m_func); + instr->InsertBefore(newInstr); + } + + newInstr = IR::BranchInstr::New(opcode, done, m_func); + instr->InsertBefore(newInstr); + + Lowerer::InsertMove(dst, opndFalse, instr); + instr->InsertBefore(done); + instr->Remove(); } ///---------------------------------------------------------------------------- diff --git a/lib/Backend/arm/LowerMD.h b/lib/Backend/arm/LowerMD.h index 28ee28d0a2d..0eb5bdcfd3d 100644 --- a/lib/Backend/arm/LowerMD.h +++ b/lib/Backend/arm/LowerMD.h @@ -94,8 +94,9 @@ class LowererMD void GenerateObjectPairTest(IR::Opnd * opndSrc1, IR::Opnd * opndSrc2, IR::Instr * insertInstr, IR::LabelInstr * labelTarget); bool GenerateObjectTest(IR::Opnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr * labelTarget, bool fContinueLabel = false); bool GenerateFastCmSrEqConst(IR::Instr *instr); - bool GenerateFastCmXxI4(IR::Instr *instr); - bool GenerateFastCmXxR8(IR::Instr *instr) { Assert(UNREACHED); return nullptr; } + void GenerateFastCmXxI4(IR::Instr *instr); + void GenerateFastCmXxR8(IR::Instr *instr); + void GenerateFastCmXx(IR::Instr *instr); bool GenerateFastCmXxTaggedInt(IR::Instr *instr, bool isInHelper = false); IR::Instr * GenerateConvBool(IR::Instr *instr); void GenerateClz(IR::Instr * instr); diff --git a/lib/Backend/arm64/LowerMD.cpp b/lib/Backend/arm64/LowerMD.cpp index cebe685b721..07f4972b10a 100644 --- a/lib/Backend/arm64/LowerMD.cpp +++ b/lib/Backend/arm64/LowerMD.cpp @@ -2677,9 +2677,156 @@ LowererMD::GenerateFastCmSrEqConst(IR::Instr *instr) return false; } -bool LowererMD::GenerateFastCmXxI4(IR::Instr *instr) +void LowererMD::GenerateFastCmXxI4(IR::Instr *instr) { - return this->GenerateFastCmXxTaggedInt(instr); + this->GenerateFastCmXx(instr); +} + +void LowererMD::GenerateFastCmXxR8(IR::Instr *instr) +{ + this->GenerateFastCmXx(instr); +} + +void LowererMD::GenerateFastCmXx(IR::Instr *instr) +{ + // For float src: + // LDIMM dst, trueResult + // FCMP src1, src2 + // - BVS $done (NaN check iff B.cond is BNE) + // B.cond $done + // LDIMM dst, falseResult + // $done + + // For Int src: + // LDIMM dst, trueResult + // CMP src1, src2 + // B.cond $done + // LDIMM dst, falseResult + // $done: + + IR::Opnd * src1 = instr->UnlinkSrc1(); + IR::Opnd * src2 = instr->UnlinkSrc2(); + IR::Opnd * dst = instr->UnlinkDst(); + bool isIntDst = dst->AsRegOpnd()->m_sym->IsInt32(); + bool isFloatSrc = src1->IsFloat(); + Assert(!isFloatSrc || src2->IsFloat()); + Assert(!src1->IsInt64() || src2->IsInt64()); + Assert(!isFloatSrc || AutoSystemInfo::Data.SSE2Available()); + Assert(src1->IsRegOpnd()); + IR::Opnd * opndTrue; + IR::Opnd * opndFalse; + IR::Instr * newInstr; + IR::LabelInstr * done = IR::LabelInstr::New(Js::OpCode::Label, m_func); + + if (dst->IsEqual(src1)) + { + IR::RegOpnd *newSrc1 = IR::RegOpnd::New(src1->GetType(), m_func); + Lowerer::InsertMove(newSrc1, src1, instr); + src1 = newSrc1; + } + + if (dst->IsEqual(src2)) + { + IR::RegOpnd *newSrc2 = IR::RegOpnd::New(src1->GetType(), m_func); + Lowerer::InsertMove(newSrc2, src2, instr); + src2 = newSrc2; + } + + if (isIntDst) + { + opndTrue = IR::IntConstOpnd::New(1, TyInt32, this->m_func); + opndFalse = IR::IntConstOpnd::New(0, TyInt32, this->m_func); + } + else + { + opndTrue = this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue); + opndFalse = this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse); + } + + Lowerer::InsertMove(dst, opndTrue, instr); + + // CMP src1, src2 + newInstr = IR::Instr::New(isFloatSrc ? Js::OpCode::FCMP : Js::OpCode::CMP, this->m_func); + newInstr->SetSrc1(src1); + newInstr->SetSrc2(src2); + instr->InsertBefore(newInstr); + LowererMD::Legalize(newInstr); + + bool addNaNCheck = false; + Js::OpCode opcode = Js::OpCode::InvalidOpCode; + + switch (instr->m_opcode) + { + case Js::OpCode::CmEq_A: + case Js::OpCode::CmSrEq_A: + case Js::OpCode::CmEq_I4: + opcode = Js::OpCode::BEQ; + break; + + case Js::OpCode::CmNeq_A: + case Js::OpCode::CmSrNeq_A: + case Js::OpCode::CmNeq_I4: + opcode = Js::OpCode::BNE; + addNaNCheck = isFloatSrc; + break; + + case Js::OpCode::CmGt_A: + case Js::OpCode::CmGt_I4: + opcode = Js::OpCode::BGT; + break; + + case Js::OpCode::CmGe_A: + case Js::OpCode::CmGe_I4: + opcode = Js::OpCode::BGE; + break; + + case Js::OpCode::CmLt_A: + case Js::OpCode::CmLt_I4: + //Can't use BLT as is set when the operands are unordered (NaN). + opcode = isFloatSrc ? Js::OpCode::BCC : Js::OpCode::BLT; + break; + + case Js::OpCode::CmLe_A: + case Js::OpCode::CmLe_I4: + //Can't use BLE as it is set when the operands are unordered (NaN). + opcode = isFloatSrc ? Js::OpCode::BLS : Js::OpCode::BLE; + break; + + case Js::OpCode::CmUnGt_A: + case Js::OpCode::CmUnGt_I4: + opcode = Js::OpCode::BHI; + break; + + case Js::OpCode::CmUnGe_A: + case Js::OpCode::CmUnGe_I4: + opcode = Js::OpCode::BCS; + break; + + case Js::OpCode::CmUnLt_A: + case Js::OpCode::CmUnLt_I4: + opcode = Js::OpCode::BCC; + break; + + case Js::OpCode::CmUnLe_A: + case Js::OpCode::CmUnLe_I4: + opcode = Js::OpCode::BLS; + break; + + default: Assert(false); + } + + if (addNaNCheck) + { + newInstr = IR::BranchInstr::New(Js::OpCode::BVS, done, m_func); + instr->InsertBefore(newInstr); + } + + newInstr = IR::BranchInstr::New(opcode, done, m_func); + instr->InsertBefore(newInstr); + + Lowerer::InsertMove(dst, opndFalse, instr); + instr->InsertBefore(done); + instr->Remove(); } ///---------------------------------------------------------------------------- @@ -2804,6 +2951,7 @@ bool LowererMD::GenerateFastCmXxTaggedInt(IR::Instr *instr, bool isInHelper /* Lowerer::InsertMove(newSrc1, src1, instr); src1 = newSrc1; } + if (dst->IsEqual(src2)) { IR::RegOpnd *newSrc2 = IR::RegOpnd::New(TyMachReg, m_func); diff --git a/lib/Backend/arm64/LowerMD.h b/lib/Backend/arm64/LowerMD.h index c795d310c02..eb57a953a84 100644 --- a/lib/Backend/arm64/LowerMD.h +++ b/lib/Backend/arm64/LowerMD.h @@ -94,8 +94,9 @@ class LowererMD void GenerateTaggedZeroTest( IR::Opnd * opndSrc, IR::Instr * instrInsert, IR::LabelInstr * labelHelper = nullptr); bool GenerateObjectTest(IR::Opnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr * labelTarget, bool fContinueLabel = false); bool GenerateFastCmSrEqConst(IR::Instr *instr); - bool GenerateFastCmXxI4(IR::Instr *instr); - bool GenerateFastCmXxR8(IR::Instr *instr) { Assert(UNREACHED); return nullptr; } + void GenerateFastCmXxI4(IR::Instr *instr); + void GenerateFastCmXxR8(IR::Instr *instr); + void GenerateFastCmXx(IR::Instr *instr); bool GenerateFastCmXxTaggedInt(IR::Instr *instr, bool isInHelper = false); IR::Instr * GenerateConvBool(IR::Instr *instr); void GenerateClz(IR::Instr * instr);