Reland "[interpreter] Optimize strict equal boolean"
This is a reland of commit 62632c0805
.
Reason for previous revert: Performance regressions crbug.com/1315724.
The reland only optimizes strict equal boolean literal like "a===true"
or "a===false", and we generate TestReferenceEqual rather than
TestStrictEqual for the comparasion. And also add typed optimization
for ReferenceEqual when all inputs are boolean with boolean constant.
Original change's description:
> [interpreter] Optimize strict equal boolean
>
> For strict equal boolean literal like "a===true"
> or "a===false", we could generate TestReferenceEqual
> rather than TestStrictEqual. And in `execution_result()->IsTest()`
> case, we could directly emit JumpIfTrue/JumpIfFalse.
>
> E.g.
> ```
> a === true
> ```
> Generated Bytecode From:
> ```
> LdaGlobal
> Star1
> LdaTrue
> TestEqualStrict
> ```
> To:
> ```
> LdaGlobal
> Star1
> LdaTrue
> TestReferenceEqual
> ```
>
> E.g.
> ```
> if (a === true)
> ```
> Generated Bytecode From:
> ```
> LdaGlobal
> Star1
> LdaTrue
> TestEqualStrict
> JumpIfFalse
> ```
> To
> ```
> LdaGlobal
> JumpIfTrue
> Jump
> ```
>
>
> Bug: v8:6403
> Change-Id: Ieaca147acd2d523ac0d2466e7861afb2d29a1310
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3568923
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: 王澳 <wangao.james@bytedance.com>
> Cr-Commit-Position: refs/heads/main@{#79935}
Bug: v8:6403
Change-Id: I2ae3ab57dce85313af200fa522e3632af5c3a554
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3592039
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Jakob Linke <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80141}
This commit is contained in:
parent
2c4d1b4c0a
commit
fce1047f00
@ -103,6 +103,10 @@ bool Expression::IsNullLiteral() const {
|
||||
return IsLiteral() && AsLiteral()->type() == Literal::kNull;
|
||||
}
|
||||
|
||||
bool Expression::IsBooleanLiteral() const {
|
||||
return IsLiteral() && AsLiteral()->type() == Literal::kBoolean;
|
||||
}
|
||||
|
||||
bool Expression::IsTheHoleLiteral() const {
|
||||
return IsLiteral() && AsLiteral()->type() == Literal::kTheHole;
|
||||
}
|
||||
@ -892,6 +896,24 @@ static bool IsVoidOfLiteral(Expression* expr) {
|
||||
maybe_unary->expression()->IsLiteral();
|
||||
}
|
||||
|
||||
static bool MatchLiteralStrictCompareBoolean(Expression* left, Token::Value op,
|
||||
Expression* right,
|
||||
Expression** expr,
|
||||
Literal** literal) {
|
||||
if (left->IsBooleanLiteral() && op == Token::EQ_STRICT) {
|
||||
*expr = right;
|
||||
*literal = left->AsLiteral();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompareOperation::IsLiteralStrictCompareBoolean(Expression** expr,
|
||||
Literal** literal) {
|
||||
return MatchLiteralStrictCompareBoolean(left_, op(), right_, expr, literal) ||
|
||||
MatchLiteralStrictCompareBoolean(right_, op(), left_, expr, literal);
|
||||
}
|
||||
|
||||
// Check for the pattern: void <literal> equals <expression> or
|
||||
// undefined equals <expression>
|
||||
static bool MatchLiteralCompareUndefined(Expression* left, Token::Value op,
|
||||
|
@ -236,6 +236,8 @@ class Expression : public AstNode {
|
||||
// True iff the expression is the null literal.
|
||||
bool IsNullLiteral() const;
|
||||
|
||||
bool IsBooleanLiteral() const;
|
||||
|
||||
// True iff the expression is the hole literal.
|
||||
bool IsTheHoleLiteral() const;
|
||||
|
||||
@ -955,6 +957,11 @@ class Literal final : public Expression {
|
||||
return Smi::FromInt(smi_);
|
||||
}
|
||||
|
||||
bool AsBooleanLiteral() const {
|
||||
DCHECK_EQ(kBoolean, type());
|
||||
return boolean_;
|
||||
}
|
||||
|
||||
// Returns true if literal represents a Number.
|
||||
bool IsNumber() const { return type() == kHeapNumber || type() == kSmi; }
|
||||
double AsNumber() const {
|
||||
@ -1963,6 +1970,7 @@ class CompareOperation final : public Expression {
|
||||
|
||||
// Match special cases.
|
||||
bool IsLiteralCompareTypeof(Expression** expr, Literal** literal);
|
||||
bool IsLiteralStrictCompareBoolean(Expression** expr, Literal** literal);
|
||||
bool IsLiteralCompareUndefined(Expression** expr);
|
||||
bool IsLiteralCompareNull(Expression** expr);
|
||||
|
||||
|
@ -410,6 +410,20 @@ Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
|
||||
return Replace(jsgraph()->FalseConstant());
|
||||
}
|
||||
}
|
||||
if (rhs_type.Is(Type::Boolean()) && rhs_type.IsHeapConstant() &&
|
||||
lhs_type.Is(Type::Boolean())) {
|
||||
base::Optional<bool> maybe_result =
|
||||
rhs_type.AsHeapConstant()->Ref().TryGetBooleanValue();
|
||||
if (maybe_result.has_value()) {
|
||||
if (maybe_result.value()) {
|
||||
return Replace(node->InputAt(0));
|
||||
} else {
|
||||
node->TrimInputCount(1);
|
||||
NodeProperties::ChangeOp(node, simplified()->BooleanNot());
|
||||
return Changed(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
@ -6162,6 +6162,14 @@ void BytecodeGenerator::BuildLiteralCompareNil(
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeGenerator::BuildLiteralStrictCompareBoolean(Literal* literal) {
|
||||
DCHECK(literal->IsBooleanLiteral());
|
||||
Register result = register_allocator()->NewRegister();
|
||||
builder()->StoreAccumulatorInRegister(result);
|
||||
builder()->LoadBoolean(literal->AsBooleanLiteral());
|
||||
builder()->CompareReference(result);
|
||||
}
|
||||
|
||||
void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
||||
Expression* sub_expr;
|
||||
Literal* literal;
|
||||
@ -6177,6 +6185,11 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
||||
} else {
|
||||
builder()->CompareTypeOf(literal_flag);
|
||||
}
|
||||
} else if (expr->IsLiteralStrictCompareBoolean(&sub_expr, &literal)) {
|
||||
DCHECK(expr->op() == Token::EQ_STRICT);
|
||||
VisitForAccumulatorValue(sub_expr);
|
||||
builder()->SetExpressionPosition(expr);
|
||||
BuildLiteralStrictCompareBoolean(literal);
|
||||
} else if (expr->IsLiteralCompareUndefined(&sub_expr)) {
|
||||
VisitForAccumulatorValue(sub_expr);
|
||||
builder()->SetExpressionPosition(expr);
|
||||
|
@ -263,6 +263,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
|
||||
LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal);
|
||||
void BuildLiteralCompareNil(Token::Value compare_op,
|
||||
BytecodeArrayBuilder::NilValue nil);
|
||||
void BuildLiteralStrictCompareBoolean(Literal* literal);
|
||||
void BuildReturn(int source_position);
|
||||
void BuildAsyncReturn(int source_position);
|
||||
void BuildAsyncGeneratorReturn();
|
||||
|
@ -0,0 +1,400 @@
|
||||
#
|
||||
# Autogenerated by generate-bytecode-expectations.
|
||||
#
|
||||
|
||||
---
|
||||
wrap: yes
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = 1;
|
||||
return a === true;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 7
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaSmi), I8(1),
|
||||
B(Star0),
|
||||
/* 45 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
/* 63 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = true;
|
||||
return true === a;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 6
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaTrue),
|
||||
B(Star0),
|
||||
/* 48 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
/* 66 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = false;
|
||||
return true !== a;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 7
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaFalse),
|
||||
B(Star0),
|
||||
/* 49 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
/* 61 E> */ B(LogicalNot),
|
||||
/* 67 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = 1;
|
||||
return true === a ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 15
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaSmi), I8(1),
|
||||
B(Star0),
|
||||
/* 45 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
/* 71 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = true;
|
||||
return false === a ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 14
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaTrue),
|
||||
B(Star0),
|
||||
/* 48 S> */ B(LdaFalse),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
/* 75 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = 1;
|
||||
return true !== a ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 15
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaSmi), I8(1),
|
||||
B(Star0),
|
||||
/* 45 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
/* 71 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = false;
|
||||
return false !== null ? 1 : 2;
|
||||
"
|
||||
frame size: 2
|
||||
parameter count: 1
|
||||
bytecode array length: 16
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaFalse),
|
||||
B(Star0),
|
||||
/* 49 S> */ B(LdaNull),
|
||||
B(Star1),
|
||||
B(LdaFalse),
|
||||
B(TestReferenceEqual), R(1),
|
||||
B(JumpIfTrue), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
/* 79 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = 0;
|
||||
if (a !== true) {
|
||||
return 1;
|
||||
}
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 12
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaZero),
|
||||
B(Star0),
|
||||
/* 45 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(5),
|
||||
/* 65 S> */ B(LdaSmi), I8(1),
|
||||
/* 74 S> */ B(Return),
|
||||
B(LdaUndefined),
|
||||
/* 77 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
var a = true;
|
||||
var b = 0;
|
||||
while (a !== true) {
|
||||
b++;
|
||||
}
|
||||
"
|
||||
frame size: 2
|
||||
parameter count: 1
|
||||
bytecode array length: 20
|
||||
bytecodes: [
|
||||
/* 42 S> */ B(LdaTrue),
|
||||
B(Star0),
|
||||
/* 56 S> */ B(LdaZero),
|
||||
B(Star1),
|
||||
/* 68 S> */ B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(11),
|
||||
/* 82 S> */ B(Ldar), R(1),
|
||||
B(Inc), U8(0),
|
||||
B(Star1),
|
||||
/* 59 E> */ B(JumpLoop), U8(10), I8(0), U8(1),
|
||||
B(LdaUndefined),
|
||||
/* 89 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
(0 === true) ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 15
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
B(LdaUndefined),
|
||||
/* 56 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
(0 !== true) ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 15
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
B(LdaUndefined),
|
||||
/* 56 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
(false === 0) ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 15
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaFalse),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
B(LdaUndefined),
|
||||
/* 57 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
(0 === true || 0 === false) ? 1 : 2;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 22
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(9),
|
||||
B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaFalse),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(6),
|
||||
B(LdaSmi), I8(1),
|
||||
B(Jump), U8(4),
|
||||
B(LdaSmi), I8(2),
|
||||
B(LdaUndefined),
|
||||
/* 71 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
if (0 === true || 0 === false) return 1;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 19
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaTrue),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(9),
|
||||
B(LdaZero),
|
||||
B(Star0),
|
||||
B(LdaFalse),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(5),
|
||||
/* 65 S> */ B(LdaSmi), I8(1),
|
||||
/* 74 S> */ B(Return),
|
||||
B(LdaUndefined),
|
||||
/* 75 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
if (!('false' === false)) return 1;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 13
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaConstant), U8(0),
|
||||
B(Star0),
|
||||
B(LdaFalse),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfTrue), U8(5),
|
||||
/* 60 S> */ B(LdaSmi), I8(1),
|
||||
/* 69 S> */ B(Return),
|
||||
B(LdaUndefined),
|
||||
/* 70 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["false"],
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
if (!('false' !== false)) return 1;
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 13
|
||||
bytecodes: [
|
||||
/* 34 S> */ B(LdaConstant), U8(0),
|
||||
B(Star0),
|
||||
B(LdaFalse),
|
||||
B(TestReferenceEqual), R(0),
|
||||
B(JumpIfFalse), U8(5),
|
||||
/* 60 S> */ B(LdaSmi), I8(1),
|
||||
/* 69 S> */ B(Return),
|
||||
B(LdaUndefined),
|
||||
/* 70 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["false"],
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
@ -1161,6 +1161,62 @@ TEST(CompareTypeOf) {
|
||||
LoadGolden("CompareTypeOf.golden")));
|
||||
}
|
||||
|
||||
TEST(CompareBoolean) {
|
||||
InitializedIgnitionHandleScope scope;
|
||||
BytecodeExpectationsPrinter printer(CcTest::isolate());
|
||||
|
||||
std::string snippets[] = {
|
||||
"var a = 1;\n"
|
||||
"return a === true;\n",
|
||||
|
||||
"var a = true;\n"
|
||||
"return true === a;\n",
|
||||
|
||||
"var a = false;\n"
|
||||
"return true !== a;\n",
|
||||
|
||||
"var a = 1;\n"
|
||||
"return true === a ? 1 : 2;\n",
|
||||
|
||||
"var a = true;\n"
|
||||
"return false === a ? 1 : 2;\n",
|
||||
|
||||
"var a = 1;\n"
|
||||
"return true !== a ? 1 : 2;\n",
|
||||
|
||||
"var a = false;\n"
|
||||
"return false !== null ? 1 : 2;\n",
|
||||
|
||||
"var a = 0;\n"
|
||||
"if (a !== true) {\n"
|
||||
" return 1;\n"
|
||||
"}\n",
|
||||
|
||||
"var a = true;\n"
|
||||
"var b = 0;\n"
|
||||
"while (a !== true) {\n"
|
||||
" b++;\n"
|
||||
"}\n",
|
||||
|
||||
"(0 === true) ? 1 : 2;\n",
|
||||
|
||||
"(0 !== true) ? 1 : 2;\n",
|
||||
|
||||
"(false === 0) ? 1 : 2;\n",
|
||||
|
||||
"(0 === true || 0 === false) ? 1 : 2;\n",
|
||||
|
||||
"if (0 === true || 0 === false) return 1;\n",
|
||||
|
||||
"if (!('false' === false)) return 1;\n",
|
||||
|
||||
"if (!('false' !== false)) return 1;\n",
|
||||
};
|
||||
|
||||
CHECK(CompareTexts(BuildActual(printer, snippets),
|
||||
LoadGolden("CompareBoolean.golden")));
|
||||
}
|
||||
|
||||
TEST(CompareNil) {
|
||||
InitializedIgnitionHandleScope scope;
|
||||
BytecodeExpectationsPrinter printer(CcTest::isolate());
|
||||
|
@ -16,6 +16,7 @@ addBenchmark('Number-StrictEquals-False', NumberStrictEqualsFalse);
|
||||
addBenchmark('String-StrictEquals-True', StringStrictEqualsTrue);
|
||||
addBenchmark('String-StrictEquals-False', StringStrictEqualsFalse);
|
||||
addBenchmark('SmiString-StrictEquals', MixedStrictEquals);
|
||||
addBenchmark('Boolean-StrictEquals', BooleanStrictEquals);
|
||||
addBenchmark('Smi-Equals-True', SmiEqualsTrue);
|
||||
addBenchmark('Smi-Equals-False', SmiEqualsFalse);
|
||||
addBenchmark('Number-Equals-True', NumberEqualsTrue);
|
||||
@ -46,6 +47,113 @@ function strictEquals(a, b) {
|
||||
}
|
||||
}
|
||||
|
||||
function strictEqualsBoolean(a) {
|
||||
var ret;
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === true) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
if (a === false) ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function equals(a, b) {
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
a == b; a == b; a == b; a == b; a == b; a == b; a == b; a == b; a == b; a == b;
|
||||
@ -104,6 +212,12 @@ function StringStrictEqualsTrue() {
|
||||
strictEquals("abc", "abc");
|
||||
}
|
||||
|
||||
function BooleanStrictEquals() {
|
||||
strictEqualsBoolean("a");
|
||||
strictEqualsBoolean(true);
|
||||
strictEqualsBoolean(false);
|
||||
}
|
||||
|
||||
function MixedStrictEquals() {
|
||||
strictEquals(10, "10");
|
||||
}
|
||||
|
@ -318,6 +318,7 @@
|
||||
{"name": "String-StrictEquals-True"},
|
||||
{"name": "String-StrictEquals-False"},
|
||||
{"name": "SmiString-StrictEquals"},
|
||||
{"name": "Boolean-StrictEquals"},
|
||||
{"name": "Smi-Equals-True"},
|
||||
{"name": "Smi-Equals-False"},
|
||||
{"name": "Number-Equals-True"},
|
||||
|
20
test/mjsunit/compiler/reference-equal-boolean.js
Normal file
20
test/mjsunit/compiler/reference-equal-boolean.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
// Ensure we could reduce reference equal with boolean input.
|
||||
// When the inputs are all boolean with true constant, we could
|
||||
// reduce to the input. And when the inputs are all boolean with
|
||||
// false constant, we could reduce to the input with BooleanNot.
|
||||
function foo(x, y) {
|
||||
const v = (x === y);
|
||||
%TurbofanStaticAssert(((v === true) === v));
|
||||
%TurbofanStaticAssert((!(v === false) === v));
|
||||
};
|
||||
%PrepareFunctionForOptimization(foo);
|
||||
foo(1, 2);
|
||||
foo(2, 3);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(3, 4);
|
@ -103,6 +103,26 @@ TEST_F(TypedOptimizationTest, ToBooleanWithAny) {
|
||||
ASSERT_FALSE(r.Changed());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ReferenceEqual
|
||||
TEST_F(TypedOptimizationTest, ReferenceEqualWithBooleanTrueConstant) {
|
||||
Node* left = Parameter(Type::Boolean(), 0);
|
||||
Node* right = TrueConstant();
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(simplified()->ReferenceEqual(), left, right));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), left);
|
||||
}
|
||||
|
||||
TEST_F(TypedOptimizationTest, ReferenceEqualWithBooleanFalseConstant) {
|
||||
Node* left = Parameter(Type::Boolean(), 0);
|
||||
Node* right = FalseConstant();
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(simplified()->ReferenceEqual(), left, right));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsBooleanNot(left));
|
||||
}
|
||||
|
||||
} // namespace typed_optimization_unittest
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
|
Loading…
Reference in New Issue
Block a user