wary booleans

This commit is contained in:
2026-02-21 20:42:17 -06:00
parent 8f415fea80
commit 8e96379377
9 changed files with 34034 additions and 36303 deletions

View File

@@ -69,12 +69,19 @@ var streamline = function(ir, log) {
var no_clear_ops = {
int: true, access: true, true: true, false: true, move: true, null: true,
jump: true, jump_true: true, jump_false: true, jump_not_null: true,
wary_true: true, wary_false: true, jump_null: true, jump_empty: true,
return: true, disrupt: true,
store_field: true, store_index: true, store_dynamic: true,
push: true, setarg: true, invoke: true, tail_invoke: true,
stone_text: true
}
var is_cond_jump = function(op) {
return op == "jump_true" || op == "jump_false" || op == "jump_not_null"
|| op == "wary_true" || op == "wary_false"
|| op == "jump_null" || op == "jump_empty"
}
// --- Logging support ---
var ir_stats = null
@@ -376,7 +383,12 @@ var streamline = function(ir, log) {
abs: T_NUM, floor: T_NUM, ceiling: T_NUM,
round: T_NUM, trunc: T_NUM, fraction: T_NUM,
integer: T_NUM, whole: T_NUM, sign: T_NUM,
max: T_NUM, min: T_NUM, remainder: T_NUM, modulo: T_NUM
max: T_NUM, min: T_NUM, remainder: T_NUM, modulo: T_NUM,
is_integer: T_BOOL, is_text: T_BOOL, is_number: T_BOOL,
is_null: T_BOOL, is_array: T_BOOL, is_function: T_BOOL,
is_object: T_BOOL, is_logical: T_BOOL, is_stone: T_BOOL,
is_blob: T_BOOL, starts_with: T_BOOL, ends_with: T_BOOL,
some: T_BOOL, every: T_BOOL
}
var narrow_arith_type = function(write_types, param_types, instr, typ) {
@@ -676,7 +688,49 @@ var streamline = function(ir, log) {
if (is_array(next)) {
next_op = next[0]
if (next_op == "jump_false" && next[1] == dest) {
// is_null + jump fusion: replace with jump_null / jump_not_null
if (op == "is_null" && (next_op == "jump_true" || next_op == "wary_true") && next[1] == dest) {
jlen = length(next)
nc = nc + 1
instructions[i] = "_nop_tc_" + text(nc)
instructions[i + 1] = ["jump_null", src, next[2], next[jlen - 2], next[jlen - 1]]
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "is_null_jump_fusion",
at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]],
why: {slot: src, fused_to: "jump_null"}
}
}
slot_types[dest] = T_BOOL
i = i + 2
continue
}
if (op == "is_null" && (next_op == "jump_false" || next_op == "wary_false") && next[1] == dest) {
jlen = length(next)
nc = nc + 1
instructions[i] = "_nop_tc_" + text(nc)
instructions[i + 1] = ["jump_not_null", src, next[2], next[jlen - 2], next[jlen - 1]]
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "is_null_jump_fusion",
at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]],
why: {slot: src, fused_to: "jump_not_null"}
}
}
slot_types[dest] = T_BOOL
i = i + 2
continue
}
if ((next_op == "jump_false" || next_op == "wary_false") && next[1] == dest) {
target_label = next[2]
if (slot_is(slot_types, src, checked_type)) {
nc = nc + 1
@@ -752,7 +806,7 @@ var streamline = function(ir, log) {
continue
}
if (next_op == "jump_true" && next[1] == dest) {
if ((next_op == "jump_true" || next_op == "wary_true") && next[1] == dest) {
target_label = next[2]
if (slot_is(slot_types, src, checked_type)) {
nc = nc + 1
@@ -891,6 +945,32 @@ var streamline = function(ir, log) {
continue
}
// Wary-to-certain: if slot type is T_BOOL, downgrade wary to certain jump
if (op == "wary_true" && slot_is(slot_types, instr[1], T_BOOL)) {
instr[0] = "jump_true"
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "wary_to_certain",
at: i, before: "wary_true", after: "jump_true",
why: {slot: instr[1], known_type: T_BOOL}
}
}
}
if (op == "wary_false" && slot_is(slot_types, instr[1], T_BOOL)) {
instr[0] = "jump_false"
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "wary_to_certain",
at: i, before: "wary_false", after: "jump_false",
why: {slot: instr[1], known_type: T_BOOL}
}
}
}
track_types(slot_types, instr)
i = i + 1
}
@@ -1048,11 +1128,12 @@ var streamline = function(ir, log) {
next_op = next[0]
nlen = length(next)
// not d, x; jump_false d, label → jump_true x, label
// not d, x; jump_false d, label → wary_true x, label
// (removing `not` removes coercion, so result must be wary)
if (next_op == "jump_false" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["jump_true", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
instructions[i + 1] = ["wary_true", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
@@ -1065,11 +1146,11 @@ var streamline = function(ir, log) {
continue
}
// not d, x; jump_true d, label → jump_false x, label
// not d, x; jump_true d, label → wary_false x, label
if (next_op == "jump_true" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["jump_false", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
instructions[i + 1] = ["wary_false", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
@@ -1082,6 +1163,40 @@ var streamline = function(ir, log) {
continue
}
// not d, x; wary_false d, label → wary_true x, label
if (next_op == "wary_false" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["wary_true", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
rule: "not_wary_false_fusion", at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]]
}
}
i = i + 2
continue
}
// not d, x; wary_true d, label → wary_false x, label
if (next_op == "wary_true" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["wary_false", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
rule: "not_wary_true_fusion", at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]]
}
}
i = i + 2
continue
}
// not d1, x; not d2, d1 → move d2, x
if (next_op == "not" && next[2] == instr[1]) {
nc = nc + 1
@@ -1169,7 +1284,7 @@ var streamline = function(ir, log) {
}
// Control flow with a read at position 1: substitute then clear
if (op == "return" || op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
if (op == "return" || is_cond_jump(op)) {
actual = copies[text(instr[1])]
if (actual != null) {
instr[1] = actual
@@ -1351,7 +1466,7 @@ var streamline = function(ir, log) {
op = instr[0]
if (op == "jump") {
target = instr[1]
} else if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
} else if (is_cond_jump(op)) {
target = instr[2]
}
if (target != null && is_text(target)) {
@@ -1558,7 +1673,7 @@ var streamline = function(ir, log) {
if (is_number(tgt)) stack[] = tgt
continue
}
if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
if (is_cond_jump(op)) {
tgt = label_map[instr[2]]
if (is_number(tgt)) stack[] = tgt
stack[] = idx + 1
@@ -1663,6 +1778,7 @@ var streamline = function(ir, log) {
frame: [1, 2], goframe: [1, 2],
jump: [], disrupt: [],
jump_true: [1], jump_false: [1], jump_not_null: [1],
wary_true: [1], wary_false: [1], jump_null: [1], jump_empty: [1],
return: [1],
stone_text: [1]
}
@@ -1693,6 +1809,7 @@ var streamline = function(ir, log) {
setarg: [], store_field: [], store_index: [], store_dynamic: [],
push: [], set_var: [], stone_text: [],
jump: [], jump_true: [], jump_false: [], jump_not_null: [],
wary_true: [], wary_false: [], jump_null: [], jump_empty: [],
return: [], disrupt: []
}
@@ -1706,6 +1823,7 @@ var streamline = function(ir, log) {
store_dynamic: [1, 2, 3],
push: [1, 2], set_var: [1], stone_text: [1],
jump: [], jump_true: [1], jump_false: [1], jump_not_null: [1],
wary_true: [1], wary_false: [1], jump_null: [1], jump_empty: [1],
return: [1], disrupt: []
}
@@ -1843,7 +1961,7 @@ var streamline = function(ir, log) {
target = null
if (op == "jump") {
target = instr[1]
} else if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
} else if (is_cond_jump(op)) {
target = instr[2]
}
if (target == null || !is_text(target)) {
@@ -2909,7 +3027,7 @@ var streamline = function(ir, log) {
// Remap labels in jump instructions
if (cop == "jump" && is_text(cinstr[1]) && !starts_with(cinstr[1], "_nop_")) {
new_instr[1] = label_prefix + cinstr[1]
} else if ((cop == "jump_true" || cop == "jump_false" || cop == "jump_not_null")
} else if (is_cond_jump(cop)
&& is_text(cinstr[2]) && !starts_with(cinstr[2], "_nop_")) {
new_instr[2] = label_prefix + cinstr[2]
}