From 7112fe658d21efd0b52efc262bd685a1dd67a34b Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Fri, 28 Oct 2022 22:22:04 +0800 Subject: [PATCH] [turbofan][turboshaft] Improve the reduction of UintNLessThanOrEqual Add "x <= 0 => x == 0" reduction when "x" is uint. This allows x64 to select shorter instructions: Before: REX.W cmpq r9,0x0 jna addr After: REX.W testq r9,r9 jz addr This optimization is also ported to turboshaft. Bug: v8:12783 Change-Id: I87dfd5879c047bb57d30e7a51a309106e3a519ae Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3967480 Reviewed-by: Tobias Tebbi Commit-Queue: Hao A Xu Cr-Commit-Position: refs/heads/main@{#83994} --- src/compiler/machine-operator-reducer.cc | 54 +++++++++++++------ src/compiler/machine-operator-reducer.h | 2 + .../turboshaft/machine-optimization-reducer.h | 4 ++ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc index 9436303ade..7514f724ce 100644 --- a/src/compiler/machine-operator-reducer.cc +++ b/src/compiler/machine-operator-reducer.cc @@ -34,6 +34,7 @@ class Word32Adapter { using IntNBinopMatcher = Int32BinopMatcher; using UintNBinopMatcher = Uint32BinopMatcher; using intN_t = int32_t; + using uintN_t = uint32_t; // WORD_SIZE refers to the N for which this adapter specializes. static constexpr std::size_t WORD_SIZE = 32; @@ -75,6 +76,9 @@ class Word32Adapter { const Operator* IntNAdd(MachineOperatorBuilder* machine) { return machine->Int32Add(); } + static const Operator* WordNEqual(MachineOperatorBuilder* machine) { + return machine->Word32Equal(); + } Reduction ReplaceIntN(int32_t value) { return r_->ReplaceInt32(value); } Reduction ReduceWordNAnd(Node* node) { return r_->ReduceWord32And(node); } @@ -85,6 +89,10 @@ class Word32Adapter { Node* UintNConstant(uint32_t value) { return r_->Uint32Constant(value); } Node* WordNAnd(Node* lhs, Node* rhs) { return r_->Word32And(lhs, rhs); } + Reduction ReduceWordNComparisons(Node* node) { + return r_->ReduceWord32Comparisons(node); + } + private: MachineOperatorReducer* r_; }; @@ -98,6 +106,7 @@ class Word64Adapter { using IntNBinopMatcher = Int64BinopMatcher; using UintNBinopMatcher = Uint64BinopMatcher; using intN_t = int64_t; + using uintN_t = uint64_t; // WORD_SIZE refers to the N for which this adapter specializes. static constexpr std::size_t WORD_SIZE = 64; @@ -139,6 +148,9 @@ class Word64Adapter { static const Operator* IntNAdd(MachineOperatorBuilder* machine) { return machine->Int64Add(); } + static const Operator* WordNEqual(MachineOperatorBuilder* machine) { + return machine->Word64Equal(); + } Reduction ReplaceIntN(int64_t value) { return r_->ReplaceInt64(value); } Reduction ReduceWordNAnd(Node* node) { return r_->ReduceWord64And(node); } @@ -152,6 +164,10 @@ class Word64Adapter { Node* UintNConstant(uint64_t value) { return r_->Uint64Constant(value); } Node* WordNAnd(Node* lhs, Node* rhs) { return r_->Word64And(lhs, rhs); } + Reduction ReduceWordNComparisons(Node* node) { + return r_->ReduceWord64Comparisons(node); + } + private: MachineOperatorReducer* r_; }; @@ -457,15 +473,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { return ReduceWord32Comparisons(node); } case IrOpcode::kUint32LessThanOrEqual: { - Uint32BinopMatcher m(node); - if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true - if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true - if (m.IsFoldable()) { // K <= K => K (K stands for arbitrary constants) - return ReplaceBool(m.left().ResolvedValue() <= - m.right().ResolvedValue()); - } - if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true - return ReduceWord32Comparisons(node); + return ReduceUintNLessThanOrEqual(node); } case IrOpcode::kFloat32Sub: { Float32BinopMatcher m(node); @@ -915,12 +923,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { return ReduceWord64Comparisons(node); } case IrOpcode::kUint64LessThanOrEqual: { - Uint64BinopMatcher m(node); - if (m.IsFoldable()) { // K <= K => K (K stands for arbitrary constants) - return ReplaceBool(m.left().ResolvedValue() <= - m.right().ResolvedValue()); - } - return ReduceWord64Comparisons(node); + return ReduceUintNLessThanOrEqual(node); } case IrOpcode::kFloat32Select: case IrOpcode::kFloat64Select: @@ -1858,6 +1861,27 @@ Reduction MachineOperatorReducer::ReduceWordNAnd(Node* node) { return NoChange(); } +template +Reduction MachineOperatorReducer::ReduceUintNLessThanOrEqual(Node* node) { + using A = WordNAdapter; + A a(this); + + typename A::UintNBinopMatcher m(node); + typename A::uintN_t kMaxUIntN = + std::numeric_limits::max(); + if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true + if (m.right().Is(kMaxUIntN)) return ReplaceBool(true); // x <= M => true + if (m.IsFoldable()) { // K <= K => K (K stands for arbitrary constants) + return ReplaceBool(m.left().ResolvedValue() <= m.right().ResolvedValue()); + } + if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true + if (m.right().Is(0)) { // x <= 0 => x == 0 + NodeProperties::ChangeOp(node, a.WordNEqual(machine())); + return Changed(node); + } + return a.ReduceWordNComparisons(node); +} + namespace { // Represents an operation of the form `(source & mask) == masked_value`. diff --git a/src/compiler/machine-operator-reducer.h b/src/compiler/machine-operator-reducer.h index 606d01017e..7c4dc85b59 100644 --- a/src/compiler/machine-operator-reducer.h +++ b/src/compiler/machine-operator-reducer.h @@ -134,6 +134,8 @@ class V8_EXPORT_PRIVATE MachineOperatorReducer final Reduction ReduceWordNOr(Node* node); template Reduction ReduceWordNXor(Node* node); + template + Reduction ReduceUintNLessThanOrEqual(Node* node); // Tries to simplify "if(x == 0)" by removing the "== 0" and inverting // branches. diff --git a/src/compiler/turboshaft/machine-optimization-reducer.h b/src/compiler/turboshaft/machine-optimization-reducer.h index 735159aebb..222664a3bf 100644 --- a/src/compiler/turboshaft/machine-optimization-reducer.h +++ b/src/compiler/turboshaft/machine-optimization-reducer.h @@ -1270,6 +1270,10 @@ class MachineOptimizationReducer : public Next { k == rep.MaxUnsignedValue()) { return Asm().Word32Constant(1); } + // x <= 0 => x == 0 + if (uint64_t k; Asm().MatchWordConstant(right, rep_w, &k) && k == 0) { + return Asm().Equal(left, Asm().WordConstant(0, rep_w), rep_w); + } } if (kind == Kind::kUnsignedLessThan) { // x < 0 => false