Skip to content

JIT: Introduce GT_JTEST and clean up GT_JCMP flags #85242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1237,10 +1237,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
BasicBlock* genCallFinally(BasicBlock* block);
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
// TODO: refactor for LA.
void genCodeForJumpCompare(GenTreeOp* tree);
void genCodeForJumpCompare(GenTreeOpCC* tree);
#endif
#if defined(TARGET_ARM64)
void genCodeForJumpCompare(GenTreeOp* tree);
void genCodeForJumpCompare(GenTreeOpCC* tree);
void genCodeForBfiz(GenTreeOp* tree);
void genCodeForCond(GenTreeOp* tree);
#endif // TARGET_ARM64
Expand Down
25 changes: 13 additions & 12 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4804,9 +4804,9 @@ void CodeGen::genCodeForCinc(GenTreeOp* cinc)
}

//------------------------------------------------------------------------
// genCodeForJumpCompare: Generates code for jmpCompare statement.
// genCodeForJumpCompare: Generates code for a GT_JCMP or GT_JTEST statement.
//
// A GT_JCMP node is created when a comparison and conditional branch
// A GT_JCMP/GT_JTEST node is created when a comparison and conditional branch
// can be executed in a single instruction.
//
// Arm64 has a few instructions with this behavior.
Expand All @@ -4827,42 +4827,43 @@ void CodeGen::genCodeForCinc(GenTreeOp* cinc)
// This node is responsible for consuming the register, and emitting the
// appropriate fused compare/test and branch instruction
//
// Two flags guide code generation
// GTF_JCMP_TST -- Set if this is a tbz/tbnz rather than cbz/cbnz
// GTF_JCMP_EQ -- Set if this is cbz/tbz rather than cbnz/tbnz
//
// Arguments:
// tree - The GT_JCMP tree node.
// tree - The GT_JCMP/GT_JTEST tree node.
//
// Return Value:
// None
//
void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);

GenTree* op1 = tree->gtGetOp1();
GenTree* op2 = tree->gtGetOp2();

assert(tree->OperIs(GT_JCMP));
assert(tree->OperIs(GT_JCMP, GT_JTEST));
assert(!varTypeIsFloating(tree));
assert(!op1->isUsedFromMemory());
assert(!op2->isUsedFromMemory());
assert(op2->IsCnsIntOrI());
assert(op2->isContained());

GenCondition cc = tree->gtCondition;

// For ARM64 we only expect equality comparisons.
assert((cc.GetCode() == GenCondition::EQ) || (cc.GetCode() == GenCondition::NE));

genConsumeOperands(tree);

regNumber reg = op1->GetRegNum();
emitAttr attr = emitActualTypeSize(op1->TypeGet());

if (tree->gtFlags & GTF_JCMP_TST)
if (tree->OperIs(GT_JTEST))
{
ssize_t compareImm = op2->AsIntCon()->IconValue();

assert(isPow2(((size_t)compareImm)));

instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_tbz : INS_tbnz;
instruction ins = (cc.GetCode() == GenCondition::EQ) ? INS_tbz : INS_tbnz;
int imm = genLog2((size_t)compareImm);

GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm);
Expand All @@ -4871,7 +4872,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
{
assert(op2->IsIntegralConst(0));

instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_cbz : INS_cbnz;
instruction ins = (cc.GetCode() == GenCondition::EQ) ? INS_cbz : INS_cbnz;

GetEmitter()->emitIns_J_R(ins, attr, compiler->compCurBB->bbJumpDest, reg);
}
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;

case GT_JCMP:
genCodeForJumpCompare(treeNode->AsOp());
case GT_JTEST:
genCodeForJumpCompare(treeNode->AsOpCC());
break;

case GT_CCMP:
Expand Down
35 changes: 16 additions & 19 deletions src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4311,7 +4311,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
// genCodeForJumpCompare: Generates code for jmpCompare statement.
//
// A GT_JCMP node is created for an integer-comparison's conditional branch.
void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);

Expand All @@ -4337,10 +4337,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
instruction ins = INS_invalid;
int regs = 0;

int cond = ((int)tree->gtFlags >> 25) & 0xf; // GenCondition::Code.
assert((((int)tree->gtFlags >> 25) & GenCondition::Float) == 0);

