// tools/hako_shared/mir_analyzer.hako - MirAnalyzerBox (Phase 161-2) // .hako native MIR JSON v1 analyzer for JoinIR/MIR analysis // Provides PHI/loop/if detection algorithms // MirAnalyzerBox: Main analyzer for MIR JSON v1 box MirAnalyzerBox { _mir_json: MapBox // Parsed MIR JSON root _functions: ArrayBox // Cached functions array _verbose: integer // Verbose mode (0=off, 1=on) // Constructor: Parse MIR JSON v1 from text birth(mir_json_text) { me._verbose = 0 // Parse JSON using JsonParserBox me._mir_json = JsonParserBox.parse_object(mir_json_text) if me._mir_json == null { print("[MirAnalyzerBox] ERROR: Failed to parse MIR JSON") return null } // Extract functions array me._functions = me._mir_json.get("functions") if me._functions == null { print("[MirAnalyzerBox] ERROR: No 'functions' field in MIR JSON") return null } if me._verbose == 1 { print("[MirAnalyzerBox] Parsed MIR JSON successfully") print("[MirAnalyzerBox] Functions count: " + me._functions.size()) } return me } // Validate MIR JSON v1 schema validateSchema() { if me._mir_json == null { return 0 } // Check required top-level fields local capabilities = me._mir_json.get("capabilities") if capabilities == null { print("[MirAnalyzerBox] ERROR: Missing 'capabilities' field") return 0 } if me._functions == null { print("[MirAnalyzerBox] ERROR: Missing 'functions' field") return 0 } // Check functions array is not empty if me._functions.size() == 0 { print("[MirAnalyzerBox] WARNING: Empty functions array") } if me._verbose == 1 { print("[MirAnalyzerBox] Schema validation: PASS") } return 1 } // Summarize function metadata // Returns: MapBox with {name, params, blocks, instructions, has_loops, has_ifs, has_phis} summarize_function(funcIndex) { local func = me._get_function(funcIndex) if func == null { print("[MirAnalyzerBox] ERROR: Function index out of bounds: " + funcIndex) return null } local summary = new MapBox() // Basic metadata local name = func.get("name") summary.set("name", name) local params = func.get("params") if params == null { summary.set("param_count", 0) } else { summary.set("param_count", params.size()) } // Block count local blocks = func.get("blocks") if blocks == null { summary.set("block_count", 0) summary.set("instruction_count", 0) summary.set("has_phis", 0) summary.set("has_loops", 0) summary.set("has_ifs", 0) return summary } summary.set("block_count", blocks.size()) // Count instructions and detect patterns local total_instructions = 0 local has_phi = 0 local has_branch = 0 local i = 0 loop(i < blocks.size()) { local block = blocks.get(i) local instructions = block.get("instructions") if instructions != null { total_instructions = total_instructions + instructions.size() // Check for PHI and Branch instructions local j = 0 loop(j < instructions.size()) { local inst = instructions.get(j) local op = inst.get("op") if op == "phi" { has_phi = 1 } if op == "branch" { has_branch = 1 } j = j + 1 } } i = i + 1 } summary.set("instruction_count", total_instructions) summary.set("has_phis", has_phi) summary.set("has_ifs", has_branch) // Loop detection (basic backward edge check) local has_loop = me._has_backward_edge(blocks) summary.set("has_loops", has_loop) if me._verbose == 1 { print("[MirAnalyzerBox] Summary for " + name + ":") print(" Blocks: " + blocks.size()) print(" Instructions: " + total_instructions) print(" Has PHI: " + has_phi) print(" Has Branch: " + has_branch) print(" Has Loop: " + has_loop) } return summary } // Count PHI instructions in function // Returns: ArrayBox of {block_id, dest, incoming_count} count_phis(funcIndex) { local func = me._get_function(funcIndex) if func == null { print("[MirAnalyzerBox] ERROR: Function index out of bounds: " + funcIndex) return null } local blocks = func.get("blocks") if blocks == null { return new ArrayBox() } local phi_list = new ArrayBox() local i = 0 loop(i < blocks.size()) { local block = blocks.get(i) local block_id = block.get("id") local instructions = block.get("instructions") if instructions != null { local j = 0 loop(j < instructions.size()) { local inst = instructions.get(j) local op = inst.get("op") if op == "phi" { local phi_info = new MapBox() phi_info.set("block_id", block_id) local dest = inst.get("dst") phi_info.set("dest", dest) local incoming = inst.get("incoming") if incoming == null { phi_info.set("incoming_count", 0) } else { phi_info.set("incoming_count", incoming.size()) } phi_list.push(phi_info) if me._verbose == 1 { print("[MirAnalyzerBox] PHI found: block=" + block_id + " dest=" + dest) } } j = j + 1 } } i = i + 1 } return phi_list } // Count loops in function (via CFG backward edge detection) // Returns: integer count of loops detected count_loops(funcIndex) { local func = me._get_function(funcIndex) if func == null { print("[MirAnalyzerBox] ERROR: Function index out of bounds: " + funcIndex) return 0 } local blocks = func.get("blocks") if blocks == null { return 0 } // Build block_id -> block_index map for quick lookup local block_map = new MapBox() local i = 0 loop(i < blocks.size()) { local block = blocks.get(i) local block_id = block.get("id") block_map.set("" + block_id, i) i = i + 1 } // Count backward edges (target_id < source_id) local loop_count = 0 i = 0 loop(i < blocks.size()) { local block = blocks.get(i) local block_id = block.get("id") local instructions = block.get("instructions") if instructions != null { // Check last instruction for control flow local last_idx = instructions.size() - 1 if last_idx >= 0 { local last_inst = instructions.get(last_idx) local op = last_inst.get("op") // Check jump instruction if op == "jump" { local target = last_inst.get("target") if target != null { if target < block_id { loop_count = loop_count + 1 if me._verbose == 1 { print("[MirAnalyzerBox] Backward edge: block " + block_id + " -> " + target) } } } } // Check branch instruction (both targets) if op == "branch" { local then_target = last_inst.get("then") local else_target = last_inst.get("else") if then_target != null { if then_target < block_id { loop_count = loop_count + 1 if me._verbose == 1 { print("[MirAnalyzerBox] Backward edge (then): block " + block_id + " -> " + then_target) } } } if else_target != null { if else_target < block_id { loop_count = loop_count + 1 if me._verbose == 1 { print("[MirAnalyzerBox] Backward edge (else): block " + block_id + " -> " + else_target) } } } } } } i = i + 1 } return loop_count } // Enable/disable verbose mode set_verbose(enabled) { if enabled == 1 { me._verbose = 1 print("[MirAnalyzerBox] Verbose mode: ON") } else { me._verbose = 0 } } // Internal: Get function by index _get_function(funcIndex) { if me._functions == null { return null } if funcIndex < 0 { return null } if funcIndex >= me._functions.size() { return null } return me._functions.get(funcIndex) } // Internal: Check if function has backward edges (loop indicator) _has_backward_edge(blocks) { if blocks == null { return 0 } local i = 0 loop(i < blocks.size()) { local block = blocks.get(i) local block_id = block.get("id") local instructions = block.get("instructions") if instructions != null { local last_idx = instructions.size() - 1 if last_idx >= 0 { local last_inst = instructions.get(last_idx) local op = last_inst.get("op") if op == "jump" { local target = last_inst.get("target") if target != null { if target < block_id { return 1 } } } if op == "branch" { local then_target = last_inst.get("then") local else_target = last_inst.get("else") if then_target != null { if then_target < block_id { return 1 } } if else_target != null { if else_target < block_id { return 1 } } } } } i = i + 1 } return 0 } } // Main entry point for standalone testing static box MirAnalyzerMain { main(args) { print("[MirAnalyzerMain] Phase 161-2 Basic MirAnalyzerBox Implementation") print("[MirAnalyzerMain] Usage: provide MIR JSON file path as argument") // TODO: Add file reading and analysis test return 0 } }