mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
Distribute equality checks if that allows simplification (#2174)
Summary: Release note: More simplification of equality expressions Resolves issue: #2172 Expressions like (c ? x : y) === null can sometimes be simplified by first rewriting them as (c ? x === null : y === null). Add such a case to the simplifier. Closes https://github.com/facebook/prepack/pull/2174 Differential Revision: D8666251 Pulled By: hermanventer fbshipit-source-id: 5b0d56fb091e25bfcdf879be3403cb5a982375ae
This commit is contained in:
parent
30f07ead22
commit
fa4b52f573
@ -16,6 +16,7 @@ import invariant from "../invariant.js";
|
||||
import { Realm } from "../realm.js";
|
||||
import { AbstractValue, BooleanValue, ConcreteValue, Value } from "../values/index.js";
|
||||
import { Path, To } from "../singletons.js";
|
||||
import EmptyValue from "../values/EmptyValue";
|
||||
|
||||
export default function simplifyAndRefineAbstractValue(
|
||||
realm: Realm,
|
||||
@ -257,24 +258,42 @@ function simplifyEquality(realm: Realm, equality: AbstractValue): Value {
|
||||
let loc = equality.expressionLocation;
|
||||
let op = equality.kind;
|
||||
let [x, y] = equality.args;
|
||||
if (y instanceof EmptyValue) return equality;
|
||||
if (x instanceof ConcreteValue) [x, y] = [y, x];
|
||||
if (x instanceof AbstractValue && x.kind === "conditional" && (!y.mightNotBeUndefined() || !y.mightNotBeNull())) {
|
||||
function simplified(v: Value) {
|
||||
return v instanceof AbstractValue ? v.kind !== op : true;
|
||||
}
|
||||
// try to simplify "(cond ? xx : xy) op undefined/null" to just "cond" or "!cond"
|
||||
let [cond, xx, xy] = x.args;
|
||||
invariant(cond instanceof AbstractValue); // otherwise the the conditional should not have been created
|
||||
if (op === "===" || op === "!==") {
|
||||
// if xx === undefined && xy !== undefined then cond <=> x === undefined
|
||||
if (!y.mightNotBeUndefined() && !xx.mightNotBeUndefined() && !xy.mightBeUndefined())
|
||||
return op === "===" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
|
||||
// if xx !== undefined && xy === undefined then !cond <=> x === undefined
|
||||
if (!y.mightNotBeUndefined() && !xx.mightBeUndefined() && !xy.mightNotBeUndefined())
|
||||
return op === "===" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
|
||||
// if xx === null && xy !== null then cond <=> x === null
|
||||
if (!y.mightNotBeNull() && !xx.mightNotBeNull() && !xy.mightBeNull())
|
||||
return op === "===" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
|
||||
// if xx !== null && xy === null then !cond <=> x === null
|
||||
if (!y.mightNotBeNull() && !xx.mightBeNull() && !xy.mightNotBeNull())
|
||||
return op === "===" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
|
||||
if (!y.mightNotBeUndefined()) {
|
||||
// if xx === undefined && xy !== undefined then cond <=> x === undefined
|
||||
if (!xx.mightNotBeUndefined() && !xy.mightBeUndefined())
|
||||
return op === "===" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
|
||||
// if xx !== undefined && xy === undefined then !cond <=> x === undefined
|
||||
if (!xx.mightBeUndefined() && !xy.mightNotBeUndefined())
|
||||
return op === "===" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
|
||||
// distribute equality test, creating more simplication opportunities
|
||||
let sxx = AbstractValue.createFromBinaryOp(realm, op, xx, realm.intrinsics.undefined, xx.expressionLocation);
|
||||
let sxy = AbstractValue.createFromBinaryOp(realm, op, xy, realm.intrinsics.undefined, xy.expressionLocation);
|
||||
if (simplified(sxx) || simplified(sxy))
|
||||
return AbstractValue.createFromConditionalOp(realm, cond, sxx, sxy, equality.expressionLocation, true);
|
||||
}
|
||||
if (!y.mightNotBeNull()) {
|
||||
// if xx === null && xy !== null then cond <=> x === null
|
||||
if (!xx.mightNotBeNull() && !xy.mightBeNull())
|
||||
return op === "===" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
|
||||
// if xx !== null && xy === null then !cond <=> x === null
|
||||
if (!xx.mightBeNull() && !xy.mightNotBeNull())
|
||||
return op === "===" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
|
||||
// distribute equality test, creating more simplication opportunities
|
||||
let sxx = AbstractValue.createFromBinaryOp(realm, op, xx, realm.intrinsics.null, xx.expressionLocation);
|
||||
let sxy = AbstractValue.createFromBinaryOp(realm, op, xy, realm.intrinsics.null, xy.expressionLocation);
|
||||
if (simplified(sxx) || simplified(sxy))
|
||||
return AbstractValue.createFromConditionalOp(realm, cond, sxx, sxy, equality.expressionLocation, true);
|
||||
}
|
||||
} else {
|
||||
invariant(op === "==" || op === "!=");
|
||||
// if xx cannot be undefined/null and xy is undefined/null then !cond <=> x == undefined/null
|
||||
@ -283,6 +302,11 @@ function simplifyEquality(realm: Realm, equality: AbstractValue): Value {
|
||||
// if xx is undefined/null and xy cannot be undefined/null then cond <=> x == undefined/null
|
||||
if ((!xx.mightNotBeUndefined() || !xx.mightNotBeNull()) && !xy.mightBeUndefined() && !xy.mightBeNull())
|
||||
return op === "==" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
|
||||
// distribute equality test, creating more simplication opportunities
|
||||
let sxx = AbstractValue.createFromBinaryOp(realm, op, xx, y, xx.expressionLocation);
|
||||
let sxy = AbstractValue.createFromBinaryOp(realm, op, xy, y, xy.expressionLocation);
|
||||
if (simplified(sxx) || simplified(sxy))
|
||||
return AbstractValue.createFromConditionalOp(realm, cond, sxx, sxy, equality.expressionLocation, true);
|
||||
}
|
||||
}
|
||||
return equality;
|
||||
|
16
test/serializer/optimizations/simplify12.js
Normal file
16
test/serializer/optimizations/simplify12.js
Normal file
@ -0,0 +1,16 @@
|
||||
// does not contain:{}
|
||||
let x = global.__abstract ? __abstract("boolean", "(1 === 1)") : true;
|
||||
let y = global.__abstract ? __abstract("boolean", "(2 === 2)") : true;
|
||||
let a = x ? null : {};
|
||||
let b = y ? null : a;
|
||||
var c = b === null;
|
||||
let a1 = x ? undefined : {};
|
||||
let b1 = y ? undefined : a1;
|
||||
var c1 = b1 === undefined;
|
||||
let a2 = x ? undefined : {};
|
||||
let b2 = y ? null : a2;
|
||||
var c2 = b2 == undefined;
|
||||
var c3 = b2 == null;
|
||||
|
||||
|
||||
inspect = function() { return [c, c1, c2, c3].join(" "); }
|
Loading…
Reference in New Issue
Block a user