[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 <tebbi@chromium.org>
Commit-Queue: Hao A Xu <hao.a.xu@intel.com>
Cr-Commit-Position: refs/heads/main@{#83994}
This commit is contained in:
Hao Xu 2022-10-28 22:22:04 +08:00 committed by V8 LUCI CQ
parent fbd4541fe7
commit 7112fe658d
3 changed files with 45 additions and 15 deletions

View File

@ -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<Word32Adapter>(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<Word64Adapter>(node);
}
case IrOpcode::kFloat32Select:
case IrOpcode::kFloat64Select:
@ -1858,6 +1861,27 @@ Reduction MachineOperatorReducer::ReduceWordNAnd(Node* node) {
return NoChange();
}
template <typename WordNAdapter>
Reduction MachineOperatorReducer::ReduceUintNLessThanOrEqual(Node* node) {
using A = WordNAdapter;
A a(this);
typename A::UintNBinopMatcher m(node);
typename A::uintN_t kMaxUIntN =
std::numeric_limits<typename A::uintN_t>::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`.

View File

@ -134,6 +134,8 @@ class V8_EXPORT_PRIVATE MachineOperatorReducer final
Reduction ReduceWordNOr(Node* node);
template <typename WordNAdapter>
Reduction ReduceWordNXor(Node* node);
template <typename WordNAdapter>
Reduction ReduceUintNLessThanOrEqual(Node* node);
// Tries to simplify "if(x == 0)" by removing the "== 0" and inverting
// branches.

View File

@ -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