bool IsUnsigned = (cond & GenCondition::Unsigned) != 0;
GenCondition cond = tree->gtCondition;

emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
regNumber regOp1 = op1->GetRegNum();
Expand All @@ -4354,7 +4351,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
switch (cmpSize)
{
case EA_4BYTE:
if (IsUnsigned)
if (cond.IsUnsigned())
{
imm = static_cast<uint32_t>(imm);

Expand All @@ -4371,7 +4368,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
case EA_8BYTE:
break;
case EA_1BYTE:
if (IsUnsigned)
if (cond.IsUnsigned())
{
imm = static_cast<uint8_t>(imm);
}
Expand All @@ -4388,7 +4385,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
regs = (int)REG_RA << 5;
}

switch (cond)
switch (cond.GetCode())
{
case GenCondition::EQ:
regs |= ((int)regOp1);
Expand All @@ -4401,22 +4398,22 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
case GenCondition::UGE:
case GenCondition::SGE:
regs |= ((int)regOp1);
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
case GenCondition::UGT:
case GenCondition::SGT:
regs = imm ? ((((int)regOp1) << 5) | (int)REG_RA) : (((int)regOp1) << 5);
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULT:
case GenCondition::SLT:
regs |= ((int)regOp1);
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULE:
case GenCondition::SLE:
regs = imm ? ((((int)regOp1) << 5) | (int)REG_RA) : (((int)regOp1) << 5);
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
default:
NO_WAY("unexpected condition type");
Expand All @@ -4433,7 +4430,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
assert(regOp1 != tmpRegOp2);
assert(regOp2 != tmpRegOp2);

if (IsUnsigned)
if (cond.IsUnsigned())
{
emit->emitIns_R_R_I_I(INS_bstrpick_d, EA_8BYTE, tmpRegOp1, regOp1, 31, 0);
emit->emitIns_R_R_I_I(INS_bstrpick_d, EA_8BYTE, tmpRegOp2, regOp2, 31, 0);
Expand All @@ -4448,7 +4445,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
regOp2 = tmpRegOp2;
}

switch (cond)
switch (cond.GetCode())
{
case GenCondition::EQ:
regs = (((int)regOp1) << 5) | (int)regOp2;
Expand All @@ -4461,22 +4458,22 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
case GenCondition::UGE:
case GenCondition::SGE:
regs = ((int)regOp1 | ((int)regOp2 << 5));
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
case GenCondition::UGT:
case GenCondition::SGT:
regs = (((int)regOp1) << 5) | (int)regOp2;
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULT:
case GenCondition::SLT:
regs = ((int)regOp1 | ((int)regOp2 << 5));
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULE:
case GenCondition::SLE:
regs = (((int)regOp1) << 5) | (int)regOp2;
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
default:
NO_WAY("unexpected condition type-regs");
Expand Down Expand Up @@ -5075,7 +5072,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;

case GT_JCMP:
genCodeForJumpCompare(treeNode->AsOp());
genCodeForJumpCompare(treeNode->AsOpCC());
break;

case GT_RETURNTRAP:
Expand Down
37 changes: 18 additions & 19 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3567,7 +3567,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
// Return Value:
// None
//
void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);

Expand All @@ -3591,11 +3591,10 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
instruction ins = INS_invalid;
int regs = 0;

int cond = ((int)tree->gtFlags >> 25) & 0xf; // GenCondition::Code.
assert((((int)tree->gtFlags >> 25) & GenCondition::Float) == 0);
bool IsUnsigned = (cond & GenCondition::Unsigned) != 0;
emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
regNumber regOp1 = op1->GetRegNum();
GenCondition cond = tree->gtCondition;

emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
regNumber regOp1 = op1->GetRegNum();

if (varTypeIsFloating(op1Type))
{
Expand All @@ -3610,7 +3609,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
switch (cmpSize)
{
case EA_4BYTE:
if (IsUnsigned)
if (cond.IsUnsigned())
{
imm = static_cast<uint32_t>(imm);

Expand All @@ -3635,7 +3634,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
regs = (int)REG_RA << 5;
}

switch (cond)
switch (cond.GetCode())
{
case GenCondition::EQ:
regs |= ((int)regOp1);
Expand All @@ -3648,22 +3647,22 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
case GenCondition::UGE:
case GenCondition::SGE:
regs |= ((int)regOp1);
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
case GenCondition::UGT:
case GenCondition::SGT:
regs = imm ? ((((int)regOp1) << 5) | (int)REG_RA) : (((int)regOp1) << 5);
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULT:
case GenCondition::SLT:
regs |= ((int)regOp1);
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULE:
case GenCondition::SLE:
regs = imm ? ((((int)regOp1) << 5) | (int)REG_RA) : (((int)regOp1) << 5);
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
default:
NO_WAY("unexpected condition type");
Expand All @@ -3680,7 +3679,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
assert(regOp1 != tmpRegOp2);
assert(regOp2 != tmpRegOp2);

if (IsUnsigned)
if (cond.IsUnsigned())
{
emit->emitIns_R_R_I(INS_slli, EA_8BYTE, tmpRegOp1, regOp1, 32);
emit->emitIns_R_R_I(INS_srli, EA_8BYTE, tmpRegOp1, tmpRegOp1, 32);
Expand All @@ -3697,7 +3696,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
regOp2 = tmpRegOp2;
}

switch (cond)
switch (cond.GetCode())
{
case GenCondition::EQ:
regs = (((int)regOp1) << 5) | (int)regOp2;
Expand All @@ -3710,22 +3709,22 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
case GenCondition::UGE:
case GenCondition::SGE:
regs = ((int)regOp1 | ((int)regOp2 << 5));
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
case GenCondition::UGT:
case GenCondition::SGT:
regs = (((int)regOp1) << 5) | (int)regOp2;
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULT:
case GenCondition::SLT:
regs = ((int)regOp1 | ((int)regOp2 << 5));
ins = IsUnsigned ? INS_bltu : INS_blt;
ins = cond.IsUnsigned() ? INS_bltu : INS_blt;
break;
case GenCondition::ULE:
case GenCondition::SLE:
regs = (((int)regOp1) << 5) | (int)regOp2;
ins = IsUnsigned ? INS_bgeu : INS_bge;
ins = cond.IsUnsigned() ? INS_bgeu : INS_bge;
break;
default:
NO_WAY("unexpected condition type-regs");
Expand Down Expand Up @@ -4421,7 +4420,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;

case GT_JCMP:
genCodeForJumpCompare(treeNode->AsOp());
genCodeForJumpCompare(treeNode->AsOpCC());
break;

case GT_RETURNTRAP:
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/fgstmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ inline bool OperIsControlFlow(genTreeOps oper)
{
case GT_JTRUE:
case GT_JCMP:
case GT_JTEST:
case GT_JCC:
case GT_SWITCH:
case GT_LABEL:
Expand Down
18 changes: 5 additions & 13 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3540,13 +3540,10 @@ GenTree* Compiler::gtReverseCond(GenTree* tree)
GenTreeCC* cc = tree->AsCC();
cc->gtCondition = GenCondition::Reverse(cc->gtCondition);
}
else if (tree->OperIs(GT_JCMP))
else if (tree->OperIs(GT_JCMP, GT_JTEST))
{
// Flip the GTF_JCMP_EQ
// On ARM64, this causes switching
// cbz <=> cbnz
// tbz <=> tbnz
tree->gtFlags ^= GTF_JCMP_EQ;
GenTreeOpCC* opCC = tree->AsOpCC();
opCC->gtCondition = GenCondition::Reverse(opCC->gtCondition);
}
else
{
Expand Down Expand Up @@ -10725,11 +10722,6 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_
}
goto DASH;

case GT_JCMP:
printf((tree->gtFlags & GTF_JCMP_TST) ? "T" : "C");
printf((tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
goto DASH;

case GT_CNS_INT:
if (tree->IsIconHandle())
{
Expand Down Expand Up @@ -11792,8 +11784,8 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
printf(" cond=%s", tree->AsCC()->gtCondition.Name());
break;
case GT_JCMP:
printf(" cond=%s%s", (tree->gtFlags & GTF_JCMP_TST) ? "TEST_" : "",
(tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
case GT_JTEST:
printf(" cond=%s", tree->AsOpCC()->gtCondition.Name());
break;

default:
Expand Down
Loading