Spaces:
Sleeping
Sleeping
github-actions commited on
Commit ·
6d01cfb
1
Parent(s): 49b9c11
Auto deploy from GitHub
Browse files- compiler_tetris (1).ipynb +651 -0
- space/metahack1 (1).ipynb +0 -0
- space/space/.DS_Store +0 -0
- space/space/metahack1 (1).ipynb +1379 -0
- space/space/space/metahack1.ipynb +484 -0
- space/space/space/space/.github/workflows/deploy.yml +30 -0
- space/space/space/space/README.md +1 -11
- space/space/space/space/space/.gitattributes +35 -0
- space/space/space/space/space/README.md +11 -0
compiler_tetris (1).ipynb
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": null,
|
| 6 |
+
"id": "b7fdb9ab",
|
| 7 |
+
"metadata": {},
|
| 8 |
+
"outputs": [],
|
| 9 |
+
"source": [
|
| 10 |
+
"# ==== CELL 1: Setup ====\n",
|
| 11 |
+
"!pip install -q pytest\n",
|
| 12 |
+
"import os, sys\n",
|
| 13 |
+
"\n",
|
| 14 |
+
"LOCAL_DIR = \"/content/toyir\"\n",
|
| 15 |
+
"DRIVE_DIR = \"/content/drive/MyDrive/env/toyir\"\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"os.makedirs(LOCAL_DIR, exist_ok=True)\n",
|
| 18 |
+
"sys.path.insert(0, LOCAL_DIR)\n",
|
| 19 |
+
"print(\"Workspace ready at\", LOCAL_DIR)\n"
|
| 20 |
+
]
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"cell_type": "code",
|
| 24 |
+
"execution_count": null,
|
| 25 |
+
"id": "d0337367",
|
| 26 |
+
"metadata": {},
|
| 27 |
+
"outputs": [],
|
| 28 |
+
"source": [
|
| 29 |
+
"# ==== CELL 1b: Mount Drive + sync workspace ====\n",
|
| 30 |
+
"from google.colab import drive\n",
|
| 31 |
+
"drive.mount('/content/drive')\n",
|
| 32 |
+
"\n",
|
| 33 |
+
"import shutil\n",
|
| 34 |
+
"os.makedirs(DRIVE_DIR, exist_ok=True)\n",
|
| 35 |
+
"\n",
|
| 36 |
+
"# On fresh runtime: pull existing files from Drive -> local\n",
|
| 37 |
+
"for f in os.listdir(DRIVE_DIR):\n",
|
| 38 |
+
" src = os.path.join(DRIVE_DIR, f)\n",
|
| 39 |
+
" if os.path.isfile(src) and f.endswith(\".py\"):\n",
|
| 40 |
+
" shutil.copy2(src, os.path.join(LOCAL_DIR, f))\n",
|
| 41 |
+
"print(\"Synced from Drive:\", sorted(os.listdir(LOCAL_DIR)))\n"
|
| 42 |
+
]
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"cell_type": "code",
|
| 46 |
+
"execution_count": null,
|
| 47 |
+
"id": "2c83c529",
|
| 48 |
+
"metadata": {},
|
| 49 |
+
"outputs": [],
|
| 50 |
+
"source": [
|
| 51 |
+
"%%writefile /content/toyir/toy_vm.py\n",
|
| 52 |
+
"\"\"\"Toy-IR VM: deterministic, dependency-light execution engine for RLVR.\"\"\"\n",
|
| 53 |
+
"from __future__ import annotations\n",
|
| 54 |
+
"from copy import deepcopy\n",
|
| 55 |
+
"from typing import Any\n",
|
| 56 |
+
"\n",
|
| 57 |
+
"CYCLE_COST: dict[str, int] = {\n",
|
| 58 |
+
" \"CONST\": 1, \"ADD\": 1, \"SUB\": 1, \"MUL\": 3, \"DIV\": 5,\n",
|
| 59 |
+
" \"COPY\": 1, \"LOAD\": 4, \"STORE\": 4, \"NOP\": 0,\n",
|
| 60 |
+
"}\n",
|
| 61 |
+
"OP_ORDER = (\"CONST\", \"ADD\", \"SUB\", \"MUL\", \"DIV\", \"COPY\", \"LOAD\", \"STORE\", \"NOP\")\n",
|
| 62 |
+
"VALID_OPS = frozenset(CYCLE_COST)\n",
|
| 63 |
+
"REQUIRED_KEYS = (\"op\", \"dest\", \"src1\", \"src2\")\n",
|
| 64 |
+
"\n",
|
| 65 |
+
"\n",
|
| 66 |
+
"def _is_str_or_int_or_none(x: Any) -> bool:\n",
|
| 67 |
+
" return x is None or isinstance(x, str) or (isinstance(x, int) and not isinstance(x, bool))\n",
|
| 68 |
+
"\n",
|
| 69 |
+
"\n",
|
| 70 |
+
"def _is_str_or_none(x: Any) -> bool:\n",
|
| 71 |
+
" return x is None or isinstance(x, str)\n",
|
| 72 |
+
"\n",
|
| 73 |
+
"\n",
|
| 74 |
+
"def validate_ir(program: list[dict]) -> dict:\n",
|
| 75 |
+
" errors: list[str] = []\n",
|
| 76 |
+
" for i, ins in enumerate(program):\n",
|
| 77 |
+
" if not isinstance(ins, dict):\n",
|
| 78 |
+
" errors.append(f\"[{i}] not a dict\")\n",
|
| 79 |
+
" continue\n",
|
| 80 |
+
" for k in REQUIRED_KEYS:\n",
|
| 81 |
+
" if k not in ins:\n",
|
| 82 |
+
" errors.append(f\"[{i}] missing key '{k}'\")\n",
|
| 83 |
+
" if \"op\" not in ins:\n",
|
| 84 |
+
" continue\n",
|
| 85 |
+
" op = ins[\"op\"]\n",
|
| 86 |
+
" if op not in VALID_OPS:\n",
|
| 87 |
+
" errors.append(f\"[{i}] invalid op '{op}'\")\n",
|
| 88 |
+
" continue\n",
|
| 89 |
+
" if not _is_str_or_none(ins.get(\"dest\")):\n",
|
| 90 |
+
" errors.append(f\"[{i}] dest must be str|None\")\n",
|
| 91 |
+
" if not _is_str_or_int_or_none(ins.get(\"src1\")):\n",
|
| 92 |
+
" errors.append(f\"[{i}] src1 must be str|int|None\")\n",
|
| 93 |
+
" if not _is_str_or_int_or_none(ins.get(\"src2\")):\n",
|
| 94 |
+
" errors.append(f\"[{i}] src2 must be str|int|None\")\n",
|
| 95 |
+
"\n",
|
| 96 |
+
" # per-op contracts\n",
|
| 97 |
+
" if op in (\"CONST\", \"ADD\", \"SUB\", \"MUL\", \"DIV\", \"COPY\", \"LOAD\"):\n",
|
| 98 |
+
" if not isinstance(ins.get(\"dest\"), str):\n",
|
| 99 |
+
" errors.append(f\"[{i}] {op} requires str dest\")\n",
|
| 100 |
+
" if op in (\"ADD\", \"SUB\", \"MUL\", \"DIV\"):\n",
|
| 101 |
+
" if ins.get(\"src1\") is None or ins.get(\"src2\") is None:\n",
|
| 102 |
+
" errors.append(f\"[{i}] {op} requires src1 and src2\")\n",
|
| 103 |
+
" if op in (\"CONST\", \"COPY\"):\n",
|
| 104 |
+
" if ins.get(\"src1\") is None:\n",
|
| 105 |
+
" errors.append(f\"[{i}] {op} requires src1\")\n",
|
| 106 |
+
" if op in (\"CONST\", \"COPY\", \"LOAD\", \"STORE\"):\n",
|
| 107 |
+
" if ins.get(\"src2\") is not None:\n",
|
| 108 |
+
" errors.append(f\"[{i}] {op} requires src2=None\")\n",
|
| 109 |
+
" if op == \"LOAD\":\n",
|
| 110 |
+
" if not isinstance(ins.get(\"src1\"), str):\n",
|
| 111 |
+
" errors.append(f\"[{i}] LOAD src1 must be str (variable name)\")\n",
|
| 112 |
+
" if op == \"STORE\":\n",
|
| 113 |
+
" if not isinstance(ins.get(\"dest\"), str):\n",
|
| 114 |
+
" errors.append(f\"[{i}] STORE dest must be str (variable name)\")\n",
|
| 115 |
+
" if ins.get(\"src1\") is None:\n",
|
| 116 |
+
" errors.append(f\"[{i}] STORE requires src1\")\n",
|
| 117 |
+
" if op == \"NOP\":\n",
|
| 118 |
+
" if any(ins.get(k) is not None for k in (\"dest\", \"src1\", \"src2\")):\n",
|
| 119 |
+
" errors.append(f\"[{i}] NOP fields must all be None\")\n",
|
| 120 |
+
"\n",
|
| 121 |
+
" return {\"valid\": len(errors) == 0, \"errors\": errors}\n",
|
| 122 |
+
"\n",
|
| 123 |
+
"\n",
|
| 124 |
+
"def _resolve(operand: Any, variables: dict) -> int:\n",
|
| 125 |
+
" if isinstance(operand, str):\n",
|
| 126 |
+
" if operand not in variables:\n",
|
| 127 |
+
" raise KeyError(f\"undefined variable '{operand}'\")\n",
|
| 128 |
+
" return variables[operand]\n",
|
| 129 |
+
" if isinstance(operand, int) and not isinstance(operand, bool):\n",
|
| 130 |
+
" return operand\n",
|
| 131 |
+
" raise TypeError(f\"bad operand: {operand!r}\")\n",
|
| 132 |
+
"\n",
|
| 133 |
+
"\n",
|
| 134 |
+
"def _exec_one(ins: dict, variables: dict, memory: dict) -> int:\n",
|
| 135 |
+
" op = ins[\"op\"]\n",
|
| 136 |
+
" dest = ins[\"dest\"]\n",
|
| 137 |
+
" s1, s2 = ins[\"src1\"], ins[\"src2\"]\n",
|
| 138 |
+
"\n",
|
| 139 |
+
" if op == \"CONST\":\n",
|
| 140 |
+
" variables[dest] = _resolve(s1, variables)\n",
|
| 141 |
+
" elif op == \"ADD\":\n",
|
| 142 |
+
" variables[dest] = _resolve(s1, variables) + _resolve(s2, variables)\n",
|
| 143 |
+
" elif op == \"SUB\":\n",
|
| 144 |
+
" variables[dest] = _resolve(s1, variables) - _resolve(s2, variables)\n",
|
| 145 |
+
" elif op == \"MUL\":\n",
|
| 146 |
+
" variables[dest] = _resolve(s1, variables) * _resolve(s2, variables)\n",
|
| 147 |
+
" elif op == \"DIV\":\n",
|
| 148 |
+
" b = _resolve(s2, variables)\n",
|
| 149 |
+
" if b == 0:\n",
|
| 150 |
+
" raise ZeroDivisionError(\"DIV by zero\")\n",
|
| 151 |
+
" variables[dest] = _resolve(s1, variables) // b\n",
|
| 152 |
+
" elif op == \"COPY\":\n",
|
| 153 |
+
" variables[dest] = _resolve(s1, variables)\n",
|
| 154 |
+
" elif op == \"LOAD\":\n",
|
| 155 |
+
" if not isinstance(s1, str):\n",
|
| 156 |
+
" raise TypeError(\"LOAD src1 must be a variable name\")\n",
|
| 157 |
+
" addr = variables.get(s1)\n",
|
| 158 |
+
" if not (isinstance(addr, int) and not isinstance(addr, bool)):\n",
|
| 159 |
+
" raise TypeError(f\"LOAD address from '{s1}' is not int: {addr!r}\")\n",
|
| 160 |
+
" if addr not in memory:\n",
|
| 161 |
+
" raise KeyError(f\"LOAD from uninitialized addr {addr}\")\n",
|
| 162 |
+
" variables[dest] = memory[addr]\n",
|
| 163 |
+
" elif op == \"STORE\":\n",
|
| 164 |
+
" if not isinstance(dest, str):\n",
|
| 165 |
+
" raise TypeError(\"STORE dest must be a variable name\")\n",
|
| 166 |
+
" addr = variables.get(dest)\n",
|
| 167 |
+
" if not (isinstance(addr, int) and not isinstance(addr, bool)):\n",
|
| 168 |
+
" raise TypeError(f\"STORE address from '{dest}' is not int: {addr!r}\")\n",
|
| 169 |
+
" memory[addr] = _resolve(s1, variables)\n",
|
| 170 |
+
" elif op == \"NOP\":\n",
|
| 171 |
+
" pass\n",
|
| 172 |
+
" else:\n",
|
| 173 |
+
" raise ValueError(f\"non-executable op {op}\")\n",
|
| 174 |
+
" return CYCLE_COST[op]\n",
|
| 175 |
+
"\n",
|
| 176 |
+
"\n",
|
| 177 |
+
"def execute(program: list[dict], initial_state: dict) -> dict:\n",
|
| 178 |
+
" variables: dict = {}\n",
|
| 179 |
+
" memory: dict = {}\n",
|
| 180 |
+
" cycles = 0\n",
|
| 181 |
+
" try:\n",
|
| 182 |
+
" if not isinstance(initial_state, dict):\n",
|
| 183 |
+
" raise TypeError(\"initial_state must be a dict\")\n",
|
| 184 |
+
" state = deepcopy(initial_state)\n",
|
| 185 |
+
" variables = state.get(\"variables\", {})\n",
|
| 186 |
+
" memory = state.get(\"memory\", {})\n",
|
| 187 |
+
" if not isinstance(variables, dict):\n",
|
| 188 |
+
" raise TypeError(\"initial_state['variables'] must be a dict\")\n",
|
| 189 |
+
" if not isinstance(memory, dict):\n",
|
| 190 |
+
" raise TypeError(\"initial_state['memory'] must be a dict\")\n",
|
| 191 |
+
"\n",
|
| 192 |
+
" for ins in program:\n",
|
| 193 |
+
" cycles += _exec_one(ins, variables, memory)\n",
|
| 194 |
+
" except Exception as e:\n",
|
| 195 |
+
" return {\"memory\": memory, \"variables\": variables,\n",
|
| 196 |
+
" \"cycles\": None, \"success\": False, \"error\": str(e)}\n",
|
| 197 |
+
" return {\"memory\": memory, \"variables\": variables,\n",
|
| 198 |
+
" \"cycles\": cycles, \"success\": True, \"error\": None}\n",
|
| 199 |
+
"\n",
|
| 200 |
+
"\n",
|
| 201 |
+
"def count_cycles(program: list[dict]) -> int:\n",
|
| 202 |
+
" total = 0\n",
|
| 203 |
+
" for i, ins in enumerate(program):\n",
|
| 204 |
+
" op = ins.get(\"op\") if isinstance(ins, dict) else None\n",
|
| 205 |
+
" if op not in CYCLE_COST:\n",
|
| 206 |
+
" raise ValueError(f\"count_cycles: invalid or missing op at index {i}: {op!r}\")\n",
|
| 207 |
+
" total += CYCLE_COST[op]\n",
|
| 208 |
+
" return total\n",
|
| 209 |
+
"\n",
|
| 210 |
+
"\n",
|
| 211 |
+
"def profile(program: list[dict]) -> dict:\n",
|
| 212 |
+
" out: dict[str, int] = {\"n_instructions\": len(program)}\n",
|
| 213 |
+
" for op in OP_ORDER:\n",
|
| 214 |
+
" out[f\"n_{op.lower()}\"] = 0\n",
|
| 215 |
+
" for ins in program:\n",
|
| 216 |
+
" key = f\"n_{ins['op'].lower()}\"\n",
|
| 217 |
+
" if key in out:\n",
|
| 218 |
+
" out[key] += 1\n",
|
| 219 |
+
" return out\n",
|
| 220 |
+
"\n",
|
| 221 |
+
"\n",
|
| 222 |
+
"def _fmt_operand(x: Any) -> str:\n",
|
| 223 |
+
" if x is None:\n",
|
| 224 |
+
" return \"\"\n",
|
| 225 |
+
" return str(x)\n",
|
| 226 |
+
"\n",
|
| 227 |
+
"\n",
|
| 228 |
+
"def dump_ir(program: list[dict]) -> str:\n",
|
| 229 |
+
" stores = [ins[\"dest\"] for ins in program if ins[\"op\"] == \"STORE\"]\n",
|
| 230 |
+
" seen, ordered = set(), []\n",
|
| 231 |
+
" for s in stores:\n",
|
| 232 |
+
" if s not in seen:\n",
|
| 233 |
+
" seen.add(s); ordered.append(s)\n",
|
| 234 |
+
" header = \"// OBSERVABLE OUT: \" + (\", \".join(f\"mem[{s}]\" for s in ordered) if ordered else \"(none)\")\n",
|
| 235 |
+
" lines = [header]\n",
|
| 236 |
+
" for ins in program:\n",
|
| 237 |
+
" op = ins[\"op\"]\n",
|
| 238 |
+
" dest, s1, s2 = ins[\"dest\"], ins[\"src1\"], ins[\"src2\"]\n",
|
| 239 |
+
" if op == \"STORE\":\n",
|
| 240 |
+
" lines.append(f\"STORE [{dest}] {_fmt_operand(s1)}\")\n",
|
| 241 |
+
" elif op == \"LOAD\":\n",
|
| 242 |
+
" lines.append(f\"{dest} = LOAD [{_fmt_operand(s1)}]\")\n",
|
| 243 |
+
" elif op == \"NOP\":\n",
|
| 244 |
+
" lines.append(\"NOP\")\n",
|
| 245 |
+
" else:\n",
|
| 246 |
+
" parts = [op, _fmt_operand(s1)]\n",
|
| 247 |
+
" if s2 is not None:\n",
|
| 248 |
+
" parts.append(_fmt_operand(s2))\n",
|
| 249 |
+
" lines.append(f\"{dest} = {' '.join(p for p in parts if p)}\")\n",
|
| 250 |
+
" return \"\\n\".join(lines)\n",
|
| 251 |
+
"\n",
|
| 252 |
+
"\n",
|
| 253 |
+
"def clean_nops(program: list[dict]) -> list[dict]:\n",
|
| 254 |
+
" return [deepcopy(ins) for ins in program if ins[\"op\"] != \"NOP\"]\n"
|
| 255 |
+
]
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"cell_type": "code",
|
| 259 |
+
"execution_count": null,
|
| 260 |
+
"id": "3c85a58b",
|
| 261 |
+
"metadata": {},
|
| 262 |
+
"outputs": [],
|
| 263 |
+
"source": [
|
| 264 |
+
"%%writefile /content/toyir/verifier.py\n",
|
| 265 |
+
"\"\"\"Strict equivalence verifier - anti-cheat for RL reward hacking.\"\"\"\n",
|
| 266 |
+
"from __future__ import annotations\n",
|
| 267 |
+
"from toy_vm import execute\n",
|
| 268 |
+
"\n",
|
| 269 |
+
"\n",
|
| 270 |
+
"def verify(original_program: list[dict],\n",
|
| 271 |
+
" optimized_program: list[dict],\n",
|
| 272 |
+
" initial_states: list[dict]) -> dict:\n",
|
| 273 |
+
" if not initial_states:\n",
|
| 274 |
+
" raise ValueError(\"verify requires at least one initial_state\")\n",
|
| 275 |
+
"\n",
|
| 276 |
+
" results = []\n",
|
| 277 |
+
" all_match = True\n",
|
| 278 |
+
" for st in initial_states:\n",
|
| 279 |
+
" r_o = execute(original_program, st)\n",
|
| 280 |
+
" r_p = execute(optimized_program, st)\n",
|
| 281 |
+
" mem_o = r_o[\"memory\"] if r_o[\"success\"] else None\n",
|
| 282 |
+
" mem_p = r_p[\"memory\"] if r_p[\"success\"] else None\n",
|
| 283 |
+
"\n",
|
| 284 |
+
" execution_errors = {}\n",
|
| 285 |
+
" if not r_o[\"success\"]:\n",
|
| 286 |
+
" execution_errors[\"original_error\"] = r_o[\"error\"]\n",
|
| 287 |
+
" if not r_p[\"success\"]:\n",
|
| 288 |
+
" execution_errors[\"optimized_error\"] = r_p[\"error\"]\n",
|
| 289 |
+
"\n",
|
| 290 |
+
" if execution_errors:\n",
|
| 291 |
+
" match = False\n",
|
| 292 |
+
" mismatches = [\"__execution_error__\"]\n",
|
| 293 |
+
" else:\n",
|
| 294 |
+
" keys = set(mem_o.keys()) | set(mem_p.keys())\n",
|
| 295 |
+
" mismatches = [k for k in keys if mem_o.get(k) != mem_p.get(k)]\n",
|
| 296 |
+
" match = len(mismatches) == 0\n",
|
| 297 |
+
"\n",
|
| 298 |
+
" if not match:\n",
|
| 299 |
+
" all_match = False\n",
|
| 300 |
+
" results.append({\n",
|
| 301 |
+
" \"initial_state\": st,\n",
|
| 302 |
+
" \"original_memory\": mem_o,\n",
|
| 303 |
+
" \"optimized_memory\": mem_p,\n",
|
| 304 |
+
" \"match\": match,\n",
|
| 305 |
+
" \"mismatches\": sorted(mismatches, key=lambda x: (isinstance(x, str), x)),\n",
|
| 306 |
+
" \"execution_errors\": execution_errors or None,\n",
|
| 307 |
+
" })\n",
|
| 308 |
+
" return {\"equivalent\": all_match, \"results\": results}\n"
|
| 309 |
+
]
|
| 310 |
+
},
|
| 311 |
+
{
|
| 312 |
+
"cell_type": "code",
|
| 313 |
+
"execution_count": null,
|
| 314 |
+
"id": "cd7f8fa2",
|
| 315 |
+
"metadata": {},
|
| 316 |
+
"outputs": [],
|
| 317 |
+
"source": [
|
| 318 |
+
"%%writefile /content/toyir/reward_utils.py\n",
|
| 319 |
+
"\"\"\"Reward signal: cycle-reduction metric for RL agent.\"\"\"\n",
|
| 320 |
+
"from __future__ import annotations\n",
|
| 321 |
+
"from toy_vm import execute\n",
|
| 322 |
+
"\n",
|
| 323 |
+
"\n",
|
| 324 |
+
"def compute_reduction(original_program: list[dict],\n",
|
| 325 |
+
" optimized_program: list[dict],\n",
|
| 326 |
+
" initial_state: dict) -> dict:\n",
|
| 327 |
+
" r_o = execute(original_program, initial_state)\n",
|
| 328 |
+
" r_p = execute(optimized_program, initial_state)\n",
|
| 329 |
+
"\n",
|
| 330 |
+
" if not (r_o[\"success\"] and r_p[\"success\"]):\n",
|
| 331 |
+
" return {\n",
|
| 332 |
+
" \"original_cycles\": r_o[\"cycles\"],\n",
|
| 333 |
+
" \"optimized_cycles\": r_p[\"cycles\"],\n",
|
| 334 |
+
" \"absolute_savings\": None,\n",
|
| 335 |
+
" \"relative_savings\": None,\n",
|
| 336 |
+
" \"success\": False,\n",
|
| 337 |
+
" \"error\": r_o[\"error\"] or r_p[\"error\"],\n",
|
| 338 |
+
" }\n",
|
| 339 |
+
"\n",
|
| 340 |
+
" oc, pc = r_o[\"cycles\"], r_p[\"cycles\"]\n",
|
| 341 |
+
" rel = 0.0 if oc == 0 else (oc - pc) / oc\n",
|
| 342 |
+
" rel = max(-1.0, min(1.0, rel))\n",
|
| 343 |
+
" return {\n",
|
| 344 |
+
" \"original_cycles\": oc,\n",
|
| 345 |
+
" \"optimized_cycles\": pc,\n",
|
| 346 |
+
" \"absolute_savings\": oc - pc,\n",
|
| 347 |
+
" \"relative_savings\": rel,\n",
|
| 348 |
+
" \"success\": True,\n",
|
| 349 |
+
" \"error\": None,\n",
|
| 350 |
+
" }\n"
|
| 351 |
+
]
|
| 352 |
+
},
|
| 353 |
+
{
|
| 354 |
+
"cell_type": "code",
|
| 355 |
+
"execution_count": null,
|
| 356 |
+
"id": "4f2a941c",
|
| 357 |
+
"metadata": {},
|
| 358 |
+
"outputs": [],
|
| 359 |
+
"source": [
|
| 360 |
+
"%%writefile /content/toyir/test_vm.py\n",
|
| 361 |
+
"\"\"\"Pytest suite covering VM, verifier, reward, and RL exploit guardrails.\"\"\"\n",
|
| 362 |
+
"from __future__ import annotations\n",
|
| 363 |
+
"import random\n",
|
| 364 |
+
"import pytest\n",
|
| 365 |
+
"from toy_vm import (\n",
|
| 366 |
+
" validate_ir, execute, count_cycles, profile, dump_ir, clean_nops, OP_ORDER,\n",
|
| 367 |
+
")\n",
|
| 368 |
+
"from verifier import verify\n",
|
| 369 |
+
"from reward_utils import compute_reduction\n",
|
| 370 |
+
"\n",
|
| 371 |
+
"\n",
|
| 372 |
+
"def I(op, dest=None, src1=None, src2=None):\n",
|
| 373 |
+
" return {\"op\": op, \"dest\": dest, \"src1\": src1, \"src2\": src2}\n",
|
| 374 |
+
"\n",
|
| 375 |
+
"\n",
|
| 376 |
+
"def test_const_fold_equivalence():\n",
|
| 377 |
+
" orig = [I(\"CONST\", \"t0\", 5), I(\"CONST\", \"t1\", 7), I(\"ADD\", \"t2\", \"t0\", \"t1\"),\n",
|
| 378 |
+
" I(\"CONST\", \"addr\", 0), I(\"STORE\", \"addr\", \"t2\")]\n",
|
| 379 |
+
" opt = [I(\"CONST\", \"t2\", 12), I(\"CONST\", \"addr\", 0), I(\"STORE\", \"addr\", \"t2\")]\n",
|
| 380 |
+
" res = verify(orig, opt, [{\"variables\": {}, \"memory\": {}}])\n",
|
| 381 |
+
" assert res[\"equivalent\"]\n",
|
| 382 |
+
" red = compute_reduction(orig, opt, {\"variables\": {}, \"memory\": {}})\n",
|
| 383 |
+
" assert red[\"absolute_savings\"] > 0\n",
|
| 384 |
+
"\n",
|
| 385 |
+
"\n",
|
| 386 |
+
"def test_dead_code_invisible():\n",
|
| 387 |
+
" orig = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 3),\n",
|
| 388 |
+
" I(\"MUL\", \"dead\", \"x\", 99), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 389 |
+
" opt = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 3), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 390 |
+
" res = verify(orig, opt, [{\"variables\": {}, \"memory\": {}}])\n",
|
| 391 |
+
" assert res[\"equivalent\"]\n",
|
| 392 |
+
"\n",
|
| 393 |
+
"\n",
|
| 394 |
+
"def test_fold_then_dce():\n",
|
| 395 |
+
" orig = [I(\"CONST\", \"a\", 2), I(\"CONST\", \"b\", 3), I(\"ADD\", \"c\", \"a\", \"b\"),\n",
|
| 396 |
+
" I(\"MUL\", \"d\", \"c\", 10), I(\"CONST\", \"addr\", 0), I(\"STORE\", \"addr\", \"d\")]\n",
|
| 397 |
+
" opt = [I(\"CONST\", \"d\", 50), I(\"CONST\", \"addr\", 0), I(\"STORE\", \"addr\", \"d\")]\n",
|
| 398 |
+
" res = verify(orig, opt, [{\"variables\": {}, \"memory\": {}}])\n",
|
| 399 |
+
" assert res[\"equivalent\"]\n",
|
| 400 |
+
" red = compute_reduction(orig, opt, {\"variables\": {}, \"memory\": {}})\n",
|
| 401 |
+
" assert red[\"original_cycles\"] > red[\"optimized_cycles\"]\n",
|
| 402 |
+
"\n",
|
| 403 |
+
"\n",
|
| 404 |
+
"def test_strength_reduction():\n",
|
| 405 |
+
" orig = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 7),\n",
|
| 406 |
+
" I(\"MUL\", \"y\", \"x\", 2), I(\"STORE\", \"addr\", \"y\")]\n",
|
| 407 |
+
" opt = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 7),\n",
|
| 408 |
+
" I(\"ADD\", \"y\", \"x\", \"x\"), I(\"STORE\", \"addr\", \"y\")]\n",
|
| 409 |
+
" res = verify(orig, opt, [{\"variables\": {}, \"memory\": {}}])\n",
|
| 410 |
+
" assert res[\"equivalent\"]\n",
|
| 411 |
+
" red = compute_reduction(orig, opt, {\"variables\": {}, \"memory\": {}})\n",
|
| 412 |
+
" assert red[\"absolute_savings\"] > 0\n",
|
| 413 |
+
"\n",
|
| 414 |
+
"\n",
|
| 415 |
+
"def test_already_optimal():\n",
|
| 416 |
+
" p = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 1), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 417 |
+
" red = compute_reduction(p, p, {\"variables\": {}, \"memory\": {}})\n",
|
| 418 |
+
" assert red[\"absolute_savings\"] == 0\n",
|
| 419 |
+
" assert red[\"relative_savings\"] == 0.0\n",
|
| 420 |
+
"\n",
|
| 421 |
+
"\n",
|
| 422 |
+
"def test_div_by_zero():\n",
|
| 423 |
+
" p = [I(\"CONST\", \"a\", 10), I(\"CONST\", \"b\", 0), I(\"DIV\", \"c\", \"a\", \"b\")]\n",
|
| 424 |
+
" r = execute(p, {\"variables\": {}, \"memory\": {}})\n",
|
| 425 |
+
" assert r[\"success\"] is False\n",
|
| 426 |
+
" assert \"zero\" in r[\"error\"].lower()\n",
|
| 427 |
+
"\n",
|
| 428 |
+
"\n",
|
| 429 |
+
"def test_hardcoded_exploit_caught():\n",
|
| 430 |
+
" orig = [I(\"CONST\", \"addr\", 0), I(\"LOAD\", \"x\", \"in_addr\"),\n",
|
| 431 |
+
" I(\"MUL\", \"y\", \"x\", 3), I(\"STORE\", \"addr\", \"y\")]\n",
|
| 432 |
+
" opt = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"y\", 42), I(\"STORE\", \"addr\", \"y\")]\n",
|
| 433 |
+
" rng = random.Random(0)\n",
|
| 434 |
+
" states = [{\"variables\": {\"in_addr\": 1}, \"memory\": {1: rng.randint(0, 100)}} for _ in range(5)]\n",
|
| 435 |
+
" res = verify(orig, opt, states)\n",
|
| 436 |
+
" assert res[\"equivalent\"] is False\n",
|
| 437 |
+
" assert any(not r[\"match\"] for r in res[\"results\"])\n",
|
| 438 |
+
"\n",
|
| 439 |
+
"\n",
|
| 440 |
+
"def test_nop_zero_cost():\n",
|
| 441 |
+
" p = [I(\"NOP\"), I(\"CONST\", \"x\", 1), I(\"NOP\")]\n",
|
| 442 |
+
" assert count_cycles(p) == 1\n",
|
| 443 |
+
" r = execute(p, {\"variables\": {}, \"memory\": {}})\n",
|
| 444 |
+
" assert r[\"success\"] and r[\"cycles\"] == 1\n",
|
| 445 |
+
"\n",
|
| 446 |
+
"\n",
|
| 447 |
+
"def test_load_store_non_int_address():\n",
|
| 448 |
+
" p = [I(\"COPY\", \"addr\", \"bad\"), I(\"LOAD\", \"x\", \"addr\")]\n",
|
| 449 |
+
" r = execute(p, {\"variables\": {\"bad\": \"notint\"}, \"memory\": {}})\n",
|
| 450 |
+
" assert r[\"success\"] is False\n",
|
| 451 |
+
"\n",
|
| 452 |
+
"\n",
|
| 453 |
+
"def test_validate_ir_malformed():\n",
|
| 454 |
+
" assert not validate_ir([I(\"FOOBAR\", \"t\", 1, 2)])[\"valid\"]\n",
|
| 455 |
+
" assert not validate_ir([{\"op\": \"ADD\", \"dest\": \"x\"}])[\"valid\"]\n",
|
| 456 |
+
" assert not validate_ir([I(\"CONST\", 123, 1)])[\"valid\"]\n",
|
| 457 |
+
" assert not validate_ir([I(\"STORE\", None, \"x\")])[\"valid\"]\n",
|
| 458 |
+
" assert not validate_ir([I(\"LOAD\", \"x\", 42)])[\"valid\"]\n",
|
| 459 |
+
" assert not validate_ir([I(\"NOP\", \"x\", 1)])[\"valid\"]\n",
|
| 460 |
+
" assert not validate_ir([I(\"ADD\", \"x\", \"a\", None)])[\"valid\"]\n",
|
| 461 |
+
" assert not validate_ir([I(\"LOAD\", \"x\", \"addr\", 9)])[\"valid\"]\n",
|
| 462 |
+
" assert not validate_ir([I(\"STORE\", \"addr\", \"x\", 9)])[\"valid\"]\n",
|
| 463 |
+
" assert validate_ir([I(\"CONST\", \"x\", 1)])[\"valid\"]\n",
|
| 464 |
+
"\n",
|
| 465 |
+
"\n",
|
| 466 |
+
"def test_dump_ir_format():\n",
|
| 467 |
+
" p = [I(\"CONST\", \"t0\", 5), I(\"ADD\", \"t1\", \"t0\", \"a\"),\n",
|
| 468 |
+
" I(\"MUL\", \"t2\", \"t1\", 3), I(\"STORE\", \"addr0\", \"t2\")]\n",
|
| 469 |
+
" s = dump_ir(p)\n",
|
| 470 |
+
" lines = s.split(\"\\n\")\n",
|
| 471 |
+
" assert lines[0] == \"// OBSERVABLE OUT: mem[addr0]\"\n",
|
| 472 |
+
" assert lines[1] == \"t0 = CONST 5\"\n",
|
| 473 |
+
" assert lines[2] == \"t1 = ADD t0 a\"\n",
|
| 474 |
+
" assert lines[3] == \"t2 = MUL t1 3\"\n",
|
| 475 |
+
" assert lines[4] == \"STORE [addr0] t2\"\n",
|
| 476 |
+
" assert len(lines) == 5\n",
|
| 477 |
+
"\n",
|
| 478 |
+
"\n",
|
| 479 |
+
"def test_dump_ir_multi_store_header_order():\n",
|
| 480 |
+
" p = [I(\"CONST\", \"a\", 0), I(\"CONST\", \"b\", 1),\n",
|
| 481 |
+
" I(\"STORE\", \"a\", 5), I(\"STORE\", \"b\", 6), I(\"STORE\", \"a\", 7)]\n",
|
| 482 |
+
" s = dump_ir(p)\n",
|
| 483 |
+
" assert s.split(\"\\n\")[0] == \"// OBSERVABLE OUT: mem[a], mem[b]\"\n",
|
| 484 |
+
"\n",
|
| 485 |
+
"\n",
|
| 486 |
+
"def test_clean_nops():\n",
|
| 487 |
+
" p = [I(\"NOP\"), I(\"CONST\", \"x\", 1), I(\"NOP\"), I(\"CONST\", \"y\", 2), I(\"NOP\")]\n",
|
| 488 |
+
" out = clean_nops(p)\n",
|
| 489 |
+
" assert len(out) == 2\n",
|
| 490 |
+
" assert all(ins[\"op\"] != \"NOP\" for ins in out)\n",
|
| 491 |
+
"\n",
|
| 492 |
+
"\n",
|
| 493 |
+
"def test_verify_mismatches():\n",
|
| 494 |
+
" orig = [I(\"CONST\", \"a0\", 0), I(\"CONST\", \"a1\", 1),\n",
|
| 495 |
+
" I(\"CONST\", \"x\", 5), I(\"CONST\", \"y\", 9),\n",
|
| 496 |
+
" I(\"STORE\", \"a0\", \"x\"), I(\"STORE\", \"a1\", \"y\")]\n",
|
| 497 |
+
" opt = [I(\"CONST\", \"a0\", 0), I(\"CONST\", \"a1\", 1),\n",
|
| 498 |
+
" I(\"CONST\", \"x\", 5), I(\"CONST\", \"y\", 8),\n",
|
| 499 |
+
" I(\"STORE\", \"a0\", \"x\"), I(\"STORE\", \"a1\", \"y\")]\n",
|
| 500 |
+
" res = verify(orig, opt, [{\"variables\": {}, \"memory\": {}}])\n",
|
| 501 |
+
" assert res[\"equivalent\"] is False\n",
|
| 502 |
+
" assert res[\"results\"][0][\"mismatches\"] == [1]\n",
|
| 503 |
+
"\n",
|
| 504 |
+
"\n",
|
| 505 |
+
"def test_profile_counts_and_ordering():\n",
|
| 506 |
+
" p = [I(\"CONST\", \"x\", 1), I(\"ADD\", \"y\", \"x\", 2), I(\"MUL\", \"z\", \"y\", 3)]\n",
|
| 507 |
+
" pr = profile(p)\n",
|
| 508 |
+
" assert pr[\"n_instructions\"] == 3\n",
|
| 509 |
+
" assert pr[\"n_const\"] == 1 and pr[\"n_add\"] == 1 and pr[\"n_mul\"] == 1\n",
|
| 510 |
+
" expected = [\"n_instructions\"] + [f\"n_{op.lower()}\" for op in OP_ORDER]\n",
|
| 511 |
+
" assert list(pr.keys()) == expected\n",
|
| 512 |
+
"\n",
|
| 513 |
+
"\n",
|
| 514 |
+
"def test_no_input_mutation():\n",
|
| 515 |
+
" p = [I(\"CONST\", \"x\", 1), I(\"CONST\", \"addr\", 0), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 516 |
+
" st = {\"variables\": {}, \"memory\": {}}\n",
|
| 517 |
+
" snap = {\"variables\": dict(st[\"variables\"]), \"memory\": dict(st[\"memory\"])}\n",
|
| 518 |
+
" execute(p, st)\n",
|
| 519 |
+
" assert st == snap\n",
|
| 520 |
+
"\n",
|
| 521 |
+
"\n",
|
| 522 |
+
"def test_clean_nops_no_aliasing():\n",
|
| 523 |
+
" p = [I(\"CONST\", \"x\", 1), I(\"NOP\")]\n",
|
| 524 |
+
" out = clean_nops(p)\n",
|
| 525 |
+
" out[0][\"op\"] = \"MUL\"\n",
|
| 526 |
+
" assert p[0][\"op\"] == \"CONST\"\n",
|
| 527 |
+
"\n",
|
| 528 |
+
"\n",
|
| 529 |
+
"def test_verify_rejects_empty_states():\n",
|
| 530 |
+
" with pytest.raises(ValueError):\n",
|
| 531 |
+
" verify([I(\"NOP\")], [I(\"NOP\")], [])\n",
|
| 532 |
+
"\n",
|
| 533 |
+
"\n",
|
| 534 |
+
"def test_verify_surfaces_execution_errors():\n",
|
| 535 |
+
" good = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 1), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 536 |
+
" bad = [I(\"LOAD\", \"x\", \"missing_addr\")]\n",
|
| 537 |
+
" res = verify(good, bad, [{\"variables\": {}, \"memory\": {}}])\n",
|
| 538 |
+
" assert res[\"equivalent\"] is False\n",
|
| 539 |
+
" assert res[\"results\"][0][\"mismatches\"] == [\"__execution_error__\"]\n",
|
| 540 |
+
" assert res[\"results\"][0][\"execution_errors\"][\"optimized_error\"] is not None\n",
|
| 541 |
+
" assert \"original_error\" not in res[\"results\"][0][\"execution_errors\"]\n",
|
| 542 |
+
"\n",
|
| 543 |
+
"\n",
|
| 544 |
+
"def test_execute_rejects_bad_initial_state_shape():\n",
|
| 545 |
+
" r = execute([I(\"CONST\", \"x\", 1)], \"not-a-dict\")\n",
|
| 546 |
+
" assert r[\"success\"] is False\n",
|
| 547 |
+
" assert \"initial_state\" in r[\"error\"]\n",
|
| 548 |
+
"\n",
|
| 549 |
+
"\n",
|
| 550 |
+
"def test_compute_reduction_failure_path():\n",
|
| 551 |
+
" orig = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 1), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 552 |
+
" bad = [I(\"CONST\", \"a\", 1), I(\"CONST\", \"b\", 0), I(\"DIV\", \"c\", \"a\", \"b\")]\n",
|
| 553 |
+
" red = compute_reduction(orig, bad, {\"variables\": {}, \"memory\": {}})\n",
|
| 554 |
+
" assert red[\"success\"] is False\n",
|
| 555 |
+
" assert red[\"relative_savings\"] is None\n",
|
| 556 |
+
" assert red[\"absolute_savings\"] is None\n",
|
| 557 |
+
" assert \"zero\" in red[\"error\"].lower()\n",
|
| 558 |
+
"\n",
|
| 559 |
+
"\n",
|
| 560 |
+
"def test_relative_savings_clamped_on_slowdown():\n",
|
| 561 |
+
" fast = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 1), I(\"STORE\", \"addr\", \"x\")]\n",
|
| 562 |
+
" # slower variant: extra dead MULs balloon the cycle count\n",
|
| 563 |
+
" slow = [I(\"CONST\", \"addr\", 0), I(\"CONST\", \"x\", 1)]\n",
|
| 564 |
+
" slow += [I(\"MUL\", \"junk\", \"x\", 2)] * 50\n",
|
| 565 |
+
" slow += [I(\"STORE\", \"addr\", \"x\")]\n",
|
| 566 |
+
" red = compute_reduction(fast, slow, {\"variables\": {}, \"memory\": {}})\n",
|
| 567 |
+
" assert red[\"absolute_savings\"] < 0\n",
|
| 568 |
+
" assert red[\"relative_savings\"] == -1.0 # clamped\n"
|
| 569 |
+
]
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"cell_type": "code",
|
| 573 |
+
"execution_count": null,
|
| 574 |
+
"id": "e6b83243",
|
| 575 |
+
"metadata": {},
|
| 576 |
+
"outputs": [],
|
| 577 |
+
"source": [
|
| 578 |
+
"# ==== CELL 6: Push to Drive ====\n",
|
| 579 |
+
"import shutil, os\n",
|
| 580 |
+
"for f in os.listdir(LOCAL_DIR):\n",
|
| 581 |
+
" if f.endswith(\".py\"):\n",
|
| 582 |
+
" shutil.copy2(os.path.join(LOCAL_DIR, f), os.path.join(DRIVE_DIR, f))\n",
|
| 583 |
+
"print(\"Saved to Drive:\", sorted(os.listdir(DRIVE_DIR)))\n"
|
| 584 |
+
]
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"cell_type": "code",
|
| 588 |
+
"execution_count": null,
|
| 589 |
+
"id": "5675f9a0",
|
| 590 |
+
"metadata": {},
|
| 591 |
+
"outputs": [],
|
| 592 |
+
"source": [
|
| 593 |
+
"# ==== CELL 7: Run tests ====\n",
|
| 594 |
+
"import subprocess\n",
|
| 595 |
+
"res = subprocess.run(\n",
|
| 596 |
+
" [\"python\", \"-m\", \"pytest\", \"-v\", \"test_vm.py\"],\n",
|
| 597 |
+
" cwd=LOCAL_DIR, capture_output=True, text=True,\n",
|
| 598 |
+
")\n",
|
| 599 |
+
"print(res.stdout)\n",
|
| 600 |
+
"print(res.stderr)\n",
|
| 601 |
+
"assert res.returncode == 0, \"Tests failed\"\n"
|
| 602 |
+
]
|
| 603 |
+
},
|
| 604 |
+
{
|
| 605 |
+
"cell_type": "code",
|
| 606 |
+
"execution_count": null,
|
| 607 |
+
"id": "1a500bb3",
|
| 608 |
+
"metadata": {},
|
| 609 |
+
"outputs": [],
|
| 610 |
+
"source": [
|
| 611 |
+
"# ==== CELL 8: Smoke demo ====\n",
|
| 612 |
+
"import importlib, toy_vm, verifier, reward_utils\n",
|
| 613 |
+
"importlib.reload(toy_vm); importlib.reload(verifier); importlib.reload(reward_utils)\n",
|
| 614 |
+
"from toy_vm import dump_ir\n",
|
| 615 |
+
"from reward_utils import compute_reduction\n",
|
| 616 |
+
"from verifier import verify\n",
|
| 617 |
+
"\n",
|
| 618 |
+
"orig = [\n",
|
| 619 |
+
" {\"op\":\"CONST\",\"dest\":\"addr\",\"src1\":0,\"src2\":None},\n",
|
| 620 |
+
" {\"op\":\"CONST\",\"dest\":\"a\",\"src1\":2,\"src2\":None},\n",
|
| 621 |
+
" {\"op\":\"CONST\",\"dest\":\"b\",\"src1\":3,\"src2\":None},\n",
|
| 622 |
+
" {\"op\":\"ADD\",\"dest\":\"c\",\"src1\":\"a\",\"src2\":\"b\"},\n",
|
| 623 |
+
" {\"op\":\"MUL\",\"dest\":\"d\",\"src1\":\"c\",\"src2\":2},\n",
|
| 624 |
+
" {\"op\":\"MUL\",\"dest\":\"dead\",\"src1\":\"d\",\"src2\":99},\n",
|
| 625 |
+
" {\"op\":\"STORE\",\"dest\":\"addr\",\"src1\":\"d\",\"src2\":None},\n",
|
| 626 |
+
"]\n",
|
| 627 |
+
"opt = [\n",
|
| 628 |
+
" {\"op\":\"CONST\",\"dest\":\"addr\",\"src1\":0,\"src2\":None},\n",
|
| 629 |
+
" {\"op\":\"CONST\",\"dest\":\"d\",\"src1\":10,\"src2\":None},\n",
|
| 630 |
+
" {\"op\":\"STORE\",\"dest\":\"addr\",\"src1\":\"d\",\"src2\":None},\n",
|
| 631 |
+
"]\n",
|
| 632 |
+
"\n",
|
| 633 |
+
"print(dump_ir(orig)); print(\"---\"); print(dump_ir(opt)); print(\"---\")\n",
|
| 634 |
+
"print(compute_reduction(orig, opt, {\"variables\":{},\"memory\":{}}))\n",
|
| 635 |
+
"print(\"equivalent:\", verify(orig, opt, [{\"variables\":{},\"memory\":{}}])[\"equivalent\"])\n"
|
| 636 |
+
]
|
| 637 |
+
}
|
| 638 |
+
],
|
| 639 |
+
"metadata": {
|
| 640 |
+
"kernelspec": {
|
| 641 |
+
"display_name": "Python 3",
|
| 642 |
+
"language": "python",
|
| 643 |
+
"name": "python3"
|
| 644 |
+
},
|
| 645 |
+
"language_info": {
|
| 646 |
+
"name": "python"
|
| 647 |
+
}
|
| 648 |
+
},
|
| 649 |
+
"nbformat": 4,
|
| 650 |
+
"nbformat_minor": 5
|
| 651 |
+
}
|
space/metahack1 (1).ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
space/space/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
space/space/metahack1 (1).ipynb
ADDED
|
@@ -0,0 +1,1379 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 0,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"colab": {
|
| 6 |
+
"provenance": [],
|
| 7 |
+
"gpuType": "T4"
|
| 8 |
+
},
|
| 9 |
+
"kernelspec": {
|
| 10 |
+
"name": "python3",
|
| 11 |
+
"display_name": "Python 3"
|
| 12 |
+
},
|
| 13 |
+
"language_info": {
|
| 14 |
+
"name": "python"
|
| 15 |
+
},
|
| 16 |
+
"accelerator": "GPU"
|
| 17 |
+
},
|
| 18 |
+
"cells": [
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"source": [
|
| 22 |
+
"## Design Assumptions (do not violate)\n",
|
| 23 |
+
"\n",
|
| 24 |
+
"# 1. **DCE never eliminates STOREs.** They define program output (final mem state).\n",
|
| 25 |
+
"# 2. **Addresses are distinct by construction.** Generator allocates each address variable to a unique integer; no aliasing.\n",
|
| 26 |
+
"# 3. **CF refuses to fold DIV by zero.** If src2 == 0 on a DIV op, leave instruction unchanged.\n",
|
| 27 |
+
"# 4. **Generator never emits DIV by literal zero.** When DIV is generated, src2 is always a non-zero constant or a variable known to be non-zero.\n",
|
| 28 |
+
"# # 5. **Integer arithmetic only.** No floats anywhere — avoids equivalence-check precision issues.\n",
|
| 29 |
+
"# 6. Generator declares `observable_addrs` per program — verifier compares only these mem entries.\n",
|
| 30 |
+
"# 7. State translator annotates observable outputs at top of dump.\n",
|
| 31 |
+
"# 8. Reward distinguishes broken (-1000) from valid-but-worse (small negative) — Harshal's formula.\n",
|
| 32 |
+
"# 9. Multi-input verification: 3-5 random initial states, all must match.\n",
|
| 33 |
+
"# 10. Integer division uses Python floor division (//). Aarush's VM must match."
|
| 34 |
+
],
|
| 35 |
+
"metadata": {
|
| 36 |
+
"id": "_XI5jT2Ibvrf"
|
| 37 |
+
},
|
| 38 |
+
"execution_count": 2,
|
| 39 |
+
"outputs": []
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"cell_type": "code",
|
| 43 |
+
"execution_count": 11,
|
| 44 |
+
"metadata": {
|
| 45 |
+
"id": "j6CQ327KWXwr"
|
| 46 |
+
},
|
| 47 |
+
"outputs": [],
|
| 48 |
+
"source": [
|
| 49 |
+
"# === TAC Schema v1.0 (LOCKED with Role 1 / Aarush) ===\n",
|
| 50 |
+
"# Reverse passes deferred to stretch goal — not in initial action space.\n",
|
| 51 |
+
"\n",
|
| 52 |
+
"OPS = [\"CONST\", \"ADD\", \"SUB\", \"MUL\", \"DIV\", \"LOAD\", \"STORE\", \"NOP\"]\n",
|
| 53 |
+
"\n",
|
| 54 |
+
"CYCLE_COSTS = {\n",
|
| 55 |
+
" \"CONST\": 1,\n",
|
| 56 |
+
" \"ADD\": 1,\n",
|
| 57 |
+
" \"SUB\": 1,\n",
|
| 58 |
+
" \"MUL\": 3,\n",
|
| 59 |
+
" \"DIV\": 5,\n",
|
| 60 |
+
" \"LOAD\": 4,\n",
|
| 61 |
+
" \"STORE\": 4,\n",
|
| 62 |
+
" \"NOP\": 0,\n",
|
| 63 |
+
"}\n",
|
| 64 |
+
"\n",
|
| 65 |
+
"# Instruction shape: {\"op\": str, \"dest\": str|None, \"src1\": Any, \"src2\": Any}\n",
|
| 66 |
+
"# Operands: str = variable name, int = literal constant, None = unused\n",
|
| 67 |
+
"#\n",
|
| 68 |
+
"# Op semantics:\n",
|
| 69 |
+
"# CONST: dest = src1 (src1 is int literal, src2 = None)\n",
|
| 70 |
+
"# ADD/SUB/MUL/DIV: dest = src1 OP src2 (src1, src2 are var names or int literals)\n",
|
| 71 |
+
"# LOAD: dest = mem[src1] (src1 is a var holding an address)\n",
|
| 72 |
+
"# STORE: mem[dest] = src1 (dest is a var holding an address)\n",
|
| 73 |
+
"# NOP: no-op (all fields None)\n",
|
| 74 |
+
"#\n",
|
| 75 |
+
"# Program output (for equivalence check) = final memory state (mem dict).\n",
|
| 76 |
+
"# Programs ship as: (initial_vars: dict, initial_mem: dict, instructions: list[dict])"
|
| 77 |
+
]
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"cell_type": "code",
|
| 81 |
+
"source": [
|
| 82 |
+
"import random\n",
|
| 83 |
+
"\n",
|
| 84 |
+
"def generate_level_1():\n",
|
| 85 |
+
" \"\"\"\n",
|
| 86 |
+
" Generate a Level 1 Toy-IR program.\n",
|
| 87 |
+
"\n",
|
| 88 |
+
" Characteristics:\n",
|
| 89 |
+
" - 4-6 instructions\n",
|
| 90 |
+
" - 2-3 CONST ops with literal values\n",
|
| 91 |
+
" - 1-2 arithmetic ops on those constants (foldable by CF)\n",
|
| 92 |
+
" - 0-1 dead variables (killable by DCE)\n",
|
| 93 |
+
" - Exactly 1 STORE at the end so the program has an observable output\n",
|
| 94 |
+
"\n",
|
| 95 |
+
" Returns:\n",
|
| 96 |
+
" dict with keys: initial_vars, initial_mem, instructions, observable_addrs\n",
|
| 97 |
+
" \"\"\"\n",
|
| 98 |
+
" instructions = []\n",
|
| 99 |
+
" var_counter = 0\n",
|
| 100 |
+
"\n",
|
| 101 |
+
" def new_var():\n",
|
| 102 |
+
" nonlocal var_counter\n",
|
| 103 |
+
" name = f\"v{var_counter}\"\n",
|
| 104 |
+
" var_counter += 1\n",
|
| 105 |
+
" return name\n",
|
| 106 |
+
"\n",
|
| 107 |
+
" # Step 1: Generate 2-3 constant assignments\n",
|
| 108 |
+
" num_consts = random.randint(2, 3)\n",
|
| 109 |
+
" const_vars = []\n",
|
| 110 |
+
" for _ in range(num_consts):\n",
|
| 111 |
+
" var = new_var()\n",
|
| 112 |
+
" value = random.randint(1, 10)\n",
|
| 113 |
+
" instructions.append({\"op\": \"CONST\", \"dest\": var, \"src1\": value, \"src2\": None})\n",
|
| 114 |
+
" const_vars.append(var)\n",
|
| 115 |
+
"\n",
|
| 116 |
+
" # Step 2: Generate 1-2 arithmetic ops using those constants\n",
|
| 117 |
+
" num_arith = random.randint(1, 2)\n",
|
| 118 |
+
" last_result = None\n",
|
| 119 |
+
" for _ in range(num_arith):\n",
|
| 120 |
+
" op = random.choice([\"ADD\", \"MUL\"])\n",
|
| 121 |
+
" src1 = random.choice(const_vars)\n",
|
| 122 |
+
" src2 = random.choice(const_vars)\n",
|
| 123 |
+
" dest = new_var()\n",
|
| 124 |
+
" instructions.append({\"op\": op, \"dest\": dest, \"src1\": src1, \"src2\": src2})\n",
|
| 125 |
+
" last_result = dest\n",
|
| 126 |
+
" const_vars.append(dest)\n",
|
| 127 |
+
"\n",
|
| 128 |
+
" # Step 3: Optionally add 1 dead variable (50% chance)\n",
|
| 129 |
+
" if random.random() < 0.5:\n",
|
| 130 |
+
" dead_var = new_var()\n",
|
| 131 |
+
" dead_value = random.randint(1, 10)\n",
|
| 132 |
+
" instructions.append({\"op\": \"CONST\", \"dest\": dead_var, \"src1\": dead_value, \"src2\": None})\n",
|
| 133 |
+
" # Note: dead_var is intentionally never used — DCE should catch it.\n",
|
| 134 |
+
"\n",
|
| 135 |
+
" # Step 4: Add a STORE at the end so the program has observable output\n",
|
| 136 |
+
" initial_vars = {\"addr0\": 0}\n",
|
| 137 |
+
" instructions.append({\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": last_result, \"src2\": None})\n",
|
| 138 |
+
"\n",
|
| 139 |
+
" initial_mem = {}\n",
|
| 140 |
+
"\n",
|
| 141 |
+
" return {\n",
|
| 142 |
+
" \"initial_vars\": initial_vars,\n",
|
| 143 |
+
" \"initial_mem\": initial_mem,\n",
|
| 144 |
+
" \"instructions\": instructions,\n",
|
| 145 |
+
" \"observable_addrs\": [0], # Aarush's verifier compares only these mem entries\n",
|
| 146 |
+
" }\n",
|
| 147 |
+
"\n",
|
| 148 |
+
"\n",
|
| 149 |
+
"# Sanity-check: generate a few programs and print them\n",
|
| 150 |
+
"for seed in [42, 1, 7, 99]:\n",
|
| 151 |
+
" random.seed(seed)\n",
|
| 152 |
+
" prog = generate_level_1()\n",
|
| 153 |
+
" print(f\"\\n=== seed={seed} ===\")\n",
|
| 154 |
+
" print(f\"initial_vars : {prog['initial_vars']}\")\n",
|
| 155 |
+
" print(f\"initial_mem : {prog['initial_mem']}\")\n",
|
| 156 |
+
" print(f\"observable_addrs : {prog['observable_addrs']}\")\n",
|
| 157 |
+
" print(f\"instructions ({len(prog['instructions'])}):\")\n",
|
| 158 |
+
" for i, instr in enumerate(prog['instructions']):\n",
|
| 159 |
+
" print(f\" {i}: {instr}\")"
|
| 160 |
+
],
|
| 161 |
+
"metadata": {
|
| 162 |
+
"colab": {
|
| 163 |
+
"base_uri": "https://localhost:8080/"
|
| 164 |
+
},
|
| 165 |
+
"id": "a86vD1OyWcB9",
|
| 166 |
+
"outputId": "2d6d4604-6dc1-4c29-af64-e41cf5717c0d"
|
| 167 |
+
},
|
| 168 |
+
"execution_count": 4,
|
| 169 |
+
"outputs": [
|
| 170 |
+
{
|
| 171 |
+
"output_type": "stream",
|
| 172 |
+
"name": "stdout",
|
| 173 |
+
"text": [
|
| 174 |
+
"\n",
|
| 175 |
+
"=== seed=42 ===\n",
|
| 176 |
+
"initial_vars : {'addr0': 0}\n",
|
| 177 |
+
"initial_mem : {}\n",
|
| 178 |
+
"observable_addrs : [0]\n",
|
| 179 |
+
"instructions (4):\n",
|
| 180 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 181 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 182 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 183 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 184 |
+
"\n",
|
| 185 |
+
"=== seed=1 ===\n",
|
| 186 |
+
"initial_vars : {'addr0': 0}\n",
|
| 187 |
+
"initial_mem : {}\n",
|
| 188 |
+
"observable_addrs : [0]\n",
|
| 189 |
+
"instructions (5):\n",
|
| 190 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 10, 'src2': None}\n",
|
| 191 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 2, 'src2': None}\n",
|
| 192 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v1', 'src2': 'v1'}\n",
|
| 193 |
+
" 3: {'op': 'MUL', 'dest': 'v3', 'src1': 'v2', 'src2': 'v1'}\n",
|
| 194 |
+
" 4: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 195 |
+
"\n",
|
| 196 |
+
"=== seed=7 ===\n",
|
| 197 |
+
"initial_vars : {'addr0': 0}\n",
|
| 198 |
+
"initial_mem : {}\n",
|
| 199 |
+
"observable_addrs : [0]\n",
|
| 200 |
+
"instructions (6):\n",
|
| 201 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 3, 'src2': None}\n",
|
| 202 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 7, 'src2': None}\n",
|
| 203 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 1, 'src2': None}\n",
|
| 204 |
+
" 3: {'op': 'ADD', 'dest': 'v3', 'src1': 'v1', 'src2': 'v2'}\n",
|
| 205 |
+
" 4: {'op': 'CONST', 'dest': 'v4', 'src1': 9, 'src2': None}\n",
|
| 206 |
+
" 5: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 207 |
+
"\n",
|
| 208 |
+
"=== seed=99 ===\n",
|
| 209 |
+
"initial_vars : {'addr0': 0}\n",
|
| 210 |
+
"initial_mem : {}\n",
|
| 211 |
+
"observable_addrs : [0]\n",
|
| 212 |
+
"instructions (5):\n",
|
| 213 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 7, 'src2': None}\n",
|
| 214 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 4, 'src2': None}\n",
|
| 215 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 10, 'src2': None}\n",
|
| 216 |
+
" 3: {'op': 'ADD', 'dest': 'v3', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 217 |
+
" 4: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n"
|
| 218 |
+
]
|
| 219 |
+
}
|
| 220 |
+
]
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"cell_type": "code",
|
| 224 |
+
"source": [
|
| 225 |
+
"def _resolve_operand(operand, known_constants):\n",
|
| 226 |
+
" \"\"\"\n",
|
| 227 |
+
" Given a TAC operand (string variable name or int literal),\n",
|
| 228 |
+
" return its concrete integer value if known, or None if unknown.\n",
|
| 229 |
+
" \"\"\"\n",
|
| 230 |
+
" if isinstance(operand, int):\n",
|
| 231 |
+
" return operand\n",
|
| 232 |
+
" if isinstance(operand, str) and operand in known_constants:\n",
|
| 233 |
+
" return known_constants[operand]\n",
|
| 234 |
+
" return None\n",
|
| 235 |
+
"\n",
|
| 236 |
+
"\n",
|
| 237 |
+
"def _compute(op, v1, v2):\n",
|
| 238 |
+
" \"\"\"Compute the result of a binary arithmetic op on two known integers.\"\"\"\n",
|
| 239 |
+
" if op == \"ADD\": return v1 + v2\n",
|
| 240 |
+
" if op == \"SUB\": return v1 - v2\n",
|
| 241 |
+
" if op == \"MUL\": return v1 * v2\n",
|
| 242 |
+
" if op == \"DIV\": return v1 // v2 # floor division (locked semantics)\n",
|
| 243 |
+
" raise ValueError(f\"_compute called with non-arithmetic op: {op}\")\n",
|
| 244 |
+
"\n",
|
| 245 |
+
"\n",
|
| 246 |
+
"def constant_folding(program):\n",
|
| 247 |
+
" \"\"\"\n",
|
| 248 |
+
" Forward pass that folds constant arithmetic into CONST ops, and\n",
|
| 249 |
+
" propagates known constants into instruction operands.\n",
|
| 250 |
+
"\n",
|
| 251 |
+
" Behavior:\n",
|
| 252 |
+
" - If both sources of an arithmetic op resolve to known integers,\n",
|
| 253 |
+
" replaces the instruction with a CONST holding the computed result.\n",
|
| 254 |
+
" - If only one source is known, still substitutes that known value\n",
|
| 255 |
+
" into the instruction (constant propagation), enabling downstream\n",
|
| 256 |
+
" passes (e.g., peephole) to recognize patterns like ADD-with-0 or MUL-by-1.\n",
|
| 257 |
+
" - Refuses to fold DIV by zero (Design Assumption #3).\n",
|
| 258 |
+
" - Always returns fresh dicts; never aliases input instructions.\n",
|
| 259 |
+
"\n",
|
| 260 |
+
" Args:\n",
|
| 261 |
+
" program: list of TAC instruction dicts (per locked schema).\n",
|
| 262 |
+
"\n",
|
| 263 |
+
" Returns:\n",
|
| 264 |
+
" new list of TAC instruction dicts. Always semantics-preserving.\n",
|
| 265 |
+
" Never raises, never returns None.\n",
|
| 266 |
+
" \"\"\"\n",
|
| 267 |
+
" known_constants = {}\n",
|
| 268 |
+
" new_program = []\n",
|
| 269 |
+
"\n",
|
| 270 |
+
" for instr in program:\n",
|
| 271 |
+
" # Always work on a copy — never alias input dicts\n",
|
| 272 |
+
" instr = instr.copy()\n",
|
| 273 |
+
" op = instr[\"op\"]\n",
|
| 274 |
+
" dest = instr[\"dest\"]\n",
|
| 275 |
+
"\n",
|
| 276 |
+
" if op == \"CONST\":\n",
|
| 277 |
+
" known_constants[dest] = instr[\"src1\"]\n",
|
| 278 |
+
" new_program.append(instr)\n",
|
| 279 |
+
"\n",
|
| 280 |
+
" elif op in (\"ADD\", \"SUB\", \"MUL\", \"DIV\"):\n",
|
| 281 |
+
" # === Constant propagation: substitute known constants into operands ===\n",
|
| 282 |
+
" if isinstance(instr[\"src1\"], str) and instr[\"src1\"] in known_constants:\n",
|
| 283 |
+
" instr[\"src1\"] = known_constants[instr[\"src1\"]]\n",
|
| 284 |
+
" if isinstance(instr[\"src2\"], str) and instr[\"src2\"] in known_constants:\n",
|
| 285 |
+
" instr[\"src2\"] = known_constants[instr[\"src2\"]]\n",
|
| 286 |
+
"\n",
|
| 287 |
+
" # === Try to fold ===\n",
|
| 288 |
+
" v1 = _resolve_operand(instr[\"src1\"], known_constants)\n",
|
| 289 |
+
" v2 = _resolve_operand(instr[\"src2\"], known_constants)\n",
|
| 290 |
+
"\n",
|
| 291 |
+
" if v1 is not None and v2 is not None:\n",
|
| 292 |
+
" # Both operands are known integers\n",
|
| 293 |
+
" if op == \"DIV\" and v2 == 0:\n",
|
| 294 |
+
" # Refuse to fold DIV by zero\n",
|
| 295 |
+
" new_program.append(instr)\n",
|
| 296 |
+
" known_constants.pop(dest, None)\n",
|
| 297 |
+
" else:\n",
|
| 298 |
+
" # Fold: replace with CONST\n",
|
| 299 |
+
" result = _compute(op, v1, v2)\n",
|
| 300 |
+
" new_program.append({\n",
|
| 301 |
+
" \"op\": \"CONST\",\n",
|
| 302 |
+
" \"dest\": dest,\n",
|
| 303 |
+
" \"src1\": result,\n",
|
| 304 |
+
" \"src2\": None,\n",
|
| 305 |
+
" })\n",
|
| 306 |
+
" known_constants[dest] = result\n",
|
| 307 |
+
" else:\n",
|
| 308 |
+
" # Can't fold (at least one operand unknown).\n",
|
| 309 |
+
" # Instruction may still have been mutated by propagation above.\n",
|
| 310 |
+
" new_program.append(instr)\n",
|
| 311 |
+
" known_constants.pop(dest, None)\n",
|
| 312 |
+
"\n",
|
| 313 |
+
" elif op == \"LOAD\":\n",
|
| 314 |
+
" # Memory reads aren't statically resolvable\n",
|
| 315 |
+
" new_program.append(instr)\n",
|
| 316 |
+
" known_constants.pop(dest, None)\n",
|
| 317 |
+
"\n",
|
| 318 |
+
" elif op in (\"STORE\", \"NOP\"):\n",
|
| 319 |
+
" # No dest tracking needed.\n",
|
| 320 |
+
" # Note: we COULD propagate src1 into a STORE for downstream readability,\n",
|
| 321 |
+
" # but the cycle cost is unchanged and the executor handles vars fine.\n",
|
| 322 |
+
" # Leave STORE alone — keeps the code minimal.\n",
|
| 323 |
+
" new_program.append(instr)\n",
|
| 324 |
+
"\n",
|
| 325 |
+
" else:\n",
|
| 326 |
+
" # Unknown op — defensive pass-through\n",
|
| 327 |
+
" new_program.append(instr)\n",
|
| 328 |
+
"\n",
|
| 329 |
+
" return new_program"
|
| 330 |
+
],
|
| 331 |
+
"metadata": {
|
| 332 |
+
"id": "CGk8Fz4CZA3t"
|
| 333 |
+
},
|
| 334 |
+
"execution_count": 5,
|
| 335 |
+
"outputs": []
|
| 336 |
+
},
|
| 337 |
+
{
|
| 338 |
+
"cell_type": "code",
|
| 339 |
+
"source": [
|
| 340 |
+
"# === Sanity tests for constant_folding ===\n",
|
| 341 |
+
"\n",
|
| 342 |
+
"# Test 1: simple fold — ADD of two CONSTs\n",
|
| 343 |
+
"test1 = [\n",
|
| 344 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 3, \"src2\": None},\n",
|
| 345 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 5, \"src2\": None},\n",
|
| 346 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"},\n",
|
| 347 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 348 |
+
"]\n",
|
| 349 |
+
"result1 = constant_folding(test1)\n",
|
| 350 |
+
"print(\"Test 1 (simple ADD fold):\")\n",
|
| 351 |
+
"for i, instr in enumerate(result1): print(f\" {i}: {instr}\")\n",
|
| 352 |
+
"# Expected: instruction 2 becomes CONST c = 8\n",
|
| 353 |
+
"\n",
|
| 354 |
+
"# Test 2: chained fold — second op uses first op's folded result\n",
|
| 355 |
+
"test2 = [\n",
|
| 356 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 3, \"src2\": None},\n",
|
| 357 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 5, \"src2\": None},\n",
|
| 358 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # → 8\n",
|
| 359 |
+
" {\"op\": \"MUL\", \"dest\": \"d\", \"src1\": \"c\", \"src2\": \"b\"}, # → 8 * 5 = 40\n",
|
| 360 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"d\", \"src2\": None},\n",
|
| 361 |
+
"]\n",
|
| 362 |
+
"result2 = constant_folding(test2)\n",
|
| 363 |
+
"print(\"\\nTest 2 (chained fold):\")\n",
|
| 364 |
+
"for i, instr in enumerate(result2): print(f\" {i}: {instr}\")\n",
|
| 365 |
+
"# Expected: c becomes CONST 8, d becomes CONST 40\n",
|
| 366 |
+
"\n",
|
| 367 |
+
"# Test 3: DIV by zero refused\n",
|
| 368 |
+
"test3 = [\n",
|
| 369 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 10, \"src2\": None},\n",
|
| 370 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 0, \"src2\": None},\n",
|
| 371 |
+
" {\"op\": \"DIV\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # 10/0 — must NOT fold\n",
|
| 372 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 373 |
+
"]\n",
|
| 374 |
+
"result3 = constant_folding(test3)\n",
|
| 375 |
+
"print(\"\\nTest 3 (DIV by zero refused):\")\n",
|
| 376 |
+
"for i, instr in enumerate(result3): print(f\" {i}: {instr}\")\n",
|
| 377 |
+
"# Expected: instruction 2 unchanged (still DIV, not CONST)\n",
|
| 378 |
+
"\n",
|
| 379 |
+
"# Test 4: unknown source can't fold\n",
|
| 380 |
+
"test4 = [\n",
|
| 381 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 3, \"src2\": None},\n",
|
| 382 |
+
" {\"op\": \"LOAD\", \"dest\": \"b\", \"src1\": \"addr0\", \"src2\": None}, # b is unknown\n",
|
| 383 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # can't fold\n",
|
| 384 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 385 |
+
"]\n",
|
| 386 |
+
"result4 = constant_folding(test4)\n",
|
| 387 |
+
"print(\"\\nTest 4 (LOAD makes b unknown, ADD not folded):\")\n",
|
| 388 |
+
"for i, instr in enumerate(result4): print(f\" {i}: {instr}\")\n",
|
| 389 |
+
"# Expected: instruction 2 unchanged (still ADD)\n",
|
| 390 |
+
"\n",
|
| 391 |
+
"# Test 5: idempotence — running CF on a generated program\n",
|
| 392 |
+
"random.seed(42)\n",
|
| 393 |
+
"prog = generate_level_1()\n",
|
| 394 |
+
"folded = constant_folding(prog[\"instructions\"])\n",
|
| 395 |
+
"print(\"\\nTest 5 (CF on generated Level 1 program, seed=42):\")\n",
|
| 396 |
+
"print(\"Before:\")\n",
|
| 397 |
+
"for i, instr in enumerate(prog[\"instructions\"]): print(f\" {i}: {instr}\")\n",
|
| 398 |
+
"print(\"After:\")\n",
|
| 399 |
+
"for i, instr in enumerate(folded): print(f\" {i}: {instr}\")\n",
|
| 400 |
+
"\n",
|
| 401 |
+
"# Test 6: constant propagation — only one source is known\n",
|
| 402 |
+
"test6 = [\n",
|
| 403 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 0, \"src2\": None},\n",
|
| 404 |
+
" {\"op\": \"LOAD\", \"dest\": \"b\", \"src1\": \"addr0\", \"src2\": None}, # b unknown\n",
|
| 405 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # a known (=0), b unknown\n",
|
| 406 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 407 |
+
"]\n",
|
| 408 |
+
"result6 = constant_folding(test6)\n",
|
| 409 |
+
"print(\"\\nTest 6 (propagation: a=0 substituted into ADD even though b unknown):\")\n",
|
| 410 |
+
"for i, instr in enumerate(result6): print(f\" {i}: {instr}\")\n",
|
| 411 |
+
"# Expected: instruction 2 is still ADD (can't fold — b unknown), but src1 is now literal 0, not 'a'\n",
|
| 412 |
+
"# This sets up peephole to recognize \"ADD with 0\" later"
|
| 413 |
+
],
|
| 414 |
+
"metadata": {
|
| 415 |
+
"colab": {
|
| 416 |
+
"base_uri": "https://localhost:8080/"
|
| 417 |
+
},
|
| 418 |
+
"id": "WLKSTVa8fRF8",
|
| 419 |
+
"outputId": "e9480e1e-5d59-4afe-a884-bae0fa4a2192"
|
| 420 |
+
},
|
| 421 |
+
"execution_count": 6,
|
| 422 |
+
"outputs": [
|
| 423 |
+
{
|
| 424 |
+
"output_type": "stream",
|
| 425 |
+
"name": "stdout",
|
| 426 |
+
"text": [
|
| 427 |
+
"Test 1 (simple ADD fold):\n",
|
| 428 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 3, 'src2': None}\n",
|
| 429 |
+
" 1: {'op': 'CONST', 'dest': 'b', 'src1': 5, 'src2': None}\n",
|
| 430 |
+
" 2: {'op': 'CONST', 'dest': 'c', 'src1': 8, 'src2': None}\n",
|
| 431 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 432 |
+
"\n",
|
| 433 |
+
"Test 2 (chained fold):\n",
|
| 434 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 3, 'src2': None}\n",
|
| 435 |
+
" 1: {'op': 'CONST', 'dest': 'b', 'src1': 5, 'src2': None}\n",
|
| 436 |
+
" 2: {'op': 'CONST', 'dest': 'c', 'src1': 8, 'src2': None}\n",
|
| 437 |
+
" 3: {'op': 'CONST', 'dest': 'd', 'src1': 40, 'src2': None}\n",
|
| 438 |
+
" 4: {'op': 'STORE', 'dest': 'addr0', 'src1': 'd', 'src2': None}\n",
|
| 439 |
+
"\n",
|
| 440 |
+
"Test 3 (DIV by zero refused):\n",
|
| 441 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 10, 'src2': None}\n",
|
| 442 |
+
" 1: {'op': 'CONST', 'dest': 'b', 'src1': 0, 'src2': None}\n",
|
| 443 |
+
" 2: {'op': 'DIV', 'dest': 'c', 'src1': 10, 'src2': 0}\n",
|
| 444 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 445 |
+
"\n",
|
| 446 |
+
"Test 4 (LOAD makes b unknown, ADD not folded):\n",
|
| 447 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 3, 'src2': None}\n",
|
| 448 |
+
" 1: {'op': 'LOAD', 'dest': 'b', 'src1': 'addr0', 'src2': None}\n",
|
| 449 |
+
" 2: {'op': 'ADD', 'dest': 'c', 'src1': 3, 'src2': 'b'}\n",
|
| 450 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 451 |
+
"\n",
|
| 452 |
+
"Test 5 (CF on generated Level 1 program, seed=42):\n",
|
| 453 |
+
"Before:\n",
|
| 454 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 455 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 456 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 457 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 458 |
+
"After:\n",
|
| 459 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 460 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 461 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 2, 'src2': None}\n",
|
| 462 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 463 |
+
"\n",
|
| 464 |
+
"Test 6 (propagation: a=0 substituted into ADD even though b unknown):\n",
|
| 465 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 0, 'src2': None}\n",
|
| 466 |
+
" 1: {'op': 'LOAD', 'dest': 'b', 'src1': 'addr0', 'src2': None}\n",
|
| 467 |
+
" 2: {'op': 'ADD', 'dest': 'c', 'src1': 0, 'src2': 'b'}\n",
|
| 468 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n"
|
| 469 |
+
]
|
| 470 |
+
}
|
| 471 |
+
]
|
| 472 |
+
},
|
| 473 |
+
{
|
| 474 |
+
"cell_type": "code",
|
| 475 |
+
"source": [
|
| 476 |
+
"def dead_code_elimination(program):\n",
|
| 477 |
+
" \"\"\"\n",
|
| 478 |
+
" Backward liveness analysis. Replace dead instructions with NOPs,\n",
|
| 479 |
+
" then strip NOPs.\n",
|
| 480 |
+
"\n",
|
| 481 |
+
" Rules:\n",
|
| 482 |
+
" - STOREs are always live (define program output).\n",
|
| 483 |
+
" - Address variables used in STORE/LOAD are always live.\n",
|
| 484 |
+
" - Any instruction whose dest is never read later is dead.\n",
|
| 485 |
+
"\n",
|
| 486 |
+
" Returns a fresh list of instruction dicts. Never raises, never returns None.\n",
|
| 487 |
+
" \"\"\"\n",
|
| 488 |
+
" # Walk backward, build new program in reverse, then re-reverse at the end\n",
|
| 489 |
+
" live = set()\n",
|
| 490 |
+
" new_program_reversed = []\n",
|
| 491 |
+
"\n",
|
| 492 |
+
" for instr in reversed(program):\n",
|
| 493 |
+
" instr = instr.copy() # never alias input\n",
|
| 494 |
+
" op = instr[\"op\"]\n",
|
| 495 |
+
" dest = instr[\"dest\"]\n",
|
| 496 |
+
" src1 = instr[\"src1\"]\n",
|
| 497 |
+
" src2 = instr[\"src2\"]\n",
|
| 498 |
+
"\n",
|
| 499 |
+
" if op == \"STORE\":\n",
|
| 500 |
+
" # STOREs are always kept; mark sources live\n",
|
| 501 |
+
" if isinstance(src1, str): live.add(src1)\n",
|
| 502 |
+
" if isinstance(dest, str): live.add(dest) # address variable\n",
|
| 503 |
+
" new_program_reversed.append(instr)\n",
|
| 504 |
+
"\n",
|
| 505 |
+
" elif op == \"NOP\":\n",
|
| 506 |
+
" # Pass through; will be stripped at the end\n",
|
| 507 |
+
" new_program_reversed.append(instr)\n",
|
| 508 |
+
"\n",
|
| 509 |
+
" elif op in (\"CONST\", \"ADD\", \"SUB\", \"MUL\", \"DIV\", \"LOAD\"):\n",
|
| 510 |
+
" if dest in live:\n",
|
| 511 |
+
" # Live instruction — keep it, mark its sources live\n",
|
| 512 |
+
" live.discard(dest)\n",
|
| 513 |
+
" if isinstance(src1, str): live.add(src1)\n",
|
| 514 |
+
" if isinstance(src2, str): live.add(src2)\n",
|
| 515 |
+
" new_program_reversed.append(instr)\n",
|
| 516 |
+
" else:\n",
|
| 517 |
+
" # Dead — replace with NOP\n",
|
| 518 |
+
" new_program_reversed.append({\n",
|
| 519 |
+
" \"op\": \"NOP\", \"dest\": None, \"src1\": None, \"src2\": None,\n",
|
| 520 |
+
" })\n",
|
| 521 |
+
"\n",
|
| 522 |
+
" else:\n",
|
| 523 |
+
" # Unknown op — defensive pass-through\n",
|
| 524 |
+
" new_program_reversed.append(instr)\n",
|
| 525 |
+
"\n",
|
| 526 |
+
" # Reverse back to forward order, then strip NOPs\n",
|
| 527 |
+
" new_program = list(reversed(new_program_reversed))\n",
|
| 528 |
+
" new_program = [instr for instr in new_program if instr[\"op\"] != \"NOP\"]\n",
|
| 529 |
+
"\n",
|
| 530 |
+
" return new_program"
|
| 531 |
+
],
|
| 532 |
+
"metadata": {
|
| 533 |
+
"id": "5vo-KgaffTFR"
|
| 534 |
+
},
|
| 535 |
+
"execution_count": 12,
|
| 536 |
+
"outputs": []
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"cell_type": "code",
|
| 540 |
+
"source": [
|
| 541 |
+
"# === Sanity tests for dead_code_elimination ===\n",
|
| 542 |
+
"\n",
|
| 543 |
+
"# Test 1: simple dead variable\n",
|
| 544 |
+
"test1 = [\n",
|
| 545 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 5, \"src2\": None},\n",
|
| 546 |
+
" {\"op\": \"CONST\", \"dest\": \"dead\", \"src1\": 99, \"src2\": None}, # never used\n",
|
| 547 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"a\", \"src2\": None},\n",
|
| 548 |
+
"]\n",
|
| 549 |
+
"result1 = dead_code_elimination(test1)\n",
|
| 550 |
+
"print(\"Test 1 (kill unused CONST):\")\n",
|
| 551 |
+
"for i, instr in enumerate(result1): print(f\" {i}: {instr}\")\n",
|
| 552 |
+
"# Expected: 'dead' instruction removed, 2 instructions remain\n",
|
| 553 |
+
"\n",
|
| 554 |
+
"# Test 2: chain of dead computation\n",
|
| 555 |
+
"test2 = [\n",
|
| 556 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 5, \"src2\": None},\n",
|
| 557 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 3, \"src2\": None},\n",
|
| 558 |
+
" {\"op\": \"ADD\", \"dest\": \"x\", \"src1\": \"a\", \"src2\": \"b\"}, # x never used → dead\n",
|
| 559 |
+
" {\"op\": \"CONST\", \"dest\": \"c\", \"src1\": 7, \"src2\": None},\n",
|
| 560 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 561 |
+
"]\n",
|
| 562 |
+
"result2 = dead_code_elimination(test2)\n",
|
| 563 |
+
"print(\"\\nTest 2 (kill unused ADD and its feeders... but only if feeders are also unused):\")\n",
|
| 564 |
+
"for i, instr in enumerate(result2): print(f\" {i}: {instr}\")\n",
|
| 565 |
+
"# Expected: x's ADD killed. a and b also killed (only fed into x, which is dead).\n",
|
| 566 |
+
"# Final: just CONST c=7, STORE.\n",
|
| 567 |
+
"\n",
|
| 568 |
+
"# Test 3: STORE always preserved\n",
|
| 569 |
+
"test3 = [\n",
|
| 570 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 5, \"src2\": None},\n",
|
| 571 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"a\", \"src2\": None},\n",
|
| 572 |
+
"]\n",
|
| 573 |
+
"result3 = dead_code_elimination(test3)\n",
|
| 574 |
+
"print(\"\\nTest 3 (STORE preserved, feeder kept live):\")\n",
|
| 575 |
+
"for i, instr in enumerate(result3): print(f\" {i}: {instr}\")\n",
|
| 576 |
+
"# Expected: both instructions unchanged\n",
|
| 577 |
+
"\n",
|
| 578 |
+
"# Test 4: variable used by STORE is live, even if defined far above\n",
|
| 579 |
+
"test4 = [\n",
|
| 580 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 5, \"src2\": None}, # used by STORE → live\n",
|
| 581 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 9, \"src2\": None}, # never used → dead\n",
|
| 582 |
+
" {\"op\": \"CONST\", \"dest\": \"c\", \"src1\": 1, \"src2\": None}, # never used → dead\n",
|
| 583 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"a\", \"src2\": None},\n",
|
| 584 |
+
"]\n",
|
| 585 |
+
"result4 = dead_code_elimination(test4)\n",
|
| 586 |
+
"print(\"\\nTest 4 (only 'a' is live, b/c killed):\")\n",
|
| 587 |
+
"for i, instr in enumerate(result4): print(f\" {i}: {instr}\")\n",
|
| 588 |
+
"# Expected: a's CONST + STORE remain. b, c stripped.\n",
|
| 589 |
+
"\n",
|
| 590 |
+
"# Test 5: combine CF + DCE on a generated program\n",
|
| 591 |
+
"random.seed(42)\n",
|
| 592 |
+
"prog = generate_level_1()\n",
|
| 593 |
+
"print(\"\\nTest 5 (CF then DCE on seed=42):\")\n",
|
| 594 |
+
"print(\"Original:\")\n",
|
| 595 |
+
"for i, instr in enumerate(prog[\"instructions\"]): print(f\" {i}: {instr}\")\n",
|
| 596 |
+
"\n",
|
| 597 |
+
"after_cf = constant_folding(prog[\"instructions\"])\n",
|
| 598 |
+
"print(\"After CF:\")\n",
|
| 599 |
+
"for i, instr in enumerate(after_cf): print(f\" {i}: {instr}\")\n",
|
| 600 |
+
"\n",
|
| 601 |
+
"after_dce = dead_code_elimination(after_cf)\n",
|
| 602 |
+
"print(\"After CF + DCE:\")\n",
|
| 603 |
+
"for i, instr in enumerate(after_dce): print(f\" {i}: {instr}\")\n",
|
| 604 |
+
"# Expected: original 4 instructions become much shorter — dead 'v1' eliminated, v2 folded\n",
|
| 605 |
+
"\n",
|
| 606 |
+
"# Test 6: idempotence — running DCE twice gives same result\n",
|
| 607 |
+
"test6 = [\n",
|
| 608 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 5, \"src2\": None},\n",
|
| 609 |
+
" {\"op\": \"CONST\", \"dest\": \"dead\", \"src1\": 99, \"src2\": None},\n",
|
| 610 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"a\", \"src2\": None},\n",
|
| 611 |
+
"]\n",
|
| 612 |
+
"once = dead_code_elimination(test6)\n",
|
| 613 |
+
"twice = dead_code_elimination(once)\n",
|
| 614 |
+
"print(\"\\nTest 6 (idempotence):\", \"PASS\" if once == twice else \"FAIL\")"
|
| 615 |
+
],
|
| 616 |
+
"metadata": {
|
| 617 |
+
"colab": {
|
| 618 |
+
"base_uri": "https://localhost:8080/"
|
| 619 |
+
},
|
| 620 |
+
"id": "vv8QRFRlvzdq",
|
| 621 |
+
"outputId": "e1d35874-ff1a-4dec-f43f-e22867dd3911"
|
| 622 |
+
},
|
| 623 |
+
"execution_count": 8,
|
| 624 |
+
"outputs": [
|
| 625 |
+
{
|
| 626 |
+
"output_type": "stream",
|
| 627 |
+
"name": "stdout",
|
| 628 |
+
"text": [
|
| 629 |
+
"Test 1 (kill unused CONST):\n",
|
| 630 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 5, 'src2': None}\n",
|
| 631 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'a', 'src2': None}\n",
|
| 632 |
+
"\n",
|
| 633 |
+
"Test 2 (kill unused ADD and its feeders... but only if feeders are also unused):\n",
|
| 634 |
+
" 0: {'op': 'CONST', 'dest': 'c', 'src1': 7, 'src2': None}\n",
|
| 635 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 636 |
+
"\n",
|
| 637 |
+
"Test 3 (STORE preserved, feeder kept live):\n",
|
| 638 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 5, 'src2': None}\n",
|
| 639 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'a', 'src2': None}\n",
|
| 640 |
+
"\n",
|
| 641 |
+
"Test 4 (only 'a' is live, b/c killed):\n",
|
| 642 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 5, 'src2': None}\n",
|
| 643 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'a', 'src2': None}\n",
|
| 644 |
+
"\n",
|
| 645 |
+
"Test 5 (CF then DCE on seed=42):\n",
|
| 646 |
+
"Original:\n",
|
| 647 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 648 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 649 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 650 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 651 |
+
"After CF:\n",
|
| 652 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 653 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 654 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 2, 'src2': None}\n",
|
| 655 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 656 |
+
"After CF + DCE:\n",
|
| 657 |
+
" 0: {'op': 'CONST', 'dest': 'v2', 'src1': 2, 'src2': None}\n",
|
| 658 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 659 |
+
"\n",
|
| 660 |
+
"Test 6 (idempotence): PASS\n"
|
| 661 |
+
]
|
| 662 |
+
}
|
| 663 |
+
]
|
| 664 |
+
},
|
| 665 |
+
{
|
| 666 |
+
"cell_type": "code",
|
| 667 |
+
"source": [
|
| 668 |
+
"def peephole_optimization(program):\n",
|
| 669 |
+
" \"\"\"\n",
|
| 670 |
+
" Single-instruction peephole rewrites. Replaces expensive ops with\n",
|
| 671 |
+
" cheaper equivalents when operands hit special values (0, 1, 2, self).\n",
|
| 672 |
+
"\n",
|
| 673 |
+
" Patterns (all preserve semantics):\n",
|
| 674 |
+
" MUL by 2 -> ADD x + x\n",
|
| 675 |
+
" MUL by 1 -> CONST (the other operand)\n",
|
| 676 |
+
" MUL by 0 -> CONST 0\n",
|
| 677 |
+
" ADD with 0 -> CONST (the other operand)\n",
|
| 678 |
+
" SUB x - x -> CONST 0\n",
|
| 679 |
+
" DIV by 1 -> CONST (the dividend)\n",
|
| 680 |
+
"\n",
|
| 681 |
+
" Notes:\n",
|
| 682 |
+
" - Operates on individual instructions; no cross-instruction state.\n",
|
| 683 |
+
" - Relies on constant_folding having propagated literal values into operands.\n",
|
| 684 |
+
" - Returns fresh instruction dicts; never aliases inputs.\n",
|
| 685 |
+
"\n",
|
| 686 |
+
" Returns a new list. Never raises, never returns None.\n",
|
| 687 |
+
" \"\"\"\n",
|
| 688 |
+
" new_program = []\n",
|
| 689 |
+
"\n",
|
| 690 |
+
" for instr in program:\n",
|
| 691 |
+
" instr = instr.copy()\n",
|
| 692 |
+
" op = instr[\"op\"]\n",
|
| 693 |
+
" dest = instr[\"dest\"]\n",
|
| 694 |
+
" src1 = instr[\"src1\"]\n",
|
| 695 |
+
" src2 = instr[\"src2\"]\n",
|
| 696 |
+
"\n",
|
| 697 |
+
" # === MUL patterns ===\n",
|
| 698 |
+
" if op == \"MUL\":\n",
|
| 699 |
+
" # MUL by 0 -> CONST 0\n",
|
| 700 |
+
" if src1 == 0 or src2 == 0:\n",
|
| 701 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": 0, \"src2\": None})\n",
|
| 702 |
+
" continue\n",
|
| 703 |
+
" # MUL by 1 -> CONST (other operand) if the other operand is a literal,\n",
|
| 704 |
+
" # otherwise leave alone (we don't want to introduce a useless\n",
|
| 705 |
+
" # \"CONST dest = some_var_name\" — that's not a valid CONST).\n",
|
| 706 |
+
" if src1 == 1 and isinstance(src2, int):\n",
|
| 707 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": src2, \"src2\": None})\n",
|
| 708 |
+
" continue\n",
|
| 709 |
+
" if src2 == 1 and isinstance(src1, int):\n",
|
| 710 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": src1, \"src2\": None})\n",
|
| 711 |
+
" continue\n",
|
| 712 |
+
" # MUL by 2 -> ADD x + x (when one operand is literal 2 and the other is a var)\n",
|
| 713 |
+
" if src1 == 2 and isinstance(src2, str):\n",
|
| 714 |
+
" new_program.append({\"op\": \"ADD\", \"dest\": dest, \"src1\": src2, \"src2\": src2})\n",
|
| 715 |
+
" continue\n",
|
| 716 |
+
" if src2 == 2 and isinstance(src1, str):\n",
|
| 717 |
+
" new_program.append({\"op\": \"ADD\", \"dest\": dest, \"src1\": src1, \"src2\": src1})\n",
|
| 718 |
+
" continue\n",
|
| 719 |
+
" # No pattern matched — keep as is\n",
|
| 720 |
+
" new_program.append(instr)\n",
|
| 721 |
+
"\n",
|
| 722 |
+
" # === ADD patterns ===\n",
|
| 723 |
+
" elif op == \"ADD\":\n",
|
| 724 |
+
" # ADD with 0 -> CONST (other operand) if the other operand is a literal\n",
|
| 725 |
+
" if src1 == 0 and isinstance(src2, int):\n",
|
| 726 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": src2, \"src2\": None})\n",
|
| 727 |
+
" continue\n",
|
| 728 |
+
" if src2 == 0 and isinstance(src1, int):\n",
|
| 729 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": src1, \"src2\": None})\n",
|
| 730 |
+
" continue\n",
|
| 731 |
+
" # If \"ADD x + 0\" where x is a variable, we'd want a copy — but our schema\n",
|
| 732 |
+
" # has no MOV/COPY op. Leave alone; CF + DCE handle the rest in practice.\n",
|
| 733 |
+
" new_program.append(instr)\n",
|
| 734 |
+
"\n",
|
| 735 |
+
" # === SUB patterns ===\n",
|
| 736 |
+
" elif op == \"SUB\":\n",
|
| 737 |
+
" # SUB x - x -> CONST 0 (only if both sources are the same string variable)\n",
|
| 738 |
+
" if isinstance(src1, str) and isinstance(src2, str) and src1 == src2:\n",
|
| 739 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": 0, \"src2\": None})\n",
|
| 740 |
+
" continue\n",
|
| 741 |
+
" # SUB x - 0 with literal 0 on src2 — we'd want a copy; skip (no COPY op)\n",
|
| 742 |
+
" new_program.append(instr)\n",
|
| 743 |
+
"\n",
|
| 744 |
+
" # === DIV patterns ===\n",
|
| 745 |
+
" elif op == \"DIV\":\n",
|
| 746 |
+
" # DIV by 1 -> CONST (dividend) if dividend is a literal\n",
|
| 747 |
+
" if src2 == 1 and isinstance(src1, int):\n",
|
| 748 |
+
" new_program.append({\"op\": \"CONST\", \"dest\": dest, \"src1\": src1, \"src2\": None})\n",
|
| 749 |
+
" continue\n",
|
| 750 |
+
" new_program.append(instr)\n",
|
| 751 |
+
"\n",
|
| 752 |
+
" else:\n",
|
| 753 |
+
" # CONST, LOAD, STORE, NOP — pass through\n",
|
| 754 |
+
" new_program.append(instr)\n",
|
| 755 |
+
"\n",
|
| 756 |
+
" return new_program"
|
| 757 |
+
],
|
| 758 |
+
"metadata": {
|
| 759 |
+
"id": "IaczDNeLv5PW"
|
| 760 |
+
},
|
| 761 |
+
"execution_count": 9,
|
| 762 |
+
"outputs": []
|
| 763 |
+
},
|
| 764 |
+
{
|
| 765 |
+
"cell_type": "code",
|
| 766 |
+
"source": [
|
| 767 |
+
"# === Sanity tests for peephole_optimization ===\n",
|
| 768 |
+
"\n",
|
| 769 |
+
"# Test 1: MUL by 2 -> ADD x+x\n",
|
| 770 |
+
"test1 = [\n",
|
| 771 |
+
" {\"op\": \"LOAD\", \"dest\": \"y\", \"src1\": \"addr0\", \"src2\": None},\n",
|
| 772 |
+
" {\"op\": \"MUL\", \"dest\": \"x\", \"src1\": \"y\", \"src2\": 2},\n",
|
| 773 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 774 |
+
"]\n",
|
| 775 |
+
"result1 = peephole_optimization(test1)\n",
|
| 776 |
+
"print(\"Test 1 (MUL by 2 -> ADD self):\")\n",
|
| 777 |
+
"for i, instr in enumerate(result1): print(f\" {i}: {instr}\")\n",
|
| 778 |
+
"# Expected: instruction 1 becomes ADD y+y\n",
|
| 779 |
+
"\n",
|
| 780 |
+
"# Test 2: MUL by 0 -> CONST 0\n",
|
| 781 |
+
"test2 = [\n",
|
| 782 |
+
" {\"op\": \"LOAD\", \"dest\": \"y\", \"src1\": \"addr0\", \"src2\": None},\n",
|
| 783 |
+
" {\"op\": \"MUL\", \"dest\": \"x\", \"src1\": \"y\", \"src2\": 0},\n",
|
| 784 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 785 |
+
"]\n",
|
| 786 |
+
"result2 = peephole_optimization(test2)\n",
|
| 787 |
+
"print(\"\\nTest 2 (MUL by 0 -> CONST 0):\")\n",
|
| 788 |
+
"for i, instr in enumerate(result2): print(f\" {i}: {instr}\")\n",
|
| 789 |
+
"# Expected: instruction 1 becomes CONST x = 0\n",
|
| 790 |
+
"\n",
|
| 791 |
+
"# Test 3: MUL by 1 (both literals)\n",
|
| 792 |
+
"test3 = [\n",
|
| 793 |
+
" {\"op\": \"MUL\", \"dest\": \"x\", \"src1\": 7, \"src2\": 1},\n",
|
| 794 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 795 |
+
"]\n",
|
| 796 |
+
"result3 = peephole_optimization(test3)\n",
|
| 797 |
+
"print(\"\\nTest 3 (MUL 7*1 -> CONST 7):\")\n",
|
| 798 |
+
"for i, instr in enumerate(result3): print(f\" {i}: {instr}\")\n",
|
| 799 |
+
"# Expected: instruction 0 becomes CONST x = 7\n",
|
| 800 |
+
"\n",
|
| 801 |
+
"# Test 4: SUB x - x -> CONST 0\n",
|
| 802 |
+
"test4 = [\n",
|
| 803 |
+
" {\"op\": \"LOAD\", \"dest\": \"y\", \"src1\": \"addr0\", \"src2\": None},\n",
|
| 804 |
+
" {\"op\": \"SUB\", \"dest\": \"x\", \"src1\": \"y\", \"src2\": \"y\"},\n",
|
| 805 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 806 |
+
"]\n",
|
| 807 |
+
"result4 = peephole_optimization(test4)\n",
|
| 808 |
+
"print(\"\\nTest 4 (SUB y-y -> CONST 0):\")\n",
|
| 809 |
+
"for i, instr in enumerate(result4): print(f\" {i}: {instr}\")\n",
|
| 810 |
+
"# Expected: instruction 1 becomes CONST x = 0\n",
|
| 811 |
+
"\n",
|
| 812 |
+
"# Test 5: ADD with 0\n",
|
| 813 |
+
"test5 = [\n",
|
| 814 |
+
" {\"op\": \"ADD\", \"dest\": \"x\", \"src1\": 0, \"src2\": 5},\n",
|
| 815 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 816 |
+
"]\n",
|
| 817 |
+
"result5 = peephole_optimization(test5)\n",
|
| 818 |
+
"print(\"\\nTest 5 (ADD 0+5 -> CONST 5):\")\n",
|
| 819 |
+
"for i, instr in enumerate(result5): print(f\" {i}: {instr}\")\n",
|
| 820 |
+
"# Expected: instruction 0 becomes CONST x = 5\n",
|
| 821 |
+
"\n",
|
| 822 |
+
"# Test 6: full pipeline — CF then peephole on a generated program\n",
|
| 823 |
+
"random.seed(7)\n",
|
| 824 |
+
"prog = generate_level_1()\n",
|
| 825 |
+
"print(\"\\nTest 6 (CF then peephole on seed=7):\")\n",
|
| 826 |
+
"print(\"Original:\")\n",
|
| 827 |
+
"for i, instr in enumerate(prog[\"instructions\"]): print(f\" {i}: {instr}\")\n",
|
| 828 |
+
"after_cf = constant_folding(prog[\"instructions\"])\n",
|
| 829 |
+
"print(\"After CF:\")\n",
|
| 830 |
+
"for i, instr in enumerate(after_cf): print(f\" {i}: {instr}\")\n",
|
| 831 |
+
"after_peep = peephole_optimization(after_cf)\n",
|
| 832 |
+
"print(\"After CF + peephole:\")\n",
|
| 833 |
+
"for i, instr in enumerate(after_peep): print(f\" {i}: {instr}\")\n",
|
| 834 |
+
"\n",
|
| 835 |
+
"# Test 7: idempotence\n",
|
| 836 |
+
"test7 = [\n",
|
| 837 |
+
" {\"op\": \"MUL\", \"dest\": \"x\", \"src1\": \"y\", \"src2\": 2},\n",
|
| 838 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 839 |
+
"]\n",
|
| 840 |
+
"once = peephole_optimization(test7)\n",
|
| 841 |
+
"twice = peephole_optimization(once)\n",
|
| 842 |
+
"print(\"\\nTest 7 (idempotence):\", \"PASS\" if once == twice else \"FAIL\")\n",
|
| 843 |
+
"\n",
|
| 844 |
+
"# Test 8: no false fires — vanilla program shouldn't get rewritten\n",
|
| 845 |
+
"test8 = [\n",
|
| 846 |
+
" {\"op\": \"LOAD\", \"dest\": \"y\", \"src1\": \"addr0\", \"src2\": None},\n",
|
| 847 |
+
" {\"op\": \"MUL\", \"dest\": \"x\", \"src1\": \"y\", \"src2\": \"y\"}, # y*y, no peephole pattern\n",
|
| 848 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"x\", \"src2\": None},\n",
|
| 849 |
+
"]\n",
|
| 850 |
+
"result8 = peephole_optimization(test8)\n",
|
| 851 |
+
"print(\"\\nTest 8 (no false rewrite on y*y):\")\n",
|
| 852 |
+
"for i, instr in enumerate(result8): print(f\" {i}: {instr}\")\n",
|
| 853 |
+
"# Expected: instruction 1 unchanged (still MUL y*y)"
|
| 854 |
+
],
|
| 855 |
+
"metadata": {
|
| 856 |
+
"colab": {
|
| 857 |
+
"base_uri": "https://localhost:8080/"
|
| 858 |
+
},
|
| 859 |
+
"id": "DWDUZUQvwXye",
|
| 860 |
+
"outputId": "1d1e327f-5f26-43e4-a6ac-f7a286da3781"
|
| 861 |
+
},
|
| 862 |
+
"execution_count": 10,
|
| 863 |
+
"outputs": [
|
| 864 |
+
{
|
| 865 |
+
"output_type": "stream",
|
| 866 |
+
"name": "stdout",
|
| 867 |
+
"text": [
|
| 868 |
+
"Test 1 (MUL by 2 -> ADD self):\n",
|
| 869 |
+
" 0: {'op': 'LOAD', 'dest': 'y', 'src1': 'addr0', 'src2': None}\n",
|
| 870 |
+
" 1: {'op': 'ADD', 'dest': 'x', 'src1': 'y', 'src2': 'y'}\n",
|
| 871 |
+
" 2: {'op': 'STORE', 'dest': 'addr0', 'src1': 'x', 'src2': None}\n",
|
| 872 |
+
"\n",
|
| 873 |
+
"Test 2 (MUL by 0 -> CONST 0):\n",
|
| 874 |
+
" 0: {'op': 'LOAD', 'dest': 'y', 'src1': 'addr0', 'src2': None}\n",
|
| 875 |
+
" 1: {'op': 'CONST', 'dest': 'x', 'src1': 0, 'src2': None}\n",
|
| 876 |
+
" 2: {'op': 'STORE', 'dest': 'addr0', 'src1': 'x', 'src2': None}\n",
|
| 877 |
+
"\n",
|
| 878 |
+
"Test 3 (MUL 7*1 -> CONST 7):\n",
|
| 879 |
+
" 0: {'op': 'CONST', 'dest': 'x', 'src1': 7, 'src2': None}\n",
|
| 880 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'x', 'src2': None}\n",
|
| 881 |
+
"\n",
|
| 882 |
+
"Test 4 (SUB y-y -> CONST 0):\n",
|
| 883 |
+
" 0: {'op': 'LOAD', 'dest': 'y', 'src1': 'addr0', 'src2': None}\n",
|
| 884 |
+
" 1: {'op': 'CONST', 'dest': 'x', 'src1': 0, 'src2': None}\n",
|
| 885 |
+
" 2: {'op': 'STORE', 'dest': 'addr0', 'src1': 'x', 'src2': None}\n",
|
| 886 |
+
"\n",
|
| 887 |
+
"Test 5 (ADD 0+5 -> CONST 5):\n",
|
| 888 |
+
" 0: {'op': 'CONST', 'dest': 'x', 'src1': 5, 'src2': None}\n",
|
| 889 |
+
" 1: {'op': 'STORE', 'dest': 'addr0', 'src1': 'x', 'src2': None}\n",
|
| 890 |
+
"\n",
|
| 891 |
+
"Test 6 (CF then peephole on seed=7):\n",
|
| 892 |
+
"Original:\n",
|
| 893 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 3, 'src2': None}\n",
|
| 894 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 7, 'src2': None}\n",
|
| 895 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 1, 'src2': None}\n",
|
| 896 |
+
" 3: {'op': 'ADD', 'dest': 'v3', 'src1': 'v1', 'src2': 'v2'}\n",
|
| 897 |
+
" 4: {'op': 'CONST', 'dest': 'v4', 'src1': 9, 'src2': None}\n",
|
| 898 |
+
" 5: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 899 |
+
"After CF:\n",
|
| 900 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 3, 'src2': None}\n",
|
| 901 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 7, 'src2': None}\n",
|
| 902 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 1, 'src2': None}\n",
|
| 903 |
+
" 3: {'op': 'CONST', 'dest': 'v3', 'src1': 8, 'src2': None}\n",
|
| 904 |
+
" 4: {'op': 'CONST', 'dest': 'v4', 'src1': 9, 'src2': None}\n",
|
| 905 |
+
" 5: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 906 |
+
"After CF + peephole:\n",
|
| 907 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 3, 'src2': None}\n",
|
| 908 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 7, 'src2': None}\n",
|
| 909 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 1, 'src2': None}\n",
|
| 910 |
+
" 3: {'op': 'CONST', 'dest': 'v3', 'src1': 8, 'src2': None}\n",
|
| 911 |
+
" 4: {'op': 'CONST', 'dest': 'v4', 'src1': 9, 'src2': None}\n",
|
| 912 |
+
" 5: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 913 |
+
"\n",
|
| 914 |
+
"Test 7 (idempotence): PASS\n",
|
| 915 |
+
"\n",
|
| 916 |
+
"Test 8 (no false rewrite on y*y):\n",
|
| 917 |
+
" 0: {'op': 'LOAD', 'dest': 'y', 'src1': 'addr0', 'src2': None}\n",
|
| 918 |
+
" 1: {'op': 'MUL', 'dest': 'x', 'src1': 'y', 'src2': 'y'}\n",
|
| 919 |
+
" 2: {'op': 'STORE', 'dest': 'addr0', 'src1': 'x', 'src2': None}\n"
|
| 920 |
+
]
|
| 921 |
+
}
|
| 922 |
+
]
|
| 923 |
+
},
|
| 924 |
+
{
|
| 925 |
+
"cell_type": "code",
|
| 926 |
+
"source": [
|
| 927 |
+
"def dump_ir(program_data):\n",
|
| 928 |
+
" \"\"\"\n",
|
| 929 |
+
" Convert a TAC program into a readable string for the LLM observation.\n",
|
| 930 |
+
"\n",
|
| 931 |
+
" Format:\n",
|
| 932 |
+
" // OBSERVABLE OUT: mem[0], mem[1]\n",
|
| 933 |
+
" 0: v0 = 3 # CONST [1 cycle]\n",
|
| 934 |
+
" 1: v1 = 5 # CONST [1 cycle]\n",
|
| 935 |
+
" 2: v2 = v0 + v1 # ADD [1 cycle]\n",
|
| 936 |
+
" 3: mem[addr0] = v2 # STORE [4 cycles]\n",
|
| 937 |
+
" // TOTAL: 7 cycles\n",
|
| 938 |
+
"\n",
|
| 939 |
+
" Args:\n",
|
| 940 |
+
" program_data: dict with keys 'instructions' and 'observable_addrs',\n",
|
| 941 |
+
" OR a raw list of instructions (legacy).\n",
|
| 942 |
+
"\n",
|
| 943 |
+
" Returns:\n",
|
| 944 |
+
" A multi-line string suitable for inclusion in an LLM prompt.\n",
|
| 945 |
+
" \"\"\"\n",
|
| 946 |
+
" # Accept both forms — full program dict or raw instruction list\n",
|
| 947 |
+
" if isinstance(program_data, dict):\n",
|
| 948 |
+
" instructions = program_data[\"instructions\"]\n",
|
| 949 |
+
" observable_addrs = program_data.get(\"observable_addrs\", [])\n",
|
| 950 |
+
" else:\n",
|
| 951 |
+
" instructions = program_data\n",
|
| 952 |
+
" observable_addrs = []\n",
|
| 953 |
+
"\n",
|
| 954 |
+
" lines = []\n",
|
| 955 |
+
"\n",
|
| 956 |
+
" # Header: observable outputs\n",
|
| 957 |
+
" if observable_addrs:\n",
|
| 958 |
+
" addr_str = \", \".join(f\"mem[{a}]\" for a in observable_addrs)\n",
|
| 959 |
+
" lines.append(f\"// OBSERVABLE OUT: {addr_str}\")\n",
|
| 960 |
+
"\n",
|
| 961 |
+
" # Body: each instruction in human-readable form\n",
|
| 962 |
+
" total_cycles = 0\n",
|
| 963 |
+
" for i, instr in enumerate(instructions):\n",
|
| 964 |
+
" op = instr[\"op\"]\n",
|
| 965 |
+
" dest = instr[\"dest\"]\n",
|
| 966 |
+
" src1 = instr[\"src1\"]\n",
|
| 967 |
+
" src2 = instr[\"src2\"]\n",
|
| 968 |
+
" cost = CYCLE_COSTS.get(op, 0)\n",
|
| 969 |
+
" total_cycles += cost\n",
|
| 970 |
+
"\n",
|
| 971 |
+
" # Render the instruction body\n",
|
| 972 |
+
" if op == \"CONST\":\n",
|
| 973 |
+
" body = f\"{dest} = {src1}\"\n",
|
| 974 |
+
" elif op == \"ADD\":\n",
|
| 975 |
+
" body = f\"{dest} = {src1} + {src2}\"\n",
|
| 976 |
+
" elif op == \"SUB\":\n",
|
| 977 |
+
" body = f\"{dest} = {src1} - {src2}\"\n",
|
| 978 |
+
" elif op == \"MUL\":\n",
|
| 979 |
+
" body = f\"{dest} = {src1} * {src2}\"\n",
|
| 980 |
+
" elif op == \"DIV\":\n",
|
| 981 |
+
" body = f\"{dest} = {src1} // {src2}\"\n",
|
| 982 |
+
" elif op == \"LOAD\":\n",
|
| 983 |
+
" body = f\"{dest} = mem[{src1}]\"\n",
|
| 984 |
+
" elif op == \"STORE\":\n",
|
| 985 |
+
" body = f\"mem[{dest}] = {src1}\"\n",
|
| 986 |
+
" elif op == \"NOP\":\n",
|
| 987 |
+
" body = \"nop\"\n",
|
| 988 |
+
" else:\n",
|
| 989 |
+
" body = f\"<unknown op: {op}>\"\n",
|
| 990 |
+
"\n",
|
| 991 |
+
" cost_label = f\"{cost} cycle\" if cost == 1 else f\"{cost} cycles\"\n",
|
| 992 |
+
" lines.append(f\"{i}: {body:<35} # {op:<6} [{cost_label}]\")\n",
|
| 993 |
+
"\n",
|
| 994 |
+
" # Footer: total cycles\n",
|
| 995 |
+
" lines.append(f\"// TOTAL: {total_cycles} cycles\")\n",
|
| 996 |
+
"\n",
|
| 997 |
+
" return \"\\n\".join(lines)"
|
| 998 |
+
],
|
| 999 |
+
"metadata": {
|
| 1000 |
+
"id": "yB_yMNOZwaPT"
|
| 1001 |
+
},
|
| 1002 |
+
"execution_count": 13,
|
| 1003 |
+
"outputs": []
|
| 1004 |
+
},
|
| 1005 |
+
{
|
| 1006 |
+
"cell_type": "code",
|
| 1007 |
+
"source": [
|
| 1008 |
+
"# === Sanity tests for state translator ===\n",
|
| 1009 |
+
"\n",
|
| 1010 |
+
"# Test 1: full generated program\n",
|
| 1011 |
+
"random.seed(1)\n",
|
| 1012 |
+
"prog = generate_level_1()\n",
|
| 1013 |
+
"print(\"Test 1 (raw seed=1 program):\")\n",
|
| 1014 |
+
"print(dump_ir(prog))\n",
|
| 1015 |
+
"\n",
|
| 1016 |
+
"# Test 2: after CF\n",
|
| 1017 |
+
"print(\"\\nTest 2 (after CF):\")\n",
|
| 1018 |
+
"folded = constant_folding(prog[\"instructions\"])\n",
|
| 1019 |
+
"prog_after_cf = {**prog, \"instructions\": folded}\n",
|
| 1020 |
+
"print(dump_ir(prog_after_cf))\n",
|
| 1021 |
+
"\n",
|
| 1022 |
+
"# Test 3: after CF + DCE — should show fewer instructions, lower total\n",
|
| 1023 |
+
"print(\"\\nTest 3 (after CF + DCE):\")\n",
|
| 1024 |
+
"optimized = dead_code_elimination(folded)\n",
|
| 1025 |
+
"prog_optimized = {**prog, \"instructions\": optimized}\n",
|
| 1026 |
+
"print(dump_ir(prog_optimized))\n",
|
| 1027 |
+
"\n",
|
| 1028 |
+
"# Test 4: every op type at least once\n",
|
| 1029 |
+
"test4_instructions = [\n",
|
| 1030 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 5, \"src2\": None},\n",
|
| 1031 |
+
" {\"op\": \"ADD\", \"dest\": \"b\", \"src1\": \"a\", \"src2\": 3},\n",
|
| 1032 |
+
" {\"op\": \"SUB\", \"dest\": \"c\", \"src1\": \"b\", \"src2\": \"a\"},\n",
|
| 1033 |
+
" {\"op\": \"MUL\", \"dest\": \"d\", \"src1\": \"c\", \"src2\": 2},\n",
|
| 1034 |
+
" {\"op\": \"DIV\", \"dest\": \"e\", \"src1\": \"d\", \"src2\": 4},\n",
|
| 1035 |
+
" {\"op\": \"LOAD\", \"dest\": \"f\", \"src1\": \"addr0\", \"src2\": None},\n",
|
| 1036 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"e\", \"src2\": None},\n",
|
| 1037 |
+
" {\"op\": \"NOP\", \"dest\": None, \"src1\": None, \"src2\": None},\n",
|
| 1038 |
+
"]\n",
|
| 1039 |
+
"test4_data = {\n",
|
| 1040 |
+
" \"instructions\": test4_instructions,\n",
|
| 1041 |
+
" \"observable_addrs\": [0, 1],\n",
|
| 1042 |
+
"}\n",
|
| 1043 |
+
"print(\"\\nTest 4 (every op type):\")\n",
|
| 1044 |
+
"print(dump_ir(test4_data))\n",
|
| 1045 |
+
"\n",
|
| 1046 |
+
"# Test 5: empty program shouldn't crash\n",
|
| 1047 |
+
"print(\"\\nTest 5 (empty program):\")\n",
|
| 1048 |
+
"print(dump_ir({\"instructions\": [], \"observable_addrs\": [0]}))"
|
| 1049 |
+
],
|
| 1050 |
+
"metadata": {
|
| 1051 |
+
"colab": {
|
| 1052 |
+
"base_uri": "https://localhost:8080/"
|
| 1053 |
+
},
|
| 1054 |
+
"id": "SUqa7odp3wB_",
|
| 1055 |
+
"outputId": "c3f44089-213a-4a69-f29f-42b755ed142a"
|
| 1056 |
+
},
|
| 1057 |
+
"execution_count": 14,
|
| 1058 |
+
"outputs": [
|
| 1059 |
+
{
|
| 1060 |
+
"output_type": "stream",
|
| 1061 |
+
"name": "stdout",
|
| 1062 |
+
"text": [
|
| 1063 |
+
"Test 1 (raw seed=1 program):\n",
|
| 1064 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1065 |
+
"0: v0 = 10 # CONST [1 cycle]\n",
|
| 1066 |
+
"1: v1 = 2 # CONST [1 cycle]\n",
|
| 1067 |
+
"2: v2 = v1 + v1 # ADD [1 cycle]\n",
|
| 1068 |
+
"3: v3 = v2 * v1 # MUL [3 cycles]\n",
|
| 1069 |
+
"4: mem[addr0] = v3 # STORE [4 cycles]\n",
|
| 1070 |
+
"// TOTAL: 10 cycles\n",
|
| 1071 |
+
"\n",
|
| 1072 |
+
"Test 2 (after CF):\n",
|
| 1073 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1074 |
+
"0: v0 = 10 # CONST [1 cycle]\n",
|
| 1075 |
+
"1: v1 = 2 # CONST [1 cycle]\n",
|
| 1076 |
+
"2: v2 = 4 # CONST [1 cycle]\n",
|
| 1077 |
+
"3: v3 = 8 # CONST [1 cycle]\n",
|
| 1078 |
+
"4: mem[addr0] = v3 # STORE [4 cycles]\n",
|
| 1079 |
+
"// TOTAL: 8 cycles\n",
|
| 1080 |
+
"\n",
|
| 1081 |
+
"Test 3 (after CF + DCE):\n",
|
| 1082 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1083 |
+
"0: v3 = 8 # CONST [1 cycle]\n",
|
| 1084 |
+
"1: mem[addr0] = v3 # STORE [4 cycles]\n",
|
| 1085 |
+
"// TOTAL: 5 cycles\n",
|
| 1086 |
+
"\n",
|
| 1087 |
+
"Test 4 (every op type):\n",
|
| 1088 |
+
"// OBSERVABLE OUT: mem[0], mem[1]\n",
|
| 1089 |
+
"0: a = 5 # CONST [1 cycle]\n",
|
| 1090 |
+
"1: b = a + 3 # ADD [1 cycle]\n",
|
| 1091 |
+
"2: c = b - a # SUB [1 cycle]\n",
|
| 1092 |
+
"3: d = c * 2 # MUL [3 cycles]\n",
|
| 1093 |
+
"4: e = d // 4 # DIV [5 cycles]\n",
|
| 1094 |
+
"5: f = mem[addr0] # LOAD [4 cycles]\n",
|
| 1095 |
+
"6: mem[addr0] = e # STORE [4 cycles]\n",
|
| 1096 |
+
"7: nop # NOP [0 cycles]\n",
|
| 1097 |
+
"// TOTAL: 19 cycles\n",
|
| 1098 |
+
"\n",
|
| 1099 |
+
"Test 5 (empty program):\n",
|
| 1100 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1101 |
+
"// TOTAL: 0 cycles\n"
|
| 1102 |
+
]
|
| 1103 |
+
}
|
| 1104 |
+
]
|
| 1105 |
+
},
|
| 1106 |
+
{
|
| 1107 |
+
"cell_type": "code",
|
| 1108 |
+
"source": [
|
| 1109 |
+
"def generate_level_2():\n",
|
| 1110 |
+
" \"\"\"\n",
|
| 1111 |
+
" Generate a Level 2 Toy-IR program.\n",
|
| 1112 |
+
"\n",
|
| 1113 |
+
" Characteristics:\n",
|
| 1114 |
+
" - 8-12 instructions\n",
|
| 1115 |
+
" - 3-5 CONSTs (some literal, some used in arithmetic)\n",
|
| 1116 |
+
" - 3-5 arithmetic ops (ADD, SUB, MUL, DIV) with chaining\n",
|
| 1117 |
+
" - 1-3 dead variables (DCE opportunities)\n",
|
| 1118 |
+
" - 1 LOAD from initial memory (introduces non-constant variable)\n",
|
| 1119 |
+
" - 1 STORE at the end (observable output)\n",
|
| 1120 |
+
" - Mix of operands designed to hit peephole patterns occasionally:\n",
|
| 1121 |
+
" - MUL by literal 2 / 1 / 0 (not always — diversity matters)\n",
|
| 1122 |
+
" - DIV by non-zero divisor only (Design Assumption #4)\n",
|
| 1123 |
+
"\n",
|
| 1124 |
+
" Returns:\n",
|
| 1125 |
+
" dict with keys: initial_vars, initial_mem, instructions, observable_addrs\n",
|
| 1126 |
+
" \"\"\"\n",
|
| 1127 |
+
" instructions = []\n",
|
| 1128 |
+
" var_counter = 0\n",
|
| 1129 |
+
"\n",
|
| 1130 |
+
" def new_var():\n",
|
| 1131 |
+
" nonlocal var_counter\n",
|
| 1132 |
+
" name = f\"v{var_counter}\"\n",
|
| 1133 |
+
" var_counter += 1\n",
|
| 1134 |
+
" return name\n",
|
| 1135 |
+
"\n",
|
| 1136 |
+
" available_vars = [] # vars that exist and can be used as sources\n",
|
| 1137 |
+
"\n",
|
| 1138 |
+
" # Step 1: 3-5 CONSTs\n",
|
| 1139 |
+
" num_consts = random.randint(3, 5)\n",
|
| 1140 |
+
" for _ in range(num_consts):\n",
|
| 1141 |
+
" var = new_var()\n",
|
| 1142 |
+
" value = random.randint(1, 10)\n",
|
| 1143 |
+
" instructions.append({\"op\": \"CONST\", \"dest\": var, \"src1\": value, \"src2\": None})\n",
|
| 1144 |
+
" available_vars.append(var)\n",
|
| 1145 |
+
"\n",
|
| 1146 |
+
" # Step 2: 1 LOAD from initial memory\n",
|
| 1147 |
+
" # We'll seed initial_mem with something at a fresh address.\n",
|
| 1148 |
+
" load_addr_var = \"addr_in\"\n",
|
| 1149 |
+
" loaded_var = new_var()\n",
|
| 1150 |
+
" instructions.append({\n",
|
| 1151 |
+
" \"op\": \"LOAD\", \"dest\": loaded_var, \"src1\": load_addr_var, \"src2\": None,\n",
|
| 1152 |
+
" })\n",
|
| 1153 |
+
" available_vars.append(loaded_var)\n",
|
| 1154 |
+
"\n",
|
| 1155 |
+
" # Step 3: 3-5 arithmetic ops, chained\n",
|
| 1156 |
+
" num_arith = random.randint(3, 5)\n",
|
| 1157 |
+
" last_result = None\n",
|
| 1158 |
+
" for _ in range(num_arith):\n",
|
| 1159 |
+
" op = random.choice([\"ADD\", \"SUB\", \"MUL\", \"DIV\"])\n",
|
| 1160 |
+
"\n",
|
| 1161 |
+
" # 30% chance to use a literal as src2 to expose peephole opportunities\n",
|
| 1162 |
+
" # (MUL by 2/1/0, etc.)\n",
|
| 1163 |
+
" use_literal_src2 = random.random() < 0.3\n",
|
| 1164 |
+
"\n",
|
| 1165 |
+
" src1 = random.choice(available_vars)\n",
|
| 1166 |
+
" if use_literal_src2:\n",
|
| 1167 |
+
" # For DIV, never emit literal 0 (Design Assumption #4)\n",
|
| 1168 |
+
" if op == \"DIV\":\n",
|
| 1169 |
+
" src2 = random.choice([1, 2, 3, 4]) # safe non-zero divisors\n",
|
| 1170 |
+
" else:\n",
|
| 1171 |
+
" src2 = random.choice([0, 1, 2, 3]) # 0/1/2 hit peephole patterns\n",
|
| 1172 |
+
" else:\n",
|
| 1173 |
+
" src2 = random.choice(available_vars)\n",
|
| 1174 |
+
" # If we sampled a variable for DIV's src2, we can't be sure it's non-zero\n",
|
| 1175 |
+
" # at runtime. To stay safe per Assumption #4, restrict DIV to literal src2.\n",
|
| 1176 |
+
" if op == \"DIV\":\n",
|
| 1177 |
+
" src2 = random.choice([1, 2, 3, 4])\n",
|
| 1178 |
+
"\n",
|
| 1179 |
+
" dest = new_var()\n",
|
| 1180 |
+
" instructions.append({\"op\": op, \"dest\": dest, \"src1\": src1, \"src2\": src2})\n",
|
| 1181 |
+
" available_vars.append(dest)\n",
|
| 1182 |
+
" last_result = dest\n",
|
| 1183 |
+
"\n",
|
| 1184 |
+
" # Step 4: 1-3 extra dead CONSTs sprinkled in (DCE targets)\n",
|
| 1185 |
+
" num_dead = random.randint(1, 3)\n",
|
| 1186 |
+
" for _ in range(num_dead):\n",
|
| 1187 |
+
" dead_var = new_var()\n",
|
| 1188 |
+
" dead_value = random.randint(1, 20)\n",
|
| 1189 |
+
" # Insert at a random position before the (eventual) STORE\n",
|
| 1190 |
+
" insert_pos = random.randint(0, len(instructions))\n",
|
| 1191 |
+
" instructions.insert(insert_pos, {\n",
|
| 1192 |
+
" \"op\": \"CONST\", \"dest\": dead_var, \"src1\": dead_value, \"src2\": None,\n",
|
| 1193 |
+
" })\n",
|
| 1194 |
+
" # Note: dead_var intentionally never used afterward\n",
|
| 1195 |
+
"\n",
|
| 1196 |
+
" # Step 5: STORE the final result\n",
|
| 1197 |
+
" initial_vars = {\n",
|
| 1198 |
+
" \"addr0\": 0,\n",
|
| 1199 |
+
" \"addr_in\": 1, # address that the LOAD reads from\n",
|
| 1200 |
+
" }\n",
|
| 1201 |
+
" initial_mem = {1: random.randint(1, 20)} # seed mem[1] with a random value\n",
|
| 1202 |
+
"\n",
|
| 1203 |
+
" instructions.append({\n",
|
| 1204 |
+
" \"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": last_result, \"src2\": None,\n",
|
| 1205 |
+
" })\n",
|
| 1206 |
+
"\n",
|
| 1207 |
+
" return {\n",
|
| 1208 |
+
" \"initial_vars\": initial_vars,\n",
|
| 1209 |
+
" \"initial_mem\": initial_mem,\n",
|
| 1210 |
+
" \"instructions\": instructions,\n",
|
| 1211 |
+
" \"observable_addrs\": [0],\n",
|
| 1212 |
+
" }"
|
| 1213 |
+
],
|
| 1214 |
+
"metadata": {
|
| 1215 |
+
"id": "OL6QbL0H3xuP"
|
| 1216 |
+
},
|
| 1217 |
+
"execution_count": 15,
|
| 1218 |
+
"outputs": []
|
| 1219 |
+
},
|
| 1220 |
+
{
|
| 1221 |
+
"cell_type": "code",
|
| 1222 |
+
"source": [
|
| 1223 |
+
"# === Sanity tests for Level 2 generator ===\n",
|
| 1224 |
+
"\n",
|
| 1225 |
+
"# Test 1: spot-check a few seeds\n",
|
| 1226 |
+
"for seed in [42, 1, 7]:\n",
|
| 1227 |
+
" random.seed(seed)\n",
|
| 1228 |
+
" prog = generate_level_2()\n",
|
| 1229 |
+
" print(f\"\\n=== Level 2, seed={seed} ===\")\n",
|
| 1230 |
+
" print(dump_ir(prog))\n",
|
| 1231 |
+
" print(f\"initial_vars: {prog['initial_vars']}\")\n",
|
| 1232 |
+
" print(f\"initial_mem : {prog['initial_mem']}\")\n",
|
| 1233 |
+
"\n",
|
| 1234 |
+
"# Test 2: full pipeline (CF + DCE + peephole) on a Level 2 program\n",
|
| 1235 |
+
"print(\"\\n=== Full optimization pipeline on Level 2 (seed=42) ===\")\n",
|
| 1236 |
+
"random.seed(42)\n",
|
| 1237 |
+
"prog = generate_level_2()\n",
|
| 1238 |
+
"print(\"ORIGINAL:\")\n",
|
| 1239 |
+
"print(dump_ir(prog))\n",
|
| 1240 |
+
"\n",
|
| 1241 |
+
"after_cf = constant_folding(prog[\"instructions\"])\n",
|
| 1242 |
+
"print(\"\\nAFTER CF:\")\n",
|
| 1243 |
+
"print(dump_ir({**prog, \"instructions\": after_cf}))\n",
|
| 1244 |
+
"\n",
|
| 1245 |
+
"after_dce = dead_code_elimination(after_cf)\n",
|
| 1246 |
+
"print(\"\\nAFTER CF + DCE:\")\n",
|
| 1247 |
+
"print(dump_ir({**prog, \"instructions\": after_dce}))\n",
|
| 1248 |
+
"\n",
|
| 1249 |
+
"after_peep = peephole_optimization(after_dce)\n",
|
| 1250 |
+
"print(\"\\nAFTER CF + DCE + PEEPHOLE:\")\n",
|
| 1251 |
+
"print(dump_ir({**prog, \"instructions\": after_peep}))"
|
| 1252 |
+
],
|
| 1253 |
+
"metadata": {
|
| 1254 |
+
"colab": {
|
| 1255 |
+
"base_uri": "https://localhost:8080/"
|
| 1256 |
+
},
|
| 1257 |
+
"id": "D0XjNetU5gIo",
|
| 1258 |
+
"outputId": "1c35cdfc-a95d-48ff-c7ce-c4c236bbbbdb"
|
| 1259 |
+
},
|
| 1260 |
+
"execution_count": 16,
|
| 1261 |
+
"outputs": [
|
| 1262 |
+
{
|
| 1263 |
+
"output_type": "stream",
|
| 1264 |
+
"name": "stdout",
|
| 1265 |
+
"text": [
|
| 1266 |
+
"\n",
|
| 1267 |
+
"=== Level 2, seed=42 ===\n",
|
| 1268 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1269 |
+
"0: v0 = 2 # CONST [1 cycle]\n",
|
| 1270 |
+
"1: v1 = 1 # CONST [1 cycle]\n",
|
| 1271 |
+
"2: v2 = 5 # CONST [1 cycle]\n",
|
| 1272 |
+
"3: v3 = 4 # CONST [1 cycle]\n",
|
| 1273 |
+
"4: v11 = 19 # CONST [1 cycle]\n",
|
| 1274 |
+
"5: v4 = 4 # CONST [1 cycle]\n",
|
| 1275 |
+
"6: v5 = mem[addr_in] # LOAD [4 cycles]\n",
|
| 1276 |
+
"7: v9 = 18 # CONST [1 cycle]\n",
|
| 1277 |
+
"8: v10 = 8 # CONST [1 cycle]\n",
|
| 1278 |
+
"9: v6 = v4 + v0 # ADD [1 cycle]\n",
|
| 1279 |
+
"10: v7 = v0 // 2 # DIV [5 cycles]\n",
|
| 1280 |
+
"11: v8 = v0 - v3 # SUB [1 cycle]\n",
|
| 1281 |
+
"12: mem[addr0] = v8 # STORE [4 cycles]\n",
|
| 1282 |
+
"// TOTAL: 23 cycles\n",
|
| 1283 |
+
"initial_vars: {'addr0': 0, 'addr_in': 1}\n",
|
| 1284 |
+
"initial_mem : {1: 1}\n",
|
| 1285 |
+
"\n",
|
| 1286 |
+
"=== Level 2, seed=1 ===\n",
|
| 1287 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1288 |
+
"0: v0 = 10 # CONST [1 cycle]\n",
|
| 1289 |
+
"1: v7 = 19 # CONST [1 cycle]\n",
|
| 1290 |
+
"2: v1 = 2 # CONST [1 cycle]\n",
|
| 1291 |
+
"3: v2 = 5 # CONST [1 cycle]\n",
|
| 1292 |
+
"4: v3 = mem[addr_in] # LOAD [4 cycles]\n",
|
| 1293 |
+
"5: v4 = v3 // 2 # DIV [5 cycles]\n",
|
| 1294 |
+
"6: v5 = v3 + v3 # ADD [1 cycle]\n",
|
| 1295 |
+
"7: v6 = v2 + v5 # ADD [1 cycle]\n",
|
| 1296 |
+
"8: mem[addr0] = v6 # STORE [4 cycles]\n",
|
| 1297 |
+
"// TOTAL: 19 cycles\n",
|
| 1298 |
+
"initial_vars: {'addr0': 0, 'addr_in': 1}\n",
|
| 1299 |
+
"initial_mem : {1: 11}\n",
|
| 1300 |
+
"\n",
|
| 1301 |
+
"=== Level 2, seed=7 ===\n",
|
| 1302 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1303 |
+
"0: v0 = 3 # CONST [1 cycle]\n",
|
| 1304 |
+
"1: v1 = 7 # CONST [1 cycle]\n",
|
| 1305 |
+
"2: v2 = 1 # CONST [1 cycle]\n",
|
| 1306 |
+
"3: v3 = 2 # CONST [1 cycle]\n",
|
| 1307 |
+
"4: v4 = mem[addr_in] # LOAD [4 cycles]\n",
|
| 1308 |
+
"5: v5 = v0 + v4 # ADD [1 cycle]\n",
|
| 1309 |
+
"6: v6 = v3 - 3 # SUB [1 cycle]\n",
|
| 1310 |
+
"7: v7 = v4 + 3 # ADD [1 cycle]\n",
|
| 1311 |
+
"8: v10 = 2 # CONST [1 cycle]\n",
|
| 1312 |
+
"9: v8 = v1 + v3 # ADD [1 cycle]\n",
|
| 1313 |
+
"10: v9 = v6 + v0 # ADD [1 cycle]\n",
|
| 1314 |
+
"11: mem[addr0] = v9 # STORE [4 cycles]\n",
|
| 1315 |
+
"// TOTAL: 18 cycles\n",
|
| 1316 |
+
"initial_vars: {'addr0': 0, 'addr_in': 1}\n",
|
| 1317 |
+
"initial_mem : {1: 5}\n",
|
| 1318 |
+
"\n",
|
| 1319 |
+
"=== Full optimization pipeline on Level 2 (seed=42) ===\n",
|
| 1320 |
+
"ORIGINAL:\n",
|
| 1321 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1322 |
+
"0: v0 = 2 # CONST [1 cycle]\n",
|
| 1323 |
+
"1: v1 = 1 # CONST [1 cycle]\n",
|
| 1324 |
+
"2: v2 = 5 # CONST [1 cycle]\n",
|
| 1325 |
+
"3: v3 = 4 # CONST [1 cycle]\n",
|
| 1326 |
+
"4: v11 = 19 # CONST [1 cycle]\n",
|
| 1327 |
+
"5: v4 = 4 # CONST [1 cycle]\n",
|
| 1328 |
+
"6: v5 = mem[addr_in] # LOAD [4 cycles]\n",
|
| 1329 |
+
"7: v9 = 18 # CONST [1 cycle]\n",
|
| 1330 |
+
"8: v10 = 8 # CONST [1 cycle]\n",
|
| 1331 |
+
"9: v6 = v4 + v0 # ADD [1 cycle]\n",
|
| 1332 |
+
"10: v7 = v0 // 2 # DIV [5 cycles]\n",
|
| 1333 |
+
"11: v8 = v0 - v3 # SUB [1 cycle]\n",
|
| 1334 |
+
"12: mem[addr0] = v8 # STORE [4 cycles]\n",
|
| 1335 |
+
"// TOTAL: 23 cycles\n",
|
| 1336 |
+
"\n",
|
| 1337 |
+
"AFTER CF:\n",
|
| 1338 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1339 |
+
"0: v0 = 2 # CONST [1 cycle]\n",
|
| 1340 |
+
"1: v1 = 1 # CONST [1 cycle]\n",
|
| 1341 |
+
"2: v2 = 5 # CONST [1 cycle]\n",
|
| 1342 |
+
"3: v3 = 4 # CONST [1 cycle]\n",
|
| 1343 |
+
"4: v11 = 19 # CONST [1 cycle]\n",
|
| 1344 |
+
"5: v4 = 4 # CONST [1 cycle]\n",
|
| 1345 |
+
"6: v5 = mem[addr_in] # LOAD [4 cycles]\n",
|
| 1346 |
+
"7: v9 = 18 # CONST [1 cycle]\n",
|
| 1347 |
+
"8: v10 = 8 # CONST [1 cycle]\n",
|
| 1348 |
+
"9: v6 = 6 # CONST [1 cycle]\n",
|
| 1349 |
+
"10: v7 = 1 # CONST [1 cycle]\n",
|
| 1350 |
+
"11: v8 = -2 # CONST [1 cycle]\n",
|
| 1351 |
+
"12: mem[addr0] = v8 # STORE [4 cycles]\n",
|
| 1352 |
+
"// TOTAL: 19 cycles\n",
|
| 1353 |
+
"\n",
|
| 1354 |
+
"AFTER CF + DCE:\n",
|
| 1355 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1356 |
+
"0: v8 = -2 # CONST [1 cycle]\n",
|
| 1357 |
+
"1: mem[addr0] = v8 # STORE [4 cycles]\n",
|
| 1358 |
+
"// TOTAL: 5 cycles\n",
|
| 1359 |
+
"\n",
|
| 1360 |
+
"AFTER CF + DCE + PEEPHOLE:\n",
|
| 1361 |
+
"// OBSERVABLE OUT: mem[0]\n",
|
| 1362 |
+
"0: v8 = -2 # CONST [1 cycle]\n",
|
| 1363 |
+
"1: mem[addr0] = v8 # STORE [4 cycles]\n",
|
| 1364 |
+
"// TOTAL: 5 cycles\n"
|
| 1365 |
+
]
|
| 1366 |
+
}
|
| 1367 |
+
]
|
| 1368 |
+
},
|
| 1369 |
+
{
|
| 1370 |
+
"cell_type": "code",
|
| 1371 |
+
"source": [],
|
| 1372 |
+
"metadata": {
|
| 1373 |
+
"id": "Vo-9MitD5hwM"
|
| 1374 |
+
},
|
| 1375 |
+
"execution_count": null,
|
| 1376 |
+
"outputs": []
|
| 1377 |
+
}
|
| 1378 |
+
]
|
| 1379 |
+
}
|
space/space/space/metahack1.ipynb
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 0,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"colab": {
|
| 6 |
+
"provenance": [],
|
| 7 |
+
"gpuType": "T4"
|
| 8 |
+
},
|
| 9 |
+
"kernelspec": {
|
| 10 |
+
"name": "python3",
|
| 11 |
+
"display_name": "Python 3"
|
| 12 |
+
},
|
| 13 |
+
"language_info": {
|
| 14 |
+
"name": "python"
|
| 15 |
+
},
|
| 16 |
+
"accelerator": "GPU"
|
| 17 |
+
},
|
| 18 |
+
"cells": [
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"source": [
|
| 22 |
+
"## Design Assumptions (do not violate)\n",
|
| 23 |
+
"\n",
|
| 24 |
+
"# 1. **DCE never eliminates STOREs.** They define program output (final mem state).\n",
|
| 25 |
+
"# 2. **Addresses are distinct by construction.** Generator allocates each address variable to a unique integer; no aliasing.\n",
|
| 26 |
+
"# 3. **CF refuses to fold DIV by zero.** If src2 == 0 on a DIV op, leave instruction unchanged.\n",
|
| 27 |
+
"# 4. **Generator never emits DIV by literal zero.** When DIV is generated, src2 is always a non-zero constant or a variable known to be non-zero.\n",
|
| 28 |
+
"# # 5. **Integer arithmetic only.** No floats anywhere — avoids equivalence-check precision issues.\n",
|
| 29 |
+
"# 6. Generator declares `observable_addrs` per program — verifier compares only these mem entries.\n",
|
| 30 |
+
"# 7. State translator annotates observable outputs at top of dump.\n",
|
| 31 |
+
"# 8. Reward distinguishes broken (-1000) from valid-but-worse (small negative) — Harshal's formula.\n",
|
| 32 |
+
"# 9. Multi-input verification: 3-5 random initial states, all must match.\n",
|
| 33 |
+
"# 10. Integer division uses Python floor division (//). Aarush's VM must match."
|
| 34 |
+
],
|
| 35 |
+
"metadata": {
|
| 36 |
+
"id": "_XI5jT2Ibvrf"
|
| 37 |
+
},
|
| 38 |
+
"execution_count": 17,
|
| 39 |
+
"outputs": []
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"cell_type": "code",
|
| 43 |
+
"execution_count": 13,
|
| 44 |
+
"metadata": {
|
| 45 |
+
"id": "j6CQ327KWXwr"
|
| 46 |
+
},
|
| 47 |
+
"outputs": [],
|
| 48 |
+
"source": [
|
| 49 |
+
"# === TAC Schema v1.0 (LOCKED with Role 1 / Aarush) ===\n",
|
| 50 |
+
"# Reverse passes deferred to stretch goal — not in initial action space.\n",
|
| 51 |
+
"\n",
|
| 52 |
+
"OPS = [\"CONST\", \"ADD\", \"SUB\", \"MUL\", \"DIV\", \"LOAD\", \"STORE\", \"NOP\"]\n",
|
| 53 |
+
"\n",
|
| 54 |
+
"CYCLE_COSTS = {\n",
|
| 55 |
+
" \"CONST\": 1,\n",
|
| 56 |
+
" \"ADD\": 1,\n",
|
| 57 |
+
" \"SUB\": 1,\n",
|
| 58 |
+
" \"MUL\": 3,\n",
|
| 59 |
+
" \"DIV\": 5,\n",
|
| 60 |
+
" \"LOAD\": 4,\n",
|
| 61 |
+
" \"STORE\": 4,\n",
|
| 62 |
+
" \"NOP\": 0,\n",
|
| 63 |
+
"}\n",
|
| 64 |
+
"\n",
|
| 65 |
+
"# Instruction shape: {\"op\": str, \"dest\": str|None, \"src1\": Any, \"src2\": Any}\n",
|
| 66 |
+
"# Operands: str = variable name, int = literal constant, None = unused\n",
|
| 67 |
+
"#\n",
|
| 68 |
+
"# Op semantics:\n",
|
| 69 |
+
"# CONST: dest = src1 (src1 is int literal, src2 = None)\n",
|
| 70 |
+
"# ADD/SUB/MUL/DIV: dest = src1 OP src2 (src1, src2 are var names or int literals)\n",
|
| 71 |
+
"# LOAD: dest = mem[src1] (src1 is a var holding an address)\n",
|
| 72 |
+
"# STORE: mem[dest] = src1 (dest is a var holding an address)\n",
|
| 73 |
+
"# NOP: no-op (all fields None)\n",
|
| 74 |
+
"#\n",
|
| 75 |
+
"# Program output (for equivalence check) = final memory state (mem dict).\n",
|
| 76 |
+
"# Programs ship as: (initial_vars: dict, initial_mem: dict, instructions: list[dict])\n",
|
| 77 |
+
"# 10. Integer division uses Python floor division (//). Aarush's VM must match."
|
| 78 |
+
]
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"cell_type": "code",
|
| 82 |
+
"source": [
|
| 83 |
+
"import random\n",
|
| 84 |
+
"\n",
|
| 85 |
+
"def generate_level_1():\n",
|
| 86 |
+
" \"\"\"\n",
|
| 87 |
+
" Generate a Level 1 Toy-IR program.\n",
|
| 88 |
+
"\n",
|
| 89 |
+
" Characteristics:\n",
|
| 90 |
+
" - 4-6 instructions\n",
|
| 91 |
+
" - 2-3 CONST ops with literal values\n",
|
| 92 |
+
" - 1-2 arithmetic ops on those constants (foldable by CF)\n",
|
| 93 |
+
" - 0-1 dead variables (killable by DCE)\n",
|
| 94 |
+
" - Exactly 1 STORE at the end so the program has an observable output\n",
|
| 95 |
+
"\n",
|
| 96 |
+
" Returns:\n",
|
| 97 |
+
" dict with keys: initial_vars, initial_mem, instructions, observable_addrs\n",
|
| 98 |
+
" \"\"\"\n",
|
| 99 |
+
" instructions = []\n",
|
| 100 |
+
" var_counter = 0\n",
|
| 101 |
+
"\n",
|
| 102 |
+
" def new_var():\n",
|
| 103 |
+
" nonlocal var_counter\n",
|
| 104 |
+
" name = f\"v{var_counter}\"\n",
|
| 105 |
+
" var_counter += 1\n",
|
| 106 |
+
" return name\n",
|
| 107 |
+
"\n",
|
| 108 |
+
" # Step 1: Generate 2-3 constant assignments\n",
|
| 109 |
+
" num_consts = random.randint(2, 3)\n",
|
| 110 |
+
" const_vars = []\n",
|
| 111 |
+
" for _ in range(num_consts):\n",
|
| 112 |
+
" var = new_var()\n",
|
| 113 |
+
" value = random.randint(1, 10)\n",
|
| 114 |
+
" instructions.append({\"op\": \"CONST\", \"dest\": var, \"src1\": value, \"src2\": None})\n",
|
| 115 |
+
" const_vars.append(var)\n",
|
| 116 |
+
"\n",
|
| 117 |
+
" # Step 2: Generate 1-2 arithmetic ops using those constants\n",
|
| 118 |
+
" num_arith = random.randint(1, 2)\n",
|
| 119 |
+
" last_result = None\n",
|
| 120 |
+
" for _ in range(num_arith):\n",
|
| 121 |
+
" op = random.choice([\"ADD\", \"MUL\"])\n",
|
| 122 |
+
" src1 = random.choice(const_vars)\n",
|
| 123 |
+
" src2 = random.choice(const_vars)\n",
|
| 124 |
+
" dest = new_var()\n",
|
| 125 |
+
" instructions.append({\"op\": op, \"dest\": dest, \"src1\": src1, \"src2\": src2})\n",
|
| 126 |
+
" last_result = dest\n",
|
| 127 |
+
" const_vars.append(dest)\n",
|
| 128 |
+
"\n",
|
| 129 |
+
" # Step 3: Optionally add 1 dead variable (50% chance)\n",
|
| 130 |
+
" if random.random() < 0.5:\n",
|
| 131 |
+
" dead_var = new_var()\n",
|
| 132 |
+
" dead_value = random.randint(1, 10)\n",
|
| 133 |
+
" instructions.append({\"op\": \"CONST\", \"dest\": dead_var, \"src1\": dead_value, \"src2\": None})\n",
|
| 134 |
+
" # Note: dead_var is intentionally never used — DCE should catch it.\n",
|
| 135 |
+
"\n",
|
| 136 |
+
" # Step 4: Add a STORE at the end so the program has observable output\n",
|
| 137 |
+
" initial_vars = {\"addr0\": 0}\n",
|
| 138 |
+
" instructions.append({\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": last_result, \"src2\": None})\n",
|
| 139 |
+
"\n",
|
| 140 |
+
" initial_mem = {}\n",
|
| 141 |
+
"\n",
|
| 142 |
+
" return {\n",
|
| 143 |
+
" \"initial_vars\": initial_vars,\n",
|
| 144 |
+
" \"initial_mem\": initial_mem,\n",
|
| 145 |
+
" \"instructions\": instructions,\n",
|
| 146 |
+
" \"observable_addrs\": [0], # Aarush's verifier compares only these mem entries\n",
|
| 147 |
+
" }\n",
|
| 148 |
+
"\n",
|
| 149 |
+
"\n",
|
| 150 |
+
"# Sanity-check: generate a few programs and print them\n",
|
| 151 |
+
"for seed in [42, 1, 7, 99]:\n",
|
| 152 |
+
" random.seed(seed)\n",
|
| 153 |
+
" prog = generate_level_1()\n",
|
| 154 |
+
" print(f\"\\n=== seed={seed} ===\")\n",
|
| 155 |
+
" print(f\"initial_vars : {prog['initial_vars']}\")\n",
|
| 156 |
+
" print(f\"initial_mem : {prog['initial_mem']}\")\n",
|
| 157 |
+
" print(f\"observable_addrs : {prog['observable_addrs']}\")\n",
|
| 158 |
+
" print(f\"instructions ({len(prog['instructions'])}):\")\n",
|
| 159 |
+
" for i, instr in enumerate(prog['instructions']):\n",
|
| 160 |
+
" print(f\" {i}: {instr}\")"
|
| 161 |
+
],
|
| 162 |
+
"metadata": {
|
| 163 |
+
"colab": {
|
| 164 |
+
"base_uri": "https://localhost:8080/"
|
| 165 |
+
},
|
| 166 |
+
"id": "a86vD1OyWcB9",
|
| 167 |
+
"outputId": "de3d7093-eaea-420e-a0d7-2bd9451bcf6b"
|
| 168 |
+
},
|
| 169 |
+
"execution_count": 14,
|
| 170 |
+
"outputs": [
|
| 171 |
+
{
|
| 172 |
+
"output_type": "stream",
|
| 173 |
+
"name": "stdout",
|
| 174 |
+
"text": [
|
| 175 |
+
"\n",
|
| 176 |
+
"=== seed=42 ===\n",
|
| 177 |
+
"initial_vars : {'addr0': 0}\n",
|
| 178 |
+
"initial_mem : {}\n",
|
| 179 |
+
"observable_addrs : [0]\n",
|
| 180 |
+
"instructions (4):\n",
|
| 181 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 182 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 183 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 184 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 185 |
+
"\n",
|
| 186 |
+
"=== seed=1 ===\n",
|
| 187 |
+
"initial_vars : {'addr0': 0}\n",
|
| 188 |
+
"initial_mem : {}\n",
|
| 189 |
+
"observable_addrs : [0]\n",
|
| 190 |
+
"instructions (5):\n",
|
| 191 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 10, 'src2': None}\n",
|
| 192 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 2, 'src2': None}\n",
|
| 193 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v1', 'src2': 'v1'}\n",
|
| 194 |
+
" 3: {'op': 'MUL', 'dest': 'v3', 'src1': 'v2', 'src2': 'v1'}\n",
|
| 195 |
+
" 4: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 196 |
+
"\n",
|
| 197 |
+
"=== seed=7 ===\n",
|
| 198 |
+
"initial_vars : {'addr0': 0}\n",
|
| 199 |
+
"initial_mem : {}\n",
|
| 200 |
+
"observable_addrs : [0]\n",
|
| 201 |
+
"instructions (6):\n",
|
| 202 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 3, 'src2': None}\n",
|
| 203 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 7, 'src2': None}\n",
|
| 204 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 1, 'src2': None}\n",
|
| 205 |
+
" 3: {'op': 'ADD', 'dest': 'v3', 'src1': 'v1', 'src2': 'v2'}\n",
|
| 206 |
+
" 4: {'op': 'CONST', 'dest': 'v4', 'src1': 9, 'src2': None}\n",
|
| 207 |
+
" 5: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n",
|
| 208 |
+
"\n",
|
| 209 |
+
"=== seed=99 ===\n",
|
| 210 |
+
"initial_vars : {'addr0': 0}\n",
|
| 211 |
+
"initial_mem : {}\n",
|
| 212 |
+
"observable_addrs : [0]\n",
|
| 213 |
+
"instructions (5):\n",
|
| 214 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 7, 'src2': None}\n",
|
| 215 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 4, 'src2': None}\n",
|
| 216 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 10, 'src2': None}\n",
|
| 217 |
+
" 3: {'op': 'ADD', 'dest': 'v3', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 218 |
+
" 4: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v3', 'src2': None}\n"
|
| 219 |
+
]
|
| 220 |
+
}
|
| 221 |
+
]
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"cell_type": "code",
|
| 225 |
+
"source": [
|
| 226 |
+
"def _resolve_operand(operand, known_constants):\n",
|
| 227 |
+
" \"\"\"\n",
|
| 228 |
+
" Given a TAC operand (string variable name or int literal),\n",
|
| 229 |
+
" return its concrete integer value if known, or None if unknown.\n",
|
| 230 |
+
" \"\"\"\n",
|
| 231 |
+
" if isinstance(operand, int):\n",
|
| 232 |
+
" return operand\n",
|
| 233 |
+
" if isinstance(operand, str) and operand in known_constants:\n",
|
| 234 |
+
" return known_constants[operand]\n",
|
| 235 |
+
" return None\n",
|
| 236 |
+
"\n",
|
| 237 |
+
"\n",
|
| 238 |
+
"def _compute(op, v1, v2):\n",
|
| 239 |
+
" \"\"\"Compute the result of a binary arithmetic op on two known integers.\"\"\"\n",
|
| 240 |
+
" if op == \"ADD\": return v1 + v2\n",
|
| 241 |
+
" if op == \"SUB\": return v1 - v2\n",
|
| 242 |
+
" if op == \"MUL\": return v1 * v2\n",
|
| 243 |
+
" if op == \"DIV\": return v1 // v2 # floor division (locked semantics)\n",
|
| 244 |
+
" raise ValueError(f\"_compute called with non-arithmetic op: {op}\")\n",
|
| 245 |
+
"\n",
|
| 246 |
+
"\n",
|
| 247 |
+
"def constant_folding(program):\n",
|
| 248 |
+
" \"\"\"\n",
|
| 249 |
+
" Forward pass that folds constant arithmetic into CONST ops, and\n",
|
| 250 |
+
" propagates known constants into instruction operands.\n",
|
| 251 |
+
"\n",
|
| 252 |
+
" Behavior:\n",
|
| 253 |
+
" - If both sources of an arithmetic op resolve to known integers,\n",
|
| 254 |
+
" replaces the instruction with a CONST holding the computed result.\n",
|
| 255 |
+
" - If only one source is known, still substitutes that known value\n",
|
| 256 |
+
" into the instruction (constant propagation), enabling downstream\n",
|
| 257 |
+
" passes (e.g., peephole) to recognize patterns like ADD-with-0 or MUL-by-1.\n",
|
| 258 |
+
" - Refuses to fold DIV by zero (Design Assumption #3).\n",
|
| 259 |
+
" - Always returns fresh dicts; never aliases input instructions.\n",
|
| 260 |
+
"\n",
|
| 261 |
+
" Args:\n",
|
| 262 |
+
" program: list of TAC instruction dicts (per locked schema).\n",
|
| 263 |
+
"\n",
|
| 264 |
+
" Returns:\n",
|
| 265 |
+
" new list of TAC instruction dicts. Always semantics-preserving.\n",
|
| 266 |
+
" Never raises, never returns None.\n",
|
| 267 |
+
" \"\"\"\n",
|
| 268 |
+
" known_constants = {}\n",
|
| 269 |
+
" new_program = []\n",
|
| 270 |
+
"\n",
|
| 271 |
+
" for instr in program:\n",
|
| 272 |
+
" # Always work on a copy — never alias input dicts\n",
|
| 273 |
+
" instr = instr.copy()\n",
|
| 274 |
+
" op = instr[\"op\"]\n",
|
| 275 |
+
" dest = instr[\"dest\"]\n",
|
| 276 |
+
"\n",
|
| 277 |
+
" if op == \"CONST\":\n",
|
| 278 |
+
" known_constants[dest] = instr[\"src1\"]\n",
|
| 279 |
+
" new_program.append(instr)\n",
|
| 280 |
+
"\n",
|
| 281 |
+
" elif op in (\"ADD\", \"SUB\", \"MUL\", \"DIV\"):\n",
|
| 282 |
+
" # === Constant propagation: substitute known constants into operands ===\n",
|
| 283 |
+
" if isinstance(instr[\"src1\"], str) and instr[\"src1\"] in known_constants:\n",
|
| 284 |
+
" instr[\"src1\"] = known_constants[instr[\"src1\"]]\n",
|
| 285 |
+
" if isinstance(instr[\"src2\"], str) and instr[\"src2\"] in known_constants:\n",
|
| 286 |
+
" instr[\"src2\"] = known_constants[instr[\"src2\"]]\n",
|
| 287 |
+
"\n",
|
| 288 |
+
" # === Try to fold ===\n",
|
| 289 |
+
" v1 = _resolve_operand(instr[\"src1\"], known_constants)\n",
|
| 290 |
+
" v2 = _resolve_operand(instr[\"src2\"], known_constants)\n",
|
| 291 |
+
"\n",
|
| 292 |
+
" if v1 is not None and v2 is not None:\n",
|
| 293 |
+
" # Both operands are known integers\n",
|
| 294 |
+
" if op == \"DIV\" and v2 == 0:\n",
|
| 295 |
+
" # Refuse to fold DIV by zero\n",
|
| 296 |
+
" new_program.append(instr)\n",
|
| 297 |
+
" known_constants.pop(dest, None)\n",
|
| 298 |
+
" else:\n",
|
| 299 |
+
" # Fold: replace with CONST\n",
|
| 300 |
+
" result = _compute(op, v1, v2)\n",
|
| 301 |
+
" new_program.append({\n",
|
| 302 |
+
" \"op\": \"CONST\",\n",
|
| 303 |
+
" \"dest\": dest,\n",
|
| 304 |
+
" \"src1\": result,\n",
|
| 305 |
+
" \"src2\": None,\n",
|
| 306 |
+
" })\n",
|
| 307 |
+
" known_constants[dest] = result\n",
|
| 308 |
+
" else:\n",
|
| 309 |
+
" # Can't fold (at least one operand unknown).\n",
|
| 310 |
+
" # Instruction may still have been mutated by propagation above.\n",
|
| 311 |
+
" new_program.append(instr)\n",
|
| 312 |
+
" known_constants.pop(dest, None)\n",
|
| 313 |
+
"\n",
|
| 314 |
+
" elif op == \"LOAD\":\n",
|
| 315 |
+
" # Memory reads aren't statically resolvable\n",
|
| 316 |
+
" new_program.append(instr)\n",
|
| 317 |
+
" known_constants.pop(dest, None)\n",
|
| 318 |
+
"\n",
|
| 319 |
+
" elif op in (\"STORE\", \"NOP\"):\n",
|
| 320 |
+
" # No dest tracking needed.\n",
|
| 321 |
+
" # Note: we COULD propagate src1 into a STORE for downstream readability,\n",
|
| 322 |
+
" # but the cycle cost is unchanged and the executor handles vars fine.\n",
|
| 323 |
+
" # Leave STORE alone — keeps the code minimal.\n",
|
| 324 |
+
" new_program.append(instr)\n",
|
| 325 |
+
"\n",
|
| 326 |
+
" else:\n",
|
| 327 |
+
" # Unknown op — defensive pass-through\n",
|
| 328 |
+
" new_program.append(instr)\n",
|
| 329 |
+
"\n",
|
| 330 |
+
" return new_program"
|
| 331 |
+
],
|
| 332 |
+
"metadata": {
|
| 333 |
+
"id": "CGk8Fz4CZA3t"
|
| 334 |
+
},
|
| 335 |
+
"execution_count": 18,
|
| 336 |
+
"outputs": []
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"cell_type": "code",
|
| 340 |
+
"source": [
|
| 341 |
+
"# === Sanity tests for constant_folding ===\n",
|
| 342 |
+
"\n",
|
| 343 |
+
"# Test 1: simple fold — ADD of two CONSTs\n",
|
| 344 |
+
"test1 = [\n",
|
| 345 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 3, \"src2\": None},\n",
|
| 346 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 5, \"src2\": None},\n",
|
| 347 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"},\n",
|
| 348 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 349 |
+
"]\n",
|
| 350 |
+
"result1 = constant_folding(test1)\n",
|
| 351 |
+
"print(\"Test 1 (simple ADD fold):\")\n",
|
| 352 |
+
"for i, instr in enumerate(result1): print(f\" {i}: {instr}\")\n",
|
| 353 |
+
"# Expected: instruction 2 becomes CONST c = 8\n",
|
| 354 |
+
"\n",
|
| 355 |
+
"# Test 2: chained fold — second op uses first op's folded result\n",
|
| 356 |
+
"test2 = [\n",
|
| 357 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 3, \"src2\": None},\n",
|
| 358 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 5, \"src2\": None},\n",
|
| 359 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # → 8\n",
|
| 360 |
+
" {\"op\": \"MUL\", \"dest\": \"d\", \"src1\": \"c\", \"src2\": \"b\"}, # → 8 * 5 = 40\n",
|
| 361 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"d\", \"src2\": None},\n",
|
| 362 |
+
"]\n",
|
| 363 |
+
"result2 = constant_folding(test2)\n",
|
| 364 |
+
"print(\"\\nTest 2 (chained fold):\")\n",
|
| 365 |
+
"for i, instr in enumerate(result2): print(f\" {i}: {instr}\")\n",
|
| 366 |
+
"# Expected: c becomes CONST 8, d becomes CONST 40\n",
|
| 367 |
+
"\n",
|
| 368 |
+
"# Test 3: DIV by zero refused\n",
|
| 369 |
+
"test3 = [\n",
|
| 370 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 10, \"src2\": None},\n",
|
| 371 |
+
" {\"op\": \"CONST\", \"dest\": \"b\", \"src1\": 0, \"src2\": None},\n",
|
| 372 |
+
" {\"op\": \"DIV\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # 10/0 — must NOT fold\n",
|
| 373 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 374 |
+
"]\n",
|
| 375 |
+
"result3 = constant_folding(test3)\n",
|
| 376 |
+
"print(\"\\nTest 3 (DIV by zero refused):\")\n",
|
| 377 |
+
"for i, instr in enumerate(result3): print(f\" {i}: {instr}\")\n",
|
| 378 |
+
"# Expected: instruction 2 unchanged (still DIV, not CONST)\n",
|
| 379 |
+
"\n",
|
| 380 |
+
"# Test 4: unknown source can't fold\n",
|
| 381 |
+
"test4 = [\n",
|
| 382 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 3, \"src2\": None},\n",
|
| 383 |
+
" {\"op\": \"LOAD\", \"dest\": \"b\", \"src1\": \"addr0\", \"src2\": None}, # b is unknown\n",
|
| 384 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # can't fold\n",
|
| 385 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 386 |
+
"]\n",
|
| 387 |
+
"result4 = constant_folding(test4)\n",
|
| 388 |
+
"print(\"\\nTest 4 (LOAD makes b unknown, ADD not folded):\")\n",
|
| 389 |
+
"for i, instr in enumerate(result4): print(f\" {i}: {instr}\")\n",
|
| 390 |
+
"# Expected: instruction 2 unchanged (still ADD)\n",
|
| 391 |
+
"\n",
|
| 392 |
+
"# Test 5: idempotence — running CF on a generated program\n",
|
| 393 |
+
"random.seed(42)\n",
|
| 394 |
+
"prog = generate_level_1()\n",
|
| 395 |
+
"folded = constant_folding(prog[\"instructions\"])\n",
|
| 396 |
+
"print(\"\\nTest 5 (CF on generated Level 1 program, seed=42):\")\n",
|
| 397 |
+
"print(\"Before:\")\n",
|
| 398 |
+
"for i, instr in enumerate(prog[\"instructions\"]): print(f\" {i}: {instr}\")\n",
|
| 399 |
+
"print(\"After:\")\n",
|
| 400 |
+
"for i, instr in enumerate(folded): print(f\" {i}: {instr}\")\n",
|
| 401 |
+
"\n",
|
| 402 |
+
"# Test 6: constant propagation — only one source is known\n",
|
| 403 |
+
"test6 = [\n",
|
| 404 |
+
" {\"op\": \"CONST\", \"dest\": \"a\", \"src1\": 0, \"src2\": None},\n",
|
| 405 |
+
" {\"op\": \"LOAD\", \"dest\": \"b\", \"src1\": \"addr0\", \"src2\": None}, # b unknown\n",
|
| 406 |
+
" {\"op\": \"ADD\", \"dest\": \"c\", \"src1\": \"a\", \"src2\": \"b\"}, # a known (=0), b unknown\n",
|
| 407 |
+
" {\"op\": \"STORE\", \"dest\": \"addr0\", \"src1\": \"c\", \"src2\": None},\n",
|
| 408 |
+
"]\n",
|
| 409 |
+
"result6 = constant_folding(test6)\n",
|
| 410 |
+
"print(\"\\nTest 6 (propagation: a=0 substituted into ADD even though b unknown):\")\n",
|
| 411 |
+
"for i, instr in enumerate(result6): print(f\" {i}: {instr}\")\n",
|
| 412 |
+
"# Expected: instruction 2 is still ADD (can't fold — b unknown), but src1 is now literal 0, not 'a'\n",
|
| 413 |
+
"# This sets up peephole to recognize \"ADD with 0\" later"
|
| 414 |
+
],
|
| 415 |
+
"metadata": {
|
| 416 |
+
"colab": {
|
| 417 |
+
"base_uri": "https://localhost:8080/"
|
| 418 |
+
},
|
| 419 |
+
"id": "WLKSTVa8fRF8",
|
| 420 |
+
"outputId": "27042d38-0044-4814-bbfa-8a2c2d87ee06"
|
| 421 |
+
},
|
| 422 |
+
"execution_count": 20,
|
| 423 |
+
"outputs": [
|
| 424 |
+
{
|
| 425 |
+
"output_type": "stream",
|
| 426 |
+
"name": "stdout",
|
| 427 |
+
"text": [
|
| 428 |
+
"Test 1 (simple ADD fold):\n",
|
| 429 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 3, 'src2': None}\n",
|
| 430 |
+
" 1: {'op': 'CONST', 'dest': 'b', 'src1': 5, 'src2': None}\n",
|
| 431 |
+
" 2: {'op': 'CONST', 'dest': 'c', 'src1': 8, 'src2': None}\n",
|
| 432 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 433 |
+
"\n",
|
| 434 |
+
"Test 2 (chained fold):\n",
|
| 435 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 3, 'src2': None}\n",
|
| 436 |
+
" 1: {'op': 'CONST', 'dest': 'b', 'src1': 5, 'src2': None}\n",
|
| 437 |
+
" 2: {'op': 'CONST', 'dest': 'c', 'src1': 8, 'src2': None}\n",
|
| 438 |
+
" 3: {'op': 'CONST', 'dest': 'd', 'src1': 40, 'src2': None}\n",
|
| 439 |
+
" 4: {'op': 'STORE', 'dest': 'addr0', 'src1': 'd', 'src2': None}\n",
|
| 440 |
+
"\n",
|
| 441 |
+
"Test 3 (DIV by zero refused):\n",
|
| 442 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 10, 'src2': None}\n",
|
| 443 |
+
" 1: {'op': 'CONST', 'dest': 'b', 'src1': 0, 'src2': None}\n",
|
| 444 |
+
" 2: {'op': 'DIV', 'dest': 'c', 'src1': 10, 'src2': 0}\n",
|
| 445 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 446 |
+
"\n",
|
| 447 |
+
"Test 4 (LOAD makes b unknown, ADD not folded):\n",
|
| 448 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 3, 'src2': None}\n",
|
| 449 |
+
" 1: {'op': 'LOAD', 'dest': 'b', 'src1': 'addr0', 'src2': None}\n",
|
| 450 |
+
" 2: {'op': 'ADD', 'dest': 'c', 'src1': 3, 'src2': 'b'}\n",
|
| 451 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n",
|
| 452 |
+
"\n",
|
| 453 |
+
"Test 5 (CF on generated Level 1 program, seed=42):\n",
|
| 454 |
+
"Before:\n",
|
| 455 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 456 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 457 |
+
" 2: {'op': 'ADD', 'dest': 'v2', 'src1': 'v0', 'src2': 'v0'}\n",
|
| 458 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 459 |
+
"After:\n",
|
| 460 |
+
" 0: {'op': 'CONST', 'dest': 'v0', 'src1': 1, 'src2': None}\n",
|
| 461 |
+
" 1: {'op': 'CONST', 'dest': 'v1', 'src1': 5, 'src2': None}\n",
|
| 462 |
+
" 2: {'op': 'CONST', 'dest': 'v2', 'src1': 2, 'src2': None}\n",
|
| 463 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'v2', 'src2': None}\n",
|
| 464 |
+
"\n",
|
| 465 |
+
"Test 6 (propagation: a=0 substituted into ADD even though b unknown):\n",
|
| 466 |
+
" 0: {'op': 'CONST', 'dest': 'a', 'src1': 0, 'src2': None}\n",
|
| 467 |
+
" 1: {'op': 'LOAD', 'dest': 'b', 'src1': 'addr0', 'src2': None}\n",
|
| 468 |
+
" 2: {'op': 'ADD', 'dest': 'c', 'src1': 0, 'src2': 'b'}\n",
|
| 469 |
+
" 3: {'op': 'STORE', 'dest': 'addr0', 'src1': 'c', 'src2': None}\n"
|
| 470 |
+
]
|
| 471 |
+
}
|
| 472 |
+
]
|
| 473 |
+
},
|
| 474 |
+
{
|
| 475 |
+
"cell_type": "code",
|
| 476 |
+
"source": [],
|
| 477 |
+
"metadata": {
|
| 478 |
+
"id": "5vo-KgaffTFR"
|
| 479 |
+
},
|
| 480 |
+
"execution_count": null,
|
| 481 |
+
"outputs": []
|
| 482 |
+
}
|
| 483 |
+
]
|
| 484 |
+
}
|
space/space/space/space/.github/workflows/deploy.yml
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Deploy to Hugging Face Space
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
|
| 8 |
+
jobs:
|
| 9 |
+
deploy:
|
| 10 |
+
runs-on: ubuntu-latest
|
| 11 |
+
|
| 12 |
+
steps:
|
| 13 |
+
- name: Checkout Repo
|
| 14 |
+
uses: actions/checkout@v4
|
| 15 |
+
|
| 16 |
+
- name: Push to Hugging Face
|
| 17 |
+
env:
|
| 18 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 19 |
+
run: |
|
| 20 |
+
git config --global user.email "github-actions@github.com"
|
| 21 |
+
git config --global user.name "github-actions"
|
| 22 |
+
|
| 23 |
+
git clone https://user:$HF_TOKEN@huggingface.co/spaces/greedybeserk95/Compilertetris space
|
| 24 |
+
|
| 25 |
+
rsync -av --exclude ".git" ./ space/
|
| 26 |
+
|
| 27 |
+
cd space
|
| 28 |
+
git add .
|
| 29 |
+
git commit -m "Auto deploy from GitHub" || echo "No changes"
|
| 30 |
+
git push
|
space/space/space/space/README.md
CHANGED
|
@@ -1,11 +1 @@
|
|
| 1 |
-
|
| 2 |
-
title: Compilertetris
|
| 3 |
-
emoji: ⚡
|
| 4 |
-
colorFrom: red
|
| 5 |
-
colorTo: gray
|
| 6 |
-
sdk: docker
|
| 7 |
-
pinned: false
|
| 8 |
-
short_description: an RL environment which optimizes IR code
|
| 9 |
-
---
|
| 10 |
-
|
| 11 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
+
# MetaHackathon2026Finals
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
space/space/space/space/space/.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
space/space/space/space/space/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Compilertetris
|
| 3 |
+
emoji: ⚡
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: gray
|
| 6 |
+
sdk: docker
|
| 7 |
+
pinned: false
|
| 8 |
+
short_description: an RL environment which optimizes IR code
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|