Skip to content

Commit

Permalink
[MERGE #5721 @sigatrev] ARM/ARM64: Implement LowererMD::GenerateFastC…
Browse files Browse the repository at this point in the history
…mXx(R8)

Merge pull request #5721 from sigatrev:CmXx

This path was previously only hit in AsmJs, but PR #5686 caused it to be hit with normal JS. This commit implements the methods for ARM and ARM64.
  • Loading branch information
sigatrev committed Sep 26, 2018
2 parents 10a6930 + 2ea61b5 commit 831e6b2
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 8 deletions.
156 changes: 154 additions & 2 deletions lib/Backend/arm/LowerMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

///----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions lib/Backend/arm/LowerMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
152 changes: 150 additions & 2 deletions lib/Backend/arm64/LowerMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

///----------------------------------------------------------------------------
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions lib/Backend/arm64/LowerMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 831e6b2

Please sign in to comment.