From 9094b6ac2b85fe5d707899c4687ccbc9eae8f11f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 8 Sep 2023 20:26:19 +0200 Subject: [PATCH 1/5] Enable TryLowerSwitchToBitTest for arm64 --- src/coreclr/jit/lower.cpp | 42 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index a32fc24e95931b..8abf281a63304e 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1150,10 +1150,6 @@ GenTree* Lowering::LowerSwitch(GenTree* node) bool Lowering::TryLowerSwitchToBitTest( BasicBlock* jumpTable[], unsigned jumpCount, unsigned targetCount, BasicBlock* bbSwitch, GenTree* switchValue) { -#ifndef TARGET_XARCH - // Other architectures may use this if they substitute GT_BT with equivalent code. - return false; -#else assert(jumpCount >= 2); assert(targetCount >= 2); assert(bbSwitch->bbJumpKind == BBJ_SWITCH); @@ -1237,6 +1233,10 @@ bool Lowering::TryLowerSwitchToBitTest( bitTable = ~bitTable; std::swap(bbCase0, bbCase1); } + + const bool useBt = true; +#else + const bool useBt = false; #endif // @@ -1270,20 +1270,36 @@ bool Lowering::TryLowerSwitchToBitTest( comp->fgAddRefPred(bbCase1, bbSwitch); } - // - // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. - // - var_types bitTableType = (bitCount <= (genTypeSize(TYP_INT) * 8)) ? TYP_INT : TYP_LONG; GenTree* bitTableIcon = comp->gtNewIconNode(bitTable, bitTableType); - GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); - bitTest->gtFlags |= GTF_SET_FLAGS; - GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); - LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); + if (useBt) + { + // + // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. + // + var_types bitTableType = (bitCount <= (genTypeSize(TYP_INT) * 8)) ? TYP_INT : TYP_LONG; + GenTree* bitTableIcon = comp->gtNewIconNode(bitTable, bitTableType); + GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); + bitTest->gtFlags |= GTF_SET_FLAGS; + GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); + LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); + } + else + { + // + // Fallback to AND(RSZ(bitTable, switchValue), 1) + // + GenTree* tstCns = comp->gtNewIconNode(bbSwitch->bbNext == bbCase0 ? 0 : 1, bitTableType); + GenTree* shift = comp->gtNewOperNode(GT_RSZ, bitTableType, bitTableIcon, switchValue); + GenTree* bitTest = comp->gtNewOperNode(GT_TEST, TYP_VOID, shift, tstCns); + bitTest->gtFlags |= GTF_SET_FLAGS; + GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, GenCondition::EQ); + LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, shift, tstCns, bitTest); + LIR::AsRange(bbSwitch).InsertAfter(bitTest, jcc); + } return true; -#endif // TARGET_XARCH } void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgOrBitcast) From 9e41c621883327e02b9c03a6ee5c0bbbfbdec49a Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 8 Sep 2023 20:35:54 +0200 Subject: [PATCH 2/5] Code format --- src/coreclr/jit/lower.cpp | 51 ++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 8abf281a63304e..09c3370bf6af02 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1219,7 +1219,7 @@ bool Lowering::TryLowerSwitchToBitTest( return false; } -#ifdef TARGET_64BIT +#if defined(TARGET_64BIT) && defined(TARGET_XARCH) // // See if we can avoid a 8 byte immediate on 64 bit targets. If all upper 32 bits are 1 // then inverting the bit table will make them 0 so that the table now fits in 32 bits. @@ -1233,10 +1233,6 @@ bool Lowering::TryLowerSwitchToBitTest( bitTable = ~bitTable; std::swap(bbCase0, bbCase1); } - - const bool useBt = true; -#else - const bool useBt = false; #endif // @@ -1273,31 +1269,26 @@ bool Lowering::TryLowerSwitchToBitTest( var_types bitTableType = (bitCount <= (genTypeSize(TYP_INT) * 8)) ? TYP_INT : TYP_LONG; GenTree* bitTableIcon = comp->gtNewIconNode(bitTable, bitTableType); - if (useBt) - { - // - // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. - // - var_types bitTableType = (bitCount <= (genTypeSize(TYP_INT) * 8)) ? TYP_INT : TYP_LONG; - GenTree* bitTableIcon = comp->gtNewIconNode(bitTable, bitTableType); - GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); - bitTest->gtFlags |= GTF_SET_FLAGS; - GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); - LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); - } - else - { - // - // Fallback to AND(RSZ(bitTable, switchValue), 1) - // - GenTree* tstCns = comp->gtNewIconNode(bbSwitch->bbNext == bbCase0 ? 0 : 1, bitTableType); - GenTree* shift = comp->gtNewOperNode(GT_RSZ, bitTableType, bitTableIcon, switchValue); - GenTree* bitTest = comp->gtNewOperNode(GT_TEST, TYP_VOID, shift, tstCns); - bitTest->gtFlags |= GTF_SET_FLAGS; - GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, GenCondition::EQ); - LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, shift, tstCns, bitTest); - LIR::AsRange(bbSwitch).InsertAfter(bitTest, jcc); - } +#ifdef TARGET_XARCH + // + // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. + // + GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); + bitTest->gtFlags |= GTF_SET_FLAGS; + GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); + LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); +#else // TARGET_XARCH + // + // Fallback to AND(RSZ(bitTable, switchValue), 1) + // + GenTree* tstCns = comp->gtNewIconNode(bbSwitch->bbNext == bbCase0 ? 0 : 1, bitTableType); + GenTree* shift = comp->gtNewOperNode(GT_RSZ, bitTableType, bitTableIcon, switchValue); + GenTree* bitTest = comp->gtNewOperNode(GT_TEST, TYP_VOID, shift, tstCns); + bitTest->gtFlags |= GTF_SET_FLAGS; + GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, GenCondition::EQ); + LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, shift, tstCns, bitTest); + LIR::AsRange(bbSwitch).InsertAfter(bitTest, jcc); +#endif // !TARGET_XARCH return true; } From 5aa7025e6ceb0ebbbf44cf529165440494eea9fb Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 8 Sep 2023 21:10:01 +0200 Subject: [PATCH 3/5] Fix build on arm32 --- src/coreclr/jit/lower.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 09c3370bf6af02..36bb5e95980b0b 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1150,6 +1150,10 @@ GenTree* Lowering::LowerSwitch(GenTree* node) bool Lowering::TryLowerSwitchToBitTest( BasicBlock* jumpTable[], unsigned jumpCount, unsigned targetCount, BasicBlock* bbSwitch, GenTree* switchValue) { +#if !defined(TARGET_XARCH) && !defined(TARGET_ARM64) + // Other architectures may use this if they support either GT_BT or GT_TEST + return false; +#else assert(jumpCount >= 2); assert(targetCount >= 2); assert(bbSwitch->bbJumpKind == BBJ_SWITCH); @@ -1291,6 +1295,7 @@ bool Lowering::TryLowerSwitchToBitTest( #endif // !TARGET_XARCH return true; +#endif // !TARGET_XARCH && !TARGET_ARM64 } void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgOrBitcast) From b062f63e9bf97fd7de9adeb4f14ec5659c8a1042 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 9 Sep 2023 01:22:54 +0200 Subject: [PATCH 4/5] test --- src/coreclr/jit/lower.cpp | 41 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 36bb5e95980b0b..e73f17b72aaba9 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1273,26 +1273,33 @@ bool Lowering::TryLowerSwitchToBitTest( var_types bitTableType = (bitCount <= (genTypeSize(TYP_INT) * 8)) ? TYP_INT : TYP_LONG; GenTree* bitTableIcon = comp->gtNewIconNode(bitTable, bitTableType); -#ifdef TARGET_XARCH - // - // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. - // - GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); - bitTest->gtFlags |= GTF_SET_FLAGS; - GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); - LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); -#else // TARGET_XARCH + //#ifdef TARGET_XARCH + // // + // // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. + // // + // GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); + // bitTest->gtFlags |= GTF_SET_FLAGS; + // GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); + // LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); + //#else // TARGET_XARCH // // Fallback to AND(RSZ(bitTable, switchValue), 1) // - GenTree* tstCns = comp->gtNewIconNode(bbSwitch->bbNext == bbCase0 ? 0 : 1, bitTableType); - GenTree* shift = comp->gtNewOperNode(GT_RSZ, bitTableType, bitTableIcon, switchValue); - GenTree* bitTest = comp->gtNewOperNode(GT_TEST, TYP_VOID, shift, tstCns); - bitTest->gtFlags |= GTF_SET_FLAGS; - GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, GenCondition::EQ); - LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, shift, tstCns, bitTest); - LIR::AsRange(bbSwitch).InsertAfter(bitTest, jcc); -#endif // !TARGET_XARCH + GenTree* tstCns = comp->gtNewIconNode(bbSwitch->bbNext != bbCase0 ? 0 : 1, bitTableType); + GenTree* shift = comp->gtNewOperNode(GT_RSZ, bitTableType, bitTableIcon, switchValue); + GenTree* one = comp->gtNewIconNode(1, bitTableType); + GenTree* andOp = comp->gtNewOperNode(GT_AND, bitTableType, shift, one); + GenTree* cmp = comp->gtNewOperNode(GT_EQ, TYP_INT, andOp, tstCns); + GenTree* jcc = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, cmp); + + LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, shift, tstCns, one); + LIR::AsRange(bbSwitch).InsertAfter(one, andOp, cmp, jcc); + + LowerNode(andOp); + LowerNode(cmp); + LowerNode(jcc); + + //#endif // !TARGET_XARCH return true; #endif // !TARGET_XARCH && !TARGET_ARM64 From c125033a885f5616848ecc96a0b6dc383a6dc4b0 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 9 Sep 2023 13:16:06 +0200 Subject: [PATCH 5/5] Clean up --- src/coreclr/jit/lower.cpp | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index e73f17b72aaba9..7983f4aad47e5d 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1150,10 +1150,6 @@ GenTree* Lowering::LowerSwitch(GenTree* node) bool Lowering::TryLowerSwitchToBitTest( BasicBlock* jumpTable[], unsigned jumpCount, unsigned targetCount, BasicBlock* bbSwitch, GenTree* switchValue) { -#if !defined(TARGET_XARCH) && !defined(TARGET_ARM64) - // Other architectures may use this if they support either GT_BT or GT_TEST - return false; -#else assert(jumpCount >= 2); assert(targetCount >= 2); assert(bbSwitch->bbJumpKind == BBJ_SWITCH); @@ -1273,15 +1269,15 @@ bool Lowering::TryLowerSwitchToBitTest( var_types bitTableType = (bitCount <= (genTypeSize(TYP_INT) * 8)) ? TYP_INT : TYP_LONG; GenTree* bitTableIcon = comp->gtNewIconNode(bitTable, bitTableType); - //#ifdef TARGET_XARCH - // // - // // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. - // // - // GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); - // bitTest->gtFlags |= GTF_SET_FLAGS; - // GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); - // LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); - //#else // TARGET_XARCH +#ifdef TARGET_XARCH + // + // Append BT(bitTable, switchValue) and JCC(condition) to the switch block. + // + GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); + bitTest->gtFlags |= GTF_SET_FLAGS; + GenTreeCC* jcc = comp->gtNewCC(GT_JCC, TYP_VOID, bbSwitchCondition); + LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); +#else // TARGET_XARCH // // Fallback to AND(RSZ(bitTable, switchValue), 1) // @@ -1291,18 +1287,10 @@ bool Lowering::TryLowerSwitchToBitTest( GenTree* andOp = comp->gtNewOperNode(GT_AND, bitTableType, shift, one); GenTree* cmp = comp->gtNewOperNode(GT_EQ, TYP_INT, andOp, tstCns); GenTree* jcc = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, cmp); - LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, shift, tstCns, one); LIR::AsRange(bbSwitch).InsertAfter(one, andOp, cmp, jcc); - - LowerNode(andOp); - LowerNode(cmp); - LowerNode(jcc); - - //#endif // !TARGET_XARCH - +#endif // !TARGET_XARCH return true; -#endif // !TARGET_XARCH && !TARGET_ARM64 } void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgOrBitcast)