guard hoisting

This commit is contained in:
2026-02-13 06:32:58 -06:00
parent 36fd0a35f9
commit f7e2ff13b5
10 changed files with 31941 additions and 29049 deletions

View File

@@ -62,7 +62,47 @@ When a slot appears with conflicting type inferences (e.g., used in both `add_in
**Nop prefix:** none (analysis only, does not modify instructions)
### 2. eliminate_type_checks (type-check + jump elimination)
### 2. infer_slot_write_types (slot write-type invariance)
Scans all instructions to determine which non-parameter slots have a consistent write type. If every instruction that writes to a given slot produces the same type, that type is globally invariant and can safely persist across label join points.
This analysis is sound because:
- `alloc_slot()` in mcode.cm is monotonically increasing — temp slots are never reused
- All local variable declarations must be at function body level and initialized — slots are written before any backward jumps to loop headers
- `move` is conservatively treated as T_UNKNOWN, avoiding unsound transitive assumptions
Write type mapping:
| Instruction class | Write type |
|---|---|
| `int` | T_INT |
| `true`, `false` | T_BOOL |
| `null` | T_NULL |
| `access` | type of literal value |
| `array` | T_ARRAY |
| `record` | T_RECORD |
| `function` | T_FUNCTION |
| `length` | T_INT |
| int arithmetic, `neg_int`, bitwise ops | T_INT |
| float arithmetic, `neg_float` | T_FLOAT |
| `concat` | T_TEXT |
| bool ops, comparisons, `in` | T_BOOL |
| generic arithmetic (`add`, `subtract`, etc.) | T_UNKNOWN |
| `move`, `load_field`, `load_index`, `load_dynamic`, `pop`, `get` | T_UNKNOWN |
| `invoke`, `tail_invoke` | T_UNKNOWN |
The result is a map of slot→type for slots where all writes agree on a single known type. Parameter slots (1..nr_args) and slot 0 are excluded.
Common patterns this enables:
- **Loop counters** (`var i = 0; ... i = i + 1`): written by `int` (T_INT) and `add_int` (T_INT) → invariant T_INT
- **Length variables** (`var len = length(arr)`): written by `length` (T_INT) only → invariant T_INT
- **Boolean flags** (`var found = false; ... found = true`): written by `false` and `true` → invariant T_BOOL
- **Locally-created containers** (`var arr = []`): written by `array` only → invariant T_ARRAY
**Nop prefix:** none (analysis only, does not modify instructions)
### 3. eliminate_type_checks (type-check + jump elimination)
Forward pass that tracks the known type of each slot. When a type check (`is_int`, `is_text`, `is_num`, etc.) is followed by a conditional jump, and the slot's type is already known, the check and jump can be eliminated or converted to an unconditional jump.
@@ -74,11 +114,11 @@ Three cases:
This pass also reduces `load_dynamic`/`store_dynamic` to `load_field`/`store_field` or `load_index`/`store_index` when the key slot's type is known.
At label join points, all type information is reset except for parameter types seeded by the backward inference pass.
At label join points, all type information is reset except for parameter types from backward inference and write-invariant types from slot write-type analysis.
**Nop prefix:** `_nop_tc_`
### 3. simplify_algebra (algebraic identity + comparison folding)
### 4. simplify_algebra (algebraic identity + comparison folding)
Tracks known constant values alongside types. Rewrites identity operations:
@@ -111,7 +151,7 @@ Same-slot comparison folding:
**Nop prefix:** none (rewrites in place, does not create nops)
### 4. simplify_booleans (not + jump fusion)
### 5. simplify_booleans (not + jump fusion)
Peephole pass that eliminates unnecessary `not` instructions:
@@ -125,13 +165,13 @@ This is particularly effective on `if (!cond)` patterns, which the compiler gene
**Nop prefix:** `_nop_bl_`
### 5. eliminate_moves (self-move elimination)
### 6. eliminate_moves (self-move elimination)
Removes `move a, a` instructions where the source and destination are the same slot. These can arise from earlier passes rewriting binary operations into moves.
**Nop prefix:** `_nop_mv_`
### 6. eliminate_unreachable (dead code after return)
### 7. eliminate_unreachable (dead code after return)
Nops instructions after `return` until the next real label. Only `return` is treated as a terminal instruction; `disrupt` is not, because the disruption handler code immediately follows `disrupt` and must remain reachable.
@@ -139,7 +179,7 @@ The mcode compiler emits a label at disruption handler entry points (see `emit_l
**Nop prefix:** `_nop_ur_`
### 7. eliminate_dead_jumps (jump-to-next-label elimination)
### 8. eliminate_dead_jumps (jump-to-next-label elimination)
Removes `jump L` instructions where `L` is the immediately following label (skipping over any intervening nop strings). These are common after other passes eliminate conditional branches, leaving behind jumps that fall through naturally.
@@ -150,8 +190,9 @@ Removes `jump L` instructions where `L` is the immediately following label (skip
All passes run in sequence in `optimize_function`:
```
infer_param_types → returns param_types map
eliminate_type_checks → uses param_types
infer_param_types → returns param_types map
infer_slot_write_types → returns write_types map
eliminate_type_checks → uses param_types + write_types
simplify_algebra
simplify_booleans
eliminate_moves
@@ -237,11 +278,12 @@ The `pure_intrinsics` set currently contains only `is_*` sensory functions (`is_
The streamline optimizer uses a numeric type lattice (`T_INT`, `T_FLOAT`, `T_TEXT`, etc.) for fine-grained per-instruction tracking:
- **Backward inference** (pass 1): Scans typed operators to infer parameter types. Since parameters are `def` (immutable), inferred types persist across label boundaries.
- **Forward tracking** (pass 2): `track_types` follows instruction execution order, tracking the type of each slot. Typed arithmetic results set their destination type. Type checks on unknown slots narrow the type on fallthrough.
- **Type check elimination** (pass 2): When a slot's type is already known, `is_<type>` + conditional jump pairs are eliminated or converted to unconditional jumps.
- **Dynamic access narrowing** (pass 2): `load_dynamic`/`store_dynamic` are narrowed to `load_field`/`store_field` or `load_index`/`store_index` when the key type is known.
- **Write-type invariance** (pass 2): Scans all instructions to find local slots where every write produces the same type. These invariant types persist across label boundaries alongside parameter types.
- **Forward tracking** (pass 3): `track_types` follows instruction execution order, tracking the type of each slot. Typed arithmetic results set their destination type. Type checks on unknown slots narrow the type on fallthrough.
- **Type check elimination** (pass 3): When a slot's type is already known, `is_<type>` + conditional jump pairs are eliminated or converted to unconditional jumps.
- **Dynamic access narrowing** (pass 3): `load_dynamic`/`store_dynamic` are narrowed to `load_field`/`store_field` or `load_index`/`store_index` when the key type is known.
Type information resets at label join points (since control flow merges could bring different types), except for parameter types from backward inference.
Type information resets at label join points (since control flow merges could bring different types), except for parameter types from backward inference and write-invariant types from slot write-type analysis.
## Future Work
@@ -267,6 +309,8 @@ When a type check on a parameter passes (falls through), the parameter's type co
A safe version would require proving that a parameter is monomorphic (called with only one type across all call sites), which requires interprocedural analysis.
**Note:** For local variables (non-parameters), the write-type invariance analysis (pass 2) achieves a similar effect safely — if every write to a slot produces the same type, that type persists across labels without needing to hoist any guard.
### Tail Call Optimization
`tail_invoke` instructions are currently marked but execute identically to `invoke`. Actual TCO would reuse the current call frame instead of creating a new one. This requires:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -219,6 +219,16 @@ var streamline = function(ir, log) {
return null
}
var seed_writes = function(slot_types, write_types) {
var keys = array(write_types)
var k = 0
while (k < length(keys)) {
slot_types[keys[k]] = write_types[keys[k]]
k = k + 1
}
return null
}
// =========================================================
// Pass: infer_param_types — backward type inference
// Scans typed operators to infer immutable parameter types.
@@ -308,15 +318,137 @@ var streamline = function(ir, log) {
return param_types
}
// =========================================================
// Pass: infer_slot_write_types — slot write-type invariance
// Scans all instructions to find non-parameter slots where
// every write produces the same type. These types persist
// across label join points.
// =========================================================
var infer_slot_write_types = function(func) {
var instructions = func.instructions
var nr_args = func.nr_args != null ? func.nr_args : 0
var num_instr = 0
var write_types = null
var result = null
var keys = null
var i = 0
var k = 0
var instr = null
var op = null
var slot = 0
var typ = null
var wt = null
if (instructions == null) {
return {}
}
num_instr = length(instructions)
write_types = {}
i = 0
while (i < num_instr) {
instr = instructions[i]
if (!is_array(instr)) {
i = i + 1
continue
}
op = instr[0]
slot = -1
typ = null
if (op == "int") {
slot = instr[1]
typ = T_INT
} else if (op == "true" || op == "false") {
slot = instr[1]
typ = T_BOOL
} else if (op == "null") {
slot = instr[1]
typ = T_NULL
} else if (op == "access") {
slot = instr[1]
typ = access_value_type(instr[2])
} else if (op == "array") {
slot = instr[1]
typ = T_ARRAY
} else if (op == "record") {
slot = instr[1]
typ = T_RECORD
} else if (op == "function") {
slot = instr[1]
typ = T_FUNCTION
} else if (op == "length") {
slot = instr[1]
typ = T_INT
} else if (int_result_ops[op] == true) {
slot = instr[1]
typ = T_INT
} else if (float_result_ops[op] == true) {
slot = instr[1]
typ = T_FLOAT
} else if (op == "neg_int" || op == "bitnot" || op == "bitand" ||
op == "bitor" || op == "bitxor" || op == "shl" ||
op == "shr" || op == "ushr") {
slot = instr[1]
typ = T_INT
} else if (op == "neg_float") {
slot = instr[1]
typ = T_FLOAT
} else if (op == "concat") {
slot = instr[1]
typ = T_TEXT
} else if (bool_result_ops[op] == true) {
slot = instr[1]
typ = T_BOOL
} else if (op == "eq" || op == "ne" || op == "lt" ||
op == "le" || op == "gt" || op == "ge" || op == "in") {
slot = instr[1]
typ = T_BOOL
} else if (op == "add" || op == "subtract" || op == "multiply" ||
op == "divide" || op == "modulo" || op == "pow") {
slot = instr[1]
typ = T_UNKNOWN
} else if (op == "move" || op == "load_field" || op == "load_index" ||
op == "load_dynamic" || op == "pop" || op == "get") {
slot = instr[1]
typ = T_UNKNOWN
} else if (op == "invoke" || op == "tail_invoke") {
slot = instr[2]
typ = T_UNKNOWN
}
if (slot > 0 && slot > nr_args) {
merge_backward(write_types, slot, typ != null ? typ : T_UNKNOWN)
}
i = i + 1
}
// Filter to only slots with known (non-unknown) types
result = {}
keys = array(write_types)
k = 0
while (k < length(keys)) {
wt = write_types[keys[k]]
if (wt != null && wt != T_UNKNOWN) {
result[keys[k]] = wt
}
k = k + 1
}
return result
}
// =========================================================
// Pass: eliminate_type_checks — language-level type narrowing
// Eliminates is_<type>/jump pairs when type is known.
// Reduces load_dynamic/store_dynamic to field/index forms.
// =========================================================
var eliminate_type_checks = function(func, param_types, log) {
var eliminate_type_checks = function(func, param_types, write_types, log) {
var instructions = func.instructions
var nr_args = func.nr_args != null ? func.nr_args : 0
var has_params = false
var has_writes = false
var num_instr = 0
var slot_types = null
var nc = 0
@@ -351,11 +483,15 @@ var streamline = function(ir, log) {
}
j = j + 1
}
has_writes = length(array(write_types)) > 0
slot_types = {}
if (has_params) {
seed_params(slot_types, param_types, nr_args)
}
if (has_writes) {
seed_writes(slot_types, write_types)
}
i = 0
while (i < num_instr) {
@@ -366,6 +502,9 @@ var streamline = function(ir, log) {
if (has_params) {
seed_params(slot_types, param_types, nr_args)
}
if (has_writes) {
seed_writes(slot_types, write_types)
}
i = i + 1
continue
}
@@ -1130,6 +1269,7 @@ var streamline = function(ir, log) {
// =========================================================
var optimize_function = function(func, log) {
var param_types = null
var write_types = null
var slot_types = null
if (func.instructions == null || length(func.instructions) == 0) {
return null
@@ -1139,8 +1279,13 @@ var streamline = function(ir, log) {
return param_types
})
if (verify_fn) verify_fn(func, "after infer_param_types")
run_pass(func, "infer_slot_write_types", function() {
write_types = infer_slot_write_types(func)
return write_types
})
if (verify_fn) verify_fn(func, "after infer_slot_write_types")
run_pass(func, "eliminate_type_checks", function() {
slot_types = eliminate_type_checks(func, param_types, log)
slot_types = eliminate_type_checks(func, param_types, write_types, log)
return slot_types
})
if (verify_fn) verify_fn(func, "after eliminate_type_checks")

File diff suppressed because it is too large Load Diff

View File

@@ -136,8 +136,8 @@
"add_ni_16",
["is_text", 8, 5, 94, 17],
["jump_false", 8, "add_nt_17", 94, 17],
["is_text", 9, 6, 94, 17],
["jump_false", 9, "add_nt_17", 94, 17],
"_nop_tc_1",
["jump", "add_nt_17", 94, 17],
["concat", 7, 5, 6, 94, 17],
["jump", "add_done_18", 94, 17],
"add_nt_17",
@@ -199,8 +199,8 @@
"add_ni_28",
["is_text", 17, 14, 96, 19],
["jump_false", 17, "add_nt_29", 96, 19],
["is_text", 18, 15, 96, 19],
["jump_false", 18, "add_nt_29", 96, 19],
"_nop_tc_2",
["jump", "add_nt_29", 96, 19],
["concat", 16, 14, 15, 96, 19],
["jump", "add_done_30", 96, 19],
"add_nt_29",
@@ -225,8 +225,8 @@
"add_ni_32",
["is_text", 23, 20, 99, 19],
["jump_false", 23, "add_nt_33", 99, 19],
["is_text", 24, 21, 99, 19],
["jump_false", 24, "add_nt_33", 99, 19],
"_nop_tc_3",
["jump", "add_nt_33", 99, 19],
["concat", 22, 20, 21, 99, 19],
["jump", "add_done_34", 99, 19],
"add_nt_33",
@@ -639,20 +639,20 @@
["disrupt", 114, 44],
"num_done_100",
["access", 28, 10, 114, 51],
["is_int", 30, 25, 114, 51],
["jump_false", 30, "add_ni_102", 114, 51],
"_nop_tc_1",
["jump", "add_ni_102", 114, 51],
["add_int", 29, 25, 28, 114, 51],
["jump", "add_done_104", 114, 51],
"add_ni_102",
["is_text", 30, 25, 114, 51],
["jump_false", 30, "add_nt_103", 114, 51],
["is_text", 31, 28, 114, 51],
["jump_false", 31, "add_nt_103", 114, 51],
"_nop_tc_2",
["jump", "add_nt_103", 114, 51],
"_nop_tc_3",
["jump", "add_nt_103", 114, 51],
["concat", 29, 25, 28, 114, 51],
["jump", "add_done_104", 114, 51],
"add_nt_103",
["is_num", 30, 25, 114, 51],
["jump_false", 30, "add_err_105", 114, 51],
"_nop_tc_4",
"_nop_tc_5",
["add_float", 29, 25, 28, 114, 51],
["jump", "add_done_104", 114, 51],
"add_err_105",
@@ -733,20 +733,20 @@
["disrupt", 115, 44],
"num_done_118",
["access", 45, 10, 115, 51],
["is_int", 47, 42, 115, 51],
["jump_false", 47, "add_ni_120", 115, 51],
"_nop_tc_6",
["jump", "add_ni_120", 115, 51],
["add_int", 46, 42, 45, 115, 51],
["jump", "add_done_122", 115, 51],
"add_ni_120",
["is_text", 47, 42, 115, 51],
["jump_false", 47, "add_nt_121", 115, 51],
["is_text", 48, 45, 115, 51],
["jump_false", 48, "add_nt_121", 115, 51],
"_nop_tc_7",
["jump", "add_nt_121", 115, 51],
"_nop_tc_8",
["jump", "add_nt_121", 115, 51],
["concat", 46, 42, 45, 115, 51],
["jump", "add_done_122", 115, 51],
"add_nt_121",
["is_num", 47, 42, 115, 51],
["jump_false", 47, "add_err_123", 115, 51],
"_nop_tc_9",
"_nop_tc_10",
["add_float", 46, 42, 45, 115, 51],
["jump", "add_done_122", 115, 51],
"add_err_123",
@@ -783,15 +783,15 @@
"rel_ni_128",
["is_num", 5, 2, 122, 17],
["jump_false", 5, "rel_nn_129", 122, 17],
["is_num", 6, 3, 122, 17],
["jump_false", 6, "rel_nn_129", 122, 17],
"_nop_tc_2",
"_nop_tc_3",
["lt_float", 4, 2, 3, 122, 17],
["jump", "rel_done_130", 122, 17],
"rel_nn_129",
["is_text", 5, 2, 122, 17],
["jump_false", 5, "rel_err_131", 122, 17],
["is_text", 6, 3, 122, 17],
["jump_false", 6, "rel_err_131", 122, 17],
"_nop_tc_4",
["jump", "rel_err_131", 122, 17],
["lt_text", 4, 2, 3, 122, 17],
["jump", "rel_done_130", 122, 17],
"rel_err_131",
@@ -866,22 +866,22 @@
["setarg", 32, 0, 33, 123, 30],
["setarg", 32, 1, 26, 123, 30],
["invoke", 32, 30, 123, 30],
["is_int", 35, 23, 123, 30],
["jump_false", 35, "add_ni_139", 123, 30],
"_nop_tc_5",
["jump", "add_ni_139", 123, 30],
["is_int", 36, 30, 123, 30],
["jump_false", 36, "add_ni_139", 123, 30],
["add_int", 34, 23, 30, 123, 30],
["jump", "add_done_141", 123, 30],
"add_ni_139",
["is_text", 35, 23, 123, 30],
["jump_false", 35, "add_nt_140", 123, 30],
"_nop_tc_6",
["jump", "add_nt_140", 123, 30],
["is_text", 36, 30, 123, 30],
["jump_false", 36, "add_nt_140", 123, 30],
["concat", 34, 23, 30, 123, 30],
["jump", "add_done_141", 123, 30],
"add_nt_140",
["is_num", 35, 23, 123, 30],
["jump_false", 35, "add_err_142", 123, 30],
"_nop_tc_7",
"_nop_tc_8",
["is_num", 36, 30, 123, 30],
["jump_false", 36, "add_err_142", 123, 30],
["add_float", 34, 23, 30, 123, 30],
@@ -898,8 +898,8 @@
"add_ni_143",
["is_text", 39, 2, 124, 17],
["jump_false", 39, "add_nt_144", 124, 17],
["is_text", 40, 37, 124, 17],
["jump_false", 40, "add_nt_144", 124, 17],
"_nop_tc_9",
["jump", "add_nt_144", 124, 17],
["concat", 38, 2, 37, 124, 17],
["jump", "add_done_145", 124, 17],
"add_nt_144",
@@ -2451,8 +2451,8 @@
"add_ni_372",
["is_text", 45, 42, 201, 38],
["jump_false", 45, "add_nt_373", 201, 38],
["is_text", 46, 43, 201, 38],
["jump_false", 46, "add_nt_373", 201, 38],
"_nop_tc_1",
["jump", "add_nt_373", 201, 38],
["concat", 44, 42, 43, 201, 38],
["jump", "add_done_374", 201, 38],
"add_nt_373",
@@ -2556,8 +2556,8 @@
"add_ni_388",
["is_text", 67, 64, 203, 42],
["jump_false", 67, "add_nt_389", 203, 42],
["is_text", 68, 65, 203, 42],
["jump_false", 68, "add_nt_389", 203, 42],
"_nop_tc_2",
["jump", "add_nt_389", 203, 42],
["concat", 66, 64, 65, 203, 42],
["jump", "add_done_390", 203, 42],
"add_nt_389",
@@ -2663,8 +2663,8 @@
"add_ni_404",
["is_text", 95, 92, 206, 45],
["jump_false", 95, "add_nt_405", 206, 45],
["is_text", 96, 93, 206, 45],
["jump_false", 96, "add_nt_405", 206, 45],
"_nop_tc_3",
["jump", "add_nt_405", 206, 45],
["concat", 94, 92, 93, 206, 45],
["jump", "add_done_406", 206, 45],
"add_nt_405",
@@ -2853,22 +2853,22 @@
["access", 138, 0, 211, 37],
["is_int", 140, 6, 211, 37],
["jump_false", 140, "rel_ni_433", 211, 37],
"_nop_tc_1",
"_nop_tc_4",
["jump", "rel_ni_433", 211, 37],
["gt_int", 139, 6, 138, 211, 37],
["jump", "rel_done_435", 211, 37],
"rel_ni_433",
["is_num", 140, 6, 211, 37],
["jump_false", 140, "rel_nn_434", 211, 37],
["is_num", 141, 138, 211, 37],
["jump_false", 141, "rel_nn_434", 211, 37],
"_nop_tc_5",
"_nop_tc_6",
["gt_float", 139, 6, 138, 211, 37],
["jump", "rel_done_435", 211, 37],
"rel_nn_434",
["is_text", 140, 6, 211, 37],
["jump_false", 140, "rel_err_436", 211, 37],
["is_text", 141, 138, 211, 37],
["jump_false", 141, "rel_err_436", 211, 37],
"_nop_tc_7",
["jump", "rel_err_436", 211, 37],
["gt_text", 139, 6, 138, 211, 37],
["jump", "rel_done_435", 211, 37],
"rel_err_436",
@@ -2932,8 +2932,8 @@
"add_ni_445",
["is_text", 152, 6, 213, 50],
["jump_false", 152, "add_nt_446", 213, 50],
["is_text", 153, 150, 213, 50],
["jump_false", 153, "add_nt_446", 213, 50],
"_nop_tc_8",
["jump", "add_nt_446", 213, 50],
["concat", 151, 6, 150, 213, 50],
["jump", "add_done_447", 213, 50],
"add_nt_446",
@@ -3285,8 +3285,8 @@
"add_ni_506",
["is_text", 213, 210, 221, 46],
["jump_false", 213, "add_nt_507", 221, 46],
["is_text", 214, 211, 221, 46],
["jump_false", 214, "add_nt_507", 221, 46],
"_nop_tc_9",
["jump", "add_nt_507", 221, 46],
["concat", 212, 210, 211, 221, 46],
["jump", "add_done_508", 221, 46],
"add_nt_507",
@@ -5158,36 +5158,36 @@
"ne_ni_762",
["is_int", 36, 5, 287, 15],
["jump_false", 36, "ne_nn_763", 287, 15],
["is_int", 37, 34, 287, 15],
["jump_false", 37, "ne_nn_763", 287, 15],
"_nop_tc_1",
["jump", "ne_nn_763", 287, 15],
["ne_int", 35, 5, 34, 287, 15],
["jump", "ne_done_760", 287, 15],
"ne_nn_763",
["is_num", 36, 5, 287, 15],
["jump_false", 36, "ne_nt_764", 287, 15],
["is_num", 37, 34, 287, 15],
["jump_false", 37, "ne_nt_764", 287, 15],
"_nop_tc_2",
["jump", "ne_nt_764", 287, 15],
["ne_float", 35, 5, 34, 287, 15],
["jump", "ne_done_760", 287, 15],
"ne_nt_764",
["is_text", 36, 5, 287, 15],
["jump_false", 36, "ne_nnl_765", 287, 15],
["is_text", 37, 34, 287, 15],
["jump_false", 37, "ne_nnl_765", 287, 15],
"_nop_tc_3",
["jump", "ne_nnl_765", 287, 15],
["ne_text", 35, 5, 34, 287, 15],
["jump", "ne_done_760", 287, 15],
"ne_nnl_765",
["is_null", 36, 5, 287, 15],
["jump_false", 36, "ne_nb_766", 287, 15],
["is_null", 37, 34, 287, 15],
["jump_false", 37, "ne_nb_766", 287, 15],
"_nop_tc_4",
"_nop_tc_5",
["false", 35, 287, 15],
["jump", "ne_done_760", 287, 15],
"ne_nb_766",
["is_bool", 36, 5, 287, 15],
["jump_false", 36, "ne_mis_767", 287, 15],
["is_bool", 37, 34, 287, 15],
["jump_false", 37, "ne_mis_767", 287, 15],
"_nop_tc_6",
["jump", "ne_mis_767", 287, 15],
["ne_bool", 35, 5, 34, 287, 15],
["jump", "ne_done_760", 287, 15],
"ne_mis_767",
@@ -5685,8 +5685,8 @@
"add_ni_833",
["is_text", 19, 6, 334, 40],
["jump_false", 19, "add_nt_834", 334, 40],
["is_text", 20, 17, 334, 40],
["jump_false", 20, "add_nt_834", 334, 40],
"_nop_tc_1",
["jump", "add_nt_834", 334, 40],
["concat", 18, 6, 17, 334, 40],
["jump", "add_done_835", 334, 40],
"add_nt_834",
@@ -5774,8 +5774,8 @@
"add_ni_845",
["is_text", 18, 5, 347, 40],
["jump_false", 18, "add_nt_846", 347, 40],
["is_text", 19, 16, 347, 40],
["jump_false", 19, "add_nt_846", 347, 40],
"_nop_tc_1",
["jump", "add_nt_846", 347, 40],
["concat", 17, 5, 16, 347, 40],
["jump", "add_done_847", 347, 40],
"add_nt_846",
@@ -5862,29 +5862,29 @@
"eq_ni_854",
["is_num", 12, 3, 362, 14],
["jump_false", 12, "eq_nn_855", 362, 14],
["is_num", 13, 10, 362, 14],
["jump_false", 13, "eq_nn_855", 362, 14],
"_nop_tc_2",
"_nop_tc_3",
["eq_float", 11, 3, 10, 362, 14],
["jump", "eq_done_853", 362, 14],
"eq_nn_855",
["is_text", 12, 3, 362, 14],
["jump_false", 12, "eq_nt_856", 362, 14],
["is_text", 13, 10, 362, 14],
["jump_false", 13, "eq_nt_856", 362, 14],
"_nop_tc_4",
["jump", "eq_nt_856", 362, 14],
["eq_text", 11, 3, 10, 362, 14],
["jump", "eq_done_853", 362, 14],
"eq_nt_856",
["is_null", 12, 3, 362, 14],
["jump_false", 12, "eq_nnl_857", 362, 14],
["is_null", 13, 10, 362, 14],
["jump_false", 13, "eq_nnl_857", 362, 14],
"_nop_tc_5",
["jump", "eq_nnl_857", 362, 14],
["true", 11, 362, 14],
["jump", "eq_done_853", 362, 14],
"eq_nnl_857",
["is_bool", 12, 3, 362, 14],
["jump_false", 12, "eq_nb_858", 362, 14],
["is_bool", 13, 10, 362, 14],
["jump_false", 13, "eq_nb_858", 362, 14],
"_nop_tc_6",
["jump", "eq_nb_858", 362, 14],
["eq_bool", 11, 3, 10, 362, 14],
["jump", "eq_done_853", 362, 14],
"eq_nb_858",
@@ -11012,22 +11012,22 @@
["function", 132, 19, 356, 22],
["move", 45, 132, 356, 22],
"while_start_1521",
["is_int", 134, 6, 504, 16],
["jump_false", 134, "rel_ni_1523", 504, 16],
"_nop_tc_1",
["jump", "rel_ni_1523", 504, 16],
["is_int", 135, 30, 504, 16],
["jump_false", 135, "rel_ni_1523", 504, 16],
["lt_int", 133, 6, 30, 504, 16],
["jump", "rel_done_1525", 504, 16],
"rel_ni_1523",
["is_num", 134, 6, 504, 16],
["jump_false", 134, "rel_nn_1524", 504, 16],
"_nop_tc_2",
"_nop_tc_3",
["is_num", 135, 30, 504, 16],
["jump_false", 135, "rel_nn_1524", 504, 16],
["lt_float", 133, 6, 30, 504, 16],
["jump", "rel_done_1525", 504, 16],
"rel_nn_1524",
["is_text", 134, 6, 504, 16],
["jump_false", 134, "rel_err_1526", 504, 16],
"_nop_tc_4",
["jump", "rel_err_1526", 504, 16],
["is_text", 135, 30, 504, 16],
["jump_false", 135, "rel_err_1526", 504, 16],
["lt_text", 133, 6, 30, 504, 16],