From 226b6f755c907b670cb696417ed8a25895741f6f Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 8 Mar 2023 17:50:40 -0800 Subject: [PATCH 01/19] Initial work that allows optimizing x < 0 --- src/coreclr/jit/codegenarm64.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 602f6e5b1b7b15..6aa75896da67c5 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4548,6 +4548,29 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) if (op2->isContainedIntOrIImmed()) { GenTreeIntConCommon* intConst = op2->AsIntConCommon(); + + regNumber op1Reg = op1->GetRegNum(); + + if (compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && (targetReg != REG_NA) && + (targetReg == op1Reg) && tree->OperIs(GT_LT) && intConst->IsIntegralConst(0) && + !op1->isUsedFromMemory() && ((cmpSize == EA_4BYTE) || (cmpSize == EA_8BYTE))) + { + // if (targetReg != op1Reg) + //{ + // emit->emitIns_Mov(INS_mov, cmpSize, targetReg, op1Reg, /* canSkip */ false); + // } + + // if (tree->OperIs(GT_GE)) + //{ + // // emit "neg" for "x>=0" case + // emit->emitIns_R_R(INS_neg, cmpSize, targetReg, targetReg); + // } + + emit->emitIns_R_R_I(INS_lsr, cmpSize, targetReg, op1Reg, (int)cmpSize * 8 - 1); + genProduceReg(tree); + return; + } + emit->emitIns_R_I(ins, cmpSize, op1->GetRegNum(), intConst->IconValue()); } else From b3da93dbd7c5b41e49bc94741c6296ec6e66d8ef Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 9 Mar 2023 16:46:39 -0800 Subject: [PATCH 02/19] Few tweaks --- src/coreclr/jit/codegenarm64.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 6aa75896da67c5..d821810fc974ef 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4551,21 +4551,10 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) regNumber op1Reg = op1->GetRegNum(); - if (compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && (targetReg != REG_NA) && - (targetReg == op1Reg) && tree->OperIs(GT_LT) && intConst->IsIntegralConst(0) && - !op1->isUsedFromMemory() && ((cmpSize == EA_4BYTE) || (cmpSize == EA_8BYTE))) + if (compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && !op1->isUsedFromMemory() && + (targetReg != REG_NA) && tree->OperIs(GT_LT) && intConst->IsIntegralConst(0) && + ((cmpSize == EA_4BYTE) || (cmpSize == EA_8BYTE))) { - // if (targetReg != op1Reg) - //{ - // emit->emitIns_Mov(INS_mov, cmpSize, targetReg, op1Reg, /* canSkip */ false); - // } - - // if (tree->OperIs(GT_GE)) - //{ - // // emit "neg" for "x>=0" case - // emit->emitIns_R_R(INS_neg, cmpSize, targetReg, targetReg); - // } - emit->emitIns_R_R_I(INS_lsr, cmpSize, targetReg, op1Reg, (int)cmpSize * 8 - 1); genProduceReg(tree); return; From 41d3ecb1aec1eb7e2245d42d39ae271a56c224b9 Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 9 Mar 2023 18:54:00 -0800 Subject: [PATCH 03/19] Optimized x < 0 and x >= 0 for conditionals --- src/coreclr/jit/codegenarm64.cpp | 20 +++++++++++++++++++- src/coreclr/jit/gentree.h | 4 ++++ src/coreclr/jit/lower.cpp | 22 +++++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index d821810fc974ef..18e0168d0a8ae9 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4560,7 +4560,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) return; } - emit->emitIns_R_I(ins, cmpSize, op1->GetRegNum(), intConst->IconValue()); + emit->emitIns_R_I(ins, cmpSize, op1Reg, intConst->IconValue()); } else { @@ -4745,6 +4745,24 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); } + else if (tree->gtFlags & GTF_JCMP_LT) + { + assert(op2->IsIntegralConst(0)); + + instruction ins = INS_tbz; + int imm = (int)attr * 8 - 1; + + GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); + } + else if (tree->gtFlags & GTF_JCMP_GE) + { + assert(op2->IsIntegralConst(0)); + + instruction ins = INS_tbnz; + int imm = (int)attr * 8 - 1; + + GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); + } else { assert(op2->IsIntegralConst(0)); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 9972b71d8b8c54..50fdd93ac18dbb 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -511,6 +511,10 @@ enum GenTreeFlags : unsigned int GTF_JCMP_EQ = 0x80000000, // GTF_JCMP_EQ -- Branch on equal rather than not equal GTF_JCMP_TST = 0x40000000, // GTF_JCMP_TST -- Use bit test instruction rather than compare against zero instruction +#ifdef TARGET_ARM64 + GTF_JCMP_LT = 0x20000000, // GTF_JCMP_LT -- Branch on less than + GTF_JCMP_GE = 0x10000000, // GTF_JCMP_GE -- Branch on greater than or equal +#endif #if defined(TARGET_LOONGARCH64) GTF_JCMP_MASK = 0x3E000000, // For LoongArch64, Using the five bits[29:25] to encoding the GenCondition:code. #endif diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 81247ca991f77d..9178504e09b174 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3314,6 +3314,20 @@ GenTree* Lowering::LowerCompare(GenTree* cmp) } } #endif // TARGET_XARCH + +//#ifdef TARGET_ARM64 +// if (comp->opts.OptimizationEnabled() && !cmp->gtSetFlags() && cmp->TypeIs(TYP_INT, TYP_LONG) && cmp->OperIs(GT_LT) && +// cmp->gtGetOp2()->IsIntegralConst(0)) +// { +// ssize_t shiftAmount = cmp->TypeIs(TYP_LONG) ? 63 : 31; +// +// cmp->ChangeOper(GT_RSZ); +// cmp->gtGetOp2()->AsIntConCommon()->SetIntegralValue(shiftAmount); +// +// return LowerNode(cmp); +// } +//#endif // TARGET_ARM64 + ContainCheckCompare(cmp->AsOp()); return cmp->gtNext; } @@ -3352,6 +3366,12 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) flags = relop->OperIs(GT_EQ) ? GTF_JCMP_EQ : GTF_EMPTY; useJCMP = true; } + else if (relop->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) + { + // Codegen will use tbz or tbnz in codegen which do not affect the flag register + flags = relop->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; + useJCMP = true; + } else if (relop->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) { // Codegen will use tbz or tbnz in codegen which do not affect the flag register @@ -3362,7 +3382,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) if (useJCMP) { relop->SetOper(GT_JCMP); - relop->gtFlags &= ~(GTF_JCMP_TST | GTF_JCMP_EQ); + relop->gtFlags &= ~(GTF_JCMP_TST | GTF_JCMP_EQ | GTF_JCMP_LT); relop->gtFlags |= flags; relop->gtType = TYP_VOID; From 767fe62e5caca2c6ec2be9568067ae74b5dadf8e Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 9 Mar 2023 19:04:22 -0800 Subject: [PATCH 04/19] Removed old commented code. Switched tbz and tbnz --- src/coreclr/jit/codegenarm64.cpp | 4 ++-- src/coreclr/jit/lower.cpp | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 18e0168d0a8ae9..ac2fd41b21e77a 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4749,7 +4749,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) { assert(op2->IsIntegralConst(0)); - instruction ins = INS_tbz; + instruction ins = INS_tbnz; int imm = (int)attr * 8 - 1; GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); @@ -4758,7 +4758,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) { assert(op2->IsIntegralConst(0)); - instruction ins = INS_tbnz; + instruction ins = INS_tbz; int imm = (int)attr * 8 - 1; GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 9178504e09b174..e7f523322153f4 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3314,20 +3314,6 @@ GenTree* Lowering::LowerCompare(GenTree* cmp) } } #endif // TARGET_XARCH - -//#ifdef TARGET_ARM64 -// if (comp->opts.OptimizationEnabled() && !cmp->gtSetFlags() && cmp->TypeIs(TYP_INT, TYP_LONG) && cmp->OperIs(GT_LT) && -// cmp->gtGetOp2()->IsIntegralConst(0)) -// { -// ssize_t shiftAmount = cmp->TypeIs(TYP_LONG) ? 63 : 31; -// -// cmp->ChangeOper(GT_RSZ); -// cmp->gtGetOp2()->AsIntConCommon()->SetIntegralValue(shiftAmount); -// -// return LowerNode(cmp); -// } -//#endif // TARGET_ARM64 - ContainCheckCompare(cmp->AsOp()); return cmp->gtNext; } From 4a96fb716fd61e30bde286f07eb534e476c1c067 Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 9 Mar 2023 19:09:45 -0800 Subject: [PATCH 05/19] Simplified --- src/coreclr/jit/codegenarm64.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index ac2fd41b21e77a..a37dbbb1ee3298 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4745,20 +4745,11 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); } - else if (tree->gtFlags & GTF_JCMP_LT) + else if (tree->gtFlags & (GTF_JCMP_LT | GTF_JCMP_GE)) { assert(op2->IsIntegralConst(0)); - instruction ins = INS_tbnz; - int imm = (int)attr * 8 - 1; - - GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); - } - else if (tree->gtFlags & GTF_JCMP_GE) - { - assert(op2->IsIntegralConst(0)); - - instruction ins = INS_tbz; + instruction ins = (tree->gtFlags & GTF_JCMP_LT) ? INS_tbnz : INS_tbz; int imm = (int)attr * 8 - 1; GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); From c366a7a5947573fc0c123ef076ebebdc5d8d446d Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 9 Mar 2023 19:24:53 -0800 Subject: [PATCH 06/19] Fix build --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 00774fda6d3816..d5d1c8f97eaedb 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3382,7 +3382,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) { // Codegen will use tbz or tbnz in codegen which do not affect the flag register - flags = relop->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; + flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; useJCMP = true; } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) From 006bfead6dd54863bb034b9c765670ad7d232ce3 Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 10 Mar 2023 11:22:00 -0800 Subject: [PATCH 07/19] Check for possible interference --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index d5d1c8f97eaedb..409d0ea8bb339b 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3379,7 +3379,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) flags = cond->OperIs(GT_EQ) ? GTF_JCMP_EQ : GTF_EMPTY; useJCMP = true; } - else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) + else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0) && (relopOp2->gtNext == relopOp1)) { // Codegen will use tbz or tbnz in codegen which do not affect the flag register flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; From 72fd1d032a131b57bb5353d3f75588227437e067 Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 10 Mar 2023 12:10:27 -0800 Subject: [PATCH 08/19] Reverse --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 409d0ea8bb339b..1c0ebd11035b14 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3379,7 +3379,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) flags = cond->OperIs(GT_EQ) ? GTF_JCMP_EQ : GTF_EMPTY; useJCMP = true; } - else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0) && (relopOp2->gtNext == relopOp1)) + else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0) && (relopOp1->gtNext == relopOp2)) { // Codegen will use tbz or tbnz in codegen which do not affect the flag register flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; From bd286a500f6ba8bccb6a981c0785ec7d154505ec Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 10 Mar 2023 12:39:30 -0800 Subject: [PATCH 09/19] Check invariant-range --- src/coreclr/jit/codegenarm64.cpp | 5 ++--- src/coreclr/jit/lower.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 028109f2d4d986..85cfe3c51ad280 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4535,9 +4535,8 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) regNumber op1Reg = op1->GetRegNum(); - if (compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && !op1->isUsedFromMemory() && - (targetReg != REG_NA) && tree->OperIs(GT_LT) && intConst->IsIntegralConst(0) && - ((cmpSize == EA_4BYTE) || (cmpSize == EA_8BYTE))) + if (compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && (targetReg != REG_NA) && + tree->OperIs(GT_LT) && intConst->IsIntegralConst(0) && ((cmpSize == EA_4BYTE) || (cmpSize == EA_8BYTE))) { emit->emitIns_R_R_I(INS_lsr, cmpSize, targetReg, op1Reg, (int)cmpSize * 8 - 1); genProduceReg(tree); diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 1c0ebd11035b14..fe0d446d1477f6 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3379,7 +3379,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) flags = cond->OperIs(GT_EQ) ? GTF_JCMP_EQ : GTF_EMPTY; useJCMP = true; } - else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0) && (relopOp1->gtNext == relopOp2)) + else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0) && IsInvariantInRange(cond, jtrue)) { // Codegen will use tbz or tbnz in codegen which do not affect the flag register flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; From 69a49fd456d979f48daa8a946b65a188e6ec5598 Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 10 Mar 2023 14:52:07 -0800 Subject: [PATCH 10/19] Cleanup --- src/coreclr/jit/codegenarm64.cpp | 4 ++++ src/coreclr/jit/lower.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 85cfe3c51ad280..eef743e12d61a6 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4747,6 +4747,10 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) { assert(op2->IsIntegralConst(0)); + //GetEmitter()->emitIns_R_I(INS_cmp, attr, reg, 0); + + //inst_SETCC(GenCondition::FromRelop(tree), tree->TypeGet(), reg); + instruction ins = (tree->gtFlags & GTF_JCMP_LT) ? INS_tbnz : INS_tbz; int imm = (int)attr * 8 - 1; diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index fe0d446d1477f6..d5d1c8f97eaedb 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3379,7 +3379,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) flags = cond->OperIs(GT_EQ) ? GTF_JCMP_EQ : GTF_EMPTY; useJCMP = true; } - else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0) && IsInvariantInRange(cond, jtrue)) + else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) { // Codegen will use tbz or tbnz in codegen which do not affect the flag register flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; From 359609dd7654ac9fb5fa52b0b67043890809cfde Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 10 Mar 2023 14:54:24 -0800 Subject: [PATCH 11/19] Cleanup --- src/coreclr/jit/codegenarm64.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index eef743e12d61a6..85cfe3c51ad280 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4747,10 +4747,6 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) { assert(op2->IsIntegralConst(0)); - //GetEmitter()->emitIns_R_I(INS_cmp, attr, reg, 0); - - //inst_SETCC(GenCondition::FromRelop(tree), tree->TypeGet(), reg); - instruction ins = (tree->gtFlags & GTF_JCMP_LT) ? INS_tbnz : INS_tbz; int imm = (int)attr * 8 - 1; From a689d8106aafb2c868889e23597847101816b0b6 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 13 Mar 2023 15:24:15 -0700 Subject: [PATCH 12/19] Handle new JCMP flags in gtReverseCond --- src/coreclr/jit/codegenarm64.cpp | 3 +++ src/coreclr/jit/gentree.cpp | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 85cfe3c51ad280..5b71103493de30 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4734,6 +4734,8 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) if (tree->gtFlags & GTF_JCMP_TST) { + assert(!(tree->gtFlags & (GTF_JCMP_LT | GTF_JCMP_GE))); + ssize_t compareImm = op2->AsIntCon()->IconValue(); assert(isPow2(compareImm)); @@ -4746,6 +4748,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) else if (tree->gtFlags & (GTF_JCMP_LT | GTF_JCMP_GE)) { assert(op2->IsIntegralConst(0)); + assert(!(tree->gtFlags & GTF_JCMP_EQ)); instruction ins = (tree->gtFlags & GTF_JCMP_LT) ? INS_tbnz : INS_tbz; int imm = (int)attr * 8 - 1; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 842fde901f9504..4fe0711b4fd14b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -3480,9 +3480,28 @@ GenTree* Compiler::gtReverseCond(GenTree* tree) } else if (tree->OperIs(GT_JCMP)) { - // Flip the GTF_JCMP_EQ +#ifdef TARGET_ARM64 + // Flip the GTF_JCMP_LT, GTF_JCMP_GE // // This causes switching + // tbz <=> tbnz + + if (tree->gtFlags & GTF_JCMP_LT) + { + tree->gtFlags ^= GTF_JCMP_LT; + tree->gtFlags |= GTF_JCMP_GE; + return tree; + } + if (tree->gtFlags & GTF_JCMP_GE) + { + tree->gtFlags ^= GTF_JCMP_GE; + tree->gtFlags |= GTF_JCMP_LT; + return tree; + } +#endif // TARGET_ARM64 + + // Flip the GTF_JCMP_EQ + // On ARM64, this causes switching // cbz <=> cbnz // tbz <=> tbnz tree->gtFlags ^= GTF_JCMP_EQ; From 2f6f3789ce89f0b73fb9a8764e313f18537dc693 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 13 Mar 2023 15:25:22 -0700 Subject: [PATCH 13/19] Comment update --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index d5d1c8f97eaedb..241f863214c983 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3381,7 +3381,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) } else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) { - // Codegen will use tbz or tbnz in codegen which do not affect the flag register + // Codegen will use tbnz or tbz in codegen which do not affect the flag register flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; useJCMP = true; } From 6e3114912de6be4b5d434d8173ee1b6bbbaf4b0e Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 14 Mar 2023 03:58:59 -0700 Subject: [PATCH 14/19] Remove extra flags --- src/coreclr/jit/codegenarm64.cpp | 23 ++++++++++------------- src/coreclr/jit/gentree.cpp | 20 -------------------- src/coreclr/jit/gentree.h | 4 ---- src/coreclr/jit/lower.cpp | 4 ++-- 4 files changed, 12 insertions(+), 39 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 5b71103493de30..2b25170866e92f 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4734,24 +4734,21 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) if (tree->gtFlags & GTF_JCMP_TST) { - assert(!(tree->gtFlags & (GTF_JCMP_LT | GTF_JCMP_GE))); - ssize_t compareImm = op2->AsIntCon()->IconValue(); - assert(isPow2(compareImm)); + assert(isPow2(compareImm) || (compareImm == 0)); instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_tbz : INS_tbnz; - int imm = genLog2((size_t)compareImm); - - GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); - } - else if (tree->gtFlags & (GTF_JCMP_LT | GTF_JCMP_GE)) - { - assert(op2->IsIntegralConst(0)); - assert(!(tree->gtFlags & GTF_JCMP_EQ)); - instruction ins = (tree->gtFlags & GTF_JCMP_LT) ? INS_tbnz : INS_tbz; - int imm = (int)attr * 8 - 1; + int imm; + if (compareImm == 0) + { + imm = (int)attr * 8 - 1; + } + else + { + imm = genLog2((size_t)compareImm); + } GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); } diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 4fe0711b4fd14b..83df1116f3b20e 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -3480,26 +3480,6 @@ GenTree* Compiler::gtReverseCond(GenTree* tree) } else if (tree->OperIs(GT_JCMP)) { -#ifdef TARGET_ARM64 - // Flip the GTF_JCMP_LT, GTF_JCMP_GE - // - // This causes switching - // tbz <=> tbnz - - if (tree->gtFlags & GTF_JCMP_LT) - { - tree->gtFlags ^= GTF_JCMP_LT; - tree->gtFlags |= GTF_JCMP_GE; - return tree; - } - if (tree->gtFlags & GTF_JCMP_GE) - { - tree->gtFlags ^= GTF_JCMP_GE; - tree->gtFlags |= GTF_JCMP_LT; - return tree; - } -#endif // TARGET_ARM64 - // Flip the GTF_JCMP_EQ // On ARM64, this causes switching // cbz <=> cbnz diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index d9dfd42388fe85..5ab36443360b8f 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -511,10 +511,6 @@ enum GenTreeFlags : unsigned int GTF_JCMP_EQ = 0x80000000, // GTF_JCMP_EQ -- Branch on equal rather than not equal GTF_JCMP_TST = 0x40000000, // GTF_JCMP_TST -- Use bit test instruction rather than compare against zero instruction -#ifdef TARGET_ARM64 - GTF_JCMP_LT = 0x20000000, // GTF_JCMP_LT -- Branch on less than - GTF_JCMP_GE = 0x10000000, // GTF_JCMP_GE -- Branch on greater than or equal -#endif #if defined(TARGET_LOONGARCH64) GTF_JCMP_MASK = 0x3E000000, // For LoongArch64, Using the five bits[29:25] to encoding the GenCondition:code. #endif diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 241f863214c983..d5cc0ed5ac7979 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3382,7 +3382,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) { // Codegen will use tbnz or tbz in codegen which do not affect the flag register - flags = cond->OperIs(GT_LT) ? GTF_JCMP_LT : GTF_JCMP_GE; + flags = GTF_JCMP_TST | (cond->OperIs(GT_LT) ? GTF_EMPTY : GTF_JCMP_EQ); useJCMP = true; } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) @@ -3395,7 +3395,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) if (useJCMP) { jtrue->SetOper(GT_JCMP); - jtrue->gtFlags &= ~(GTF_JCMP_TST | GTF_JCMP_EQ | GTF_JCMP_LT | GTF_JCMP_GE); + jtrue->gtFlags &= ~(GTF_JCMP_TST | GTF_JCMP_EQ); jtrue->gtOp1 = relopOp1; jtrue->gtOp2 = relopOp2; jtrue->gtFlags |= flags; From 206a8daf701c2786befe1d841889e08b67afb2a0 Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 14 Mar 2023 05:10:04 -0700 Subject: [PATCH 15/19] Simplify further --- src/coreclr/jit/codegenarm64.cpp | 13 ++----------- src/coreclr/jit/lower.cpp | 1 + 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 2b25170866e92f..8abb897bb53d7a 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4736,19 +4736,10 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) { ssize_t compareImm = op2->AsIntCon()->IconValue(); - assert(isPow2(compareImm) || (compareImm == 0)); + assert(isPow2(compareImm)); instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_tbz : INS_tbnz; - - int imm; - if (compareImm == 0) - { - imm = (int)attr * 8 - 1; - } - else - { - imm = genLog2((size_t)compareImm); - } + int imm = genLog2((size_t)compareImm); GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm); } diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index d5cc0ed5ac7979..9556953f39bbcb 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3384,6 +3384,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) // Codegen will use tbnz or tbz in codegen which do not affect the flag register flags = GTF_JCMP_TST | (cond->OperIs(GT_LT) ? GTF_EMPTY : GTF_JCMP_EQ); useJCMP = true; + relopOp2->AsIntConCommon()->SetIntegralValue((1 << (8 * genTypeSize(genActualType(relopOp1)) - 1))); } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) { From a95a2ba5c415ac8e3cc95a3ddcb6d2a50b23305a Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 14 Mar 2023 05:15:26 -0700 Subject: [PATCH 16/19] Fix warning --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 9556953f39bbcb..ee75f651e17d50 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3384,7 +3384,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) // Codegen will use tbnz or tbz in codegen which do not affect the flag register flags = GTF_JCMP_TST | (cond->OperIs(GT_LT) ? GTF_EMPTY : GTF_JCMP_EQ); useJCMP = true; - relopOp2->AsIntConCommon()->SetIntegralValue((1 << (8 * genTypeSize(genActualType(relopOp1)) - 1))); + relopOp2->AsIntConCommon()->SetIntegralValue((1L << (8 * genTypeSize(genActualType(relopOp1)) - 1))); } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) { From bbabdd1234beb8aed0b4b824c58303d44c133ec2 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Tue, 14 Mar 2023 05:15:48 -0700 Subject: [PATCH 17/19] Update src/coreclr/jit/lower.cpp Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index ee75f651e17d50..48e28e6b344de0 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3379,7 +3379,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) flags = cond->OperIs(GT_EQ) ? GTF_JCMP_EQ : GTF_EMPTY; useJCMP = true; } - else if (cond->OperIs(GT_LT, GT_GE) && relopOp2->IsIntegralConst(0)) + else if (cond->OperIs(GT_LT, GT_GE) && !cond->IsUnsigned() && relopOp2->IsIntegralConst(0)) { // Codegen will use tbnz or tbz in codegen which do not affect the flag register flags = GTF_JCMP_TST | (cond->OperIs(GT_LT) ? GTF_EMPTY : GTF_JCMP_EQ); From 9a0b138d12db8e20531972fe2924d1262c7bf559 Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 14 Mar 2023 05:19:58 -0700 Subject: [PATCH 18/19] Fix warning --- src/coreclr/jit/lower.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 48e28e6b344de0..df5302acaf051a 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3384,7 +3384,8 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) // Codegen will use tbnz or tbz in codegen which do not affect the flag register flags = GTF_JCMP_TST | (cond->OperIs(GT_LT) ? GTF_EMPTY : GTF_JCMP_EQ); useJCMP = true; - relopOp2->AsIntConCommon()->SetIntegralValue((1L << (8 * genTypeSize(genActualType(relopOp1)) - 1))); + relopOp2->AsIntConCommon()->SetIntegralValue( + (static_cast(1) << (8 * genTypeSize(genActualType(relopOp1)) - 1))); } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) { From 887a2333d0ad3f0a653e20188015d32534a0316e Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 14 Mar 2023 13:01:36 -0700 Subject: [PATCH 19/19] Fixing assert --- src/coreclr/jit/codegenarm64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 8abb897bb53d7a..f8b161fef89958 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -4736,7 +4736,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOp* tree) { ssize_t compareImm = op2->AsIntCon()->IconValue(); - assert(isPow2(compareImm)); + assert(isPow2(((size_t)compareImm))); instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_tbz : INS_tbnz; int imm = genLog2((size_t)compareImm);