| ... | ... | @@ -68,58 +68,35 @@ pub const Code = struct { |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | /// For debugging purposes, like dumpFn but for unanalyzed zir blocks |
| 71 | | pub fn dump(code: Code, gpa: *Allocator, kind: []const u8, decl_name: [*:0]const u8) !void { |
| 71 | pub fn dump( |
| 72 | code: Code, |
| 73 | gpa: *Allocator, |
| 74 | kind: []const u8, |
| 75 | decl_name: [*:0]const u8, |
| 76 | param_count: usize, |
| 77 | ) !void { |
| 72 | 78 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 73 | 79 | defer arena.deinit(); |
| 74 | 80 | |
| 75 | | if (true) @panic("TODO fix this function for zir-memory-layout branch"); |
| 76 | | |
| 77 | 81 | var writer: Writer = .{ |
| 78 | 82 | .gpa = gpa, |
| 79 | 83 | .arena = &arena.allocator, |
| 80 | 84 | .code = code, |
| 81 | | .inst_map = try arena.allocator.alloc(*ir.Inst, code.instructions.len), |
| 82 | | .owner_decl = decl, |
| 83 | | .func = null, |
| 84 | | .param_inst_list = &.{}, |
| 85 | | }; |
| 86 | | var write = Writer{ |
| 87 | | .inst_table = InstPtrTable.init(gpa), |
| 88 | | .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(gpa), |
| 89 | | .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(gpa), |
| 90 | | .arena = std.heap.ArenaAllocator.init(gpa), |
| 91 | 85 | .indent = 4, |
| 92 | | .next_instr_index = 0, |
| 86 | .param_count = param_count, |
| 93 | 87 | }; |
| 94 | | defer write.arena.deinit(); |
| 95 | | defer write.inst_table.deinit(); |
| 96 | | defer write.block_table.deinit(); |
| 97 | | defer write.loop_table.deinit(); |
| 98 | | |
| 99 | | try write.inst_table.ensureCapacity(@intCast(u32, instructions.len)); |
| 100 | 88 | |
| 101 | 89 | const stderr = std.io.getStdErr().writer(); |
| 102 | | try stderr.print("{s} {s} {{ // unanalyzed\n", .{ kind, decl_name }); |
| 103 | | |
| 104 | | for (instructions) |inst| { |
| 105 | | const my_i = write.next_instr_index; |
| 106 | | write.next_instr_index += 1; |
| 107 | | |
| 108 | | if (inst.cast(Inst.Block)) |block| { |
| 109 | | const name = try std.fmt.allocPrint(&write.arena.allocator, "label_{d}", .{my_i}); |
| 110 | | try write.block_table.put(block, name); |
| 111 | | } else if (inst.cast(Inst.Loop)) |loop| { |
| 112 | | const name = try std.fmt.allocPrint(&write.arena.allocator, "loop_{d}", .{my_i}); |
| 113 | | try write.loop_table.put(loop, name); |
| 114 | | } |
| 90 | try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name }); |
| 115 | 91 | |
| 116 | | try write.inst_table.putNoClobber(inst, .{ .inst = inst, .index = my_i, .name = "inst" }); |
| 117 | | try stderr.print(" %{d} ", .{my_i}); |
| 118 | | try write.writeInstToStream(stderr, inst); |
| 92 | const root_body = code.extra[code.root_start..][0..code.root_len]; |
| 93 | for (root_body) |inst| { |
| 94 | try stderr.print(" %{d} ", .{inst}); |
| 95 | try writer.writeInstToStream(stderr, inst); |
| 119 | 96 | try stderr.writeByte('\n'); |
| 120 | 97 | } |
| 121 | 98 | |
| 122 | | try stderr.print("}} // {s} {s}\n\n", .{ kind, decl_name }); |
| 99 | try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name }); |
| 123 | 100 | } |
| 124 | 101 | }; |
| 125 | 102 | |
| ... | ... | @@ -679,10 +656,10 @@ pub const Inst = struct { |
| 679 | 656 | /// Resume an async function. |
| 680 | 657 | @"resume", |
| 681 | 658 | /// Obtains a pointer to the return value. |
| 682 | | /// lhs and rhs unused. |
| 659 | /// Uses the `node` union field. |
| 683 | 660 | ret_ptr, |
| 684 | 661 | /// Obtains the return type of the in-scope function. |
| 685 | | /// lhs and rhs unused. |
| 662 | /// Uses the `node` union field. |
| 686 | 663 | ret_type, |
| 687 | 664 | /// Sends control flow back to the function's callee. |
| 688 | 665 | /// Includes an operand as the return value. |
| ... | ... | @@ -821,7 +798,7 @@ pub const Inst = struct { |
| 821 | 798 | /// Uses the `un_node` union field. |
| 822 | 799 | suspend_block_one, |
| 823 | 800 | /// Suspend an async function. The suspend block has any number of statements in it. |
| 824 | | /// Uses the `block` union field. |
| 801 | /// Uses the `pl_node` union field. Payload is `MultiOp`. |
| 825 | 802 | suspend_block, |
| 826 | 803 | // /// A switch expression. |
| 827 | 804 | // /// lhs is target, SwitchBr[rhs] |
| ... | ... | @@ -1266,3 +1243,404 @@ pub const Inst = struct { |
| 1266 | 1243 | field_name: Ref, |
| 1267 | 1244 | }; |
| 1268 | 1245 | }; |
| 1246 | |
| 1247 | const Writer = struct { |
| 1248 | gpa: *Allocator, |
| 1249 | arena: *Allocator, |
| 1250 | code: Code, |
| 1251 | indent: usize, |
| 1252 | param_count: usize, |
| 1253 | |
| 1254 | fn writeInstToStream( |
| 1255 | self: *Writer, |
| 1256 | stream: anytype, |
| 1257 | inst: Inst.Index, |
| 1258 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1259 | const tags = self.code.instructions.items(.tag); |
| 1260 | const tag = tags[inst]; |
| 1261 | try stream.print("= {s}(", .{@tagName(tags[inst])}); |
| 1262 | switch (tag) { |
| 1263 | .add, |
| 1264 | .addwrap, |
| 1265 | .array_cat, |
| 1266 | .array_mul, |
| 1267 | .mul, |
| 1268 | .mulwrap, |
| 1269 | .sub, |
| 1270 | .subwrap, |
| 1271 | .array_type, |
| 1272 | .bit_and, |
| 1273 | .bit_or, |
| 1274 | .as, |
| 1275 | .bool_and, |
| 1276 | .bool_or, |
| 1277 | .@"break", |
| 1278 | .cmp_lt, |
| 1279 | .cmp_lte, |
| 1280 | .cmp_eq, |
| 1281 | .cmp_gte, |
| 1282 | .cmp_gt, |
| 1283 | .cmp_neq, |
| 1284 | .coerce_result_ptr, |
| 1285 | .div, |
| 1286 | .mod_rem, |
| 1287 | .shl, |
| 1288 | .shr, |
| 1289 | .xor, |
| 1290 | .elem_ptr, |
| 1291 | .elem_val, |
| 1292 | .intcast, |
| 1293 | .int_type, |
| 1294 | .merge_error_sets, |
| 1295 | => try self.writeBin(stream, inst), |
| 1296 | |
| 1297 | .alloc, |
| 1298 | .alloc_mut, |
| 1299 | .alloc_inferred, |
| 1300 | .alloc_inferred_mut, |
| 1301 | .anyframe_type, |
| 1302 | .indexable_ptr_len, |
| 1303 | .@"await", |
| 1304 | .bit_not, |
| 1305 | .call_none, |
| 1306 | .compile_error, |
| 1307 | .deref_node, |
| 1308 | .ensure_result_used, |
| 1309 | .ensure_result_non_error, |
| 1310 | .import, |
| 1311 | .ptrtoint, |
| 1312 | .ret_node, |
| 1313 | .set_eval_branch_quota, |
| 1314 | .resolve_inferred_alloc, |
| 1315 | .suspend_block_one, |
| 1316 | => try self.writeUnNode(stream, inst), |
| 1317 | |
| 1318 | .bool_not, |
| 1319 | .break_void_tok, |
| 1320 | .is_non_null, |
| 1321 | .is_null, |
| 1322 | .is_non_null_ptr, |
| 1323 | .is_null_ptr, |
| 1324 | .is_err, |
| 1325 | .is_err_ptr, |
| 1326 | .ref, |
| 1327 | .ret_tok, |
| 1328 | .typeof, |
| 1329 | .optional_type, |
| 1330 | .optional_type_from_ptr_elem, |
| 1331 | .optional_payload_safe, |
| 1332 | .optional_payload_unsafe, |
| 1333 | .optional_payload_safe_ptr, |
| 1334 | .optional_payload_unsafe_ptr, |
| 1335 | .err_union_payload_safe, |
| 1336 | .err_union_payload_unsafe, |
| 1337 | .err_union_payload_safe_ptr, |
| 1338 | .err_union_payload_unsafe_ptr, |
| 1339 | .err_union_code, |
| 1340 | .err_union_code_ptr, |
| 1341 | .ensure_err_payload_void, |
| 1342 | => try self.writeUnTok(stream, inst), |
| 1343 | |
| 1344 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), |
| 1345 | .@"const" => try self.writeConst(stream, inst), |
| 1346 | .param_type => try self.writeParamType(stream, inst), |
| 1347 | .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), |
| 1348 | .ptr_type => try self.writePtrType(stream, inst), |
| 1349 | .int => try self.writeInt(stream, inst), |
| 1350 | .str => try self.writeStr(stream, inst), |
| 1351 | |
| 1352 | .@"asm", |
| 1353 | .asm_volatile, |
| 1354 | .block, |
| 1355 | .block_flat, |
| 1356 | .block_comptime, |
| 1357 | .block_comptime_flat, |
| 1358 | .call, |
| 1359 | .call_async_kw, |
| 1360 | .call_no_async, |
| 1361 | .call_compile_time, |
| 1362 | .compile_log, |
| 1363 | .condbr, |
| 1364 | .elem_ptr_node, |
| 1365 | .elem_val_node, |
| 1366 | .field_ptr, |
| 1367 | .field_val, |
| 1368 | .field_ptr_named, |
| 1369 | .field_val_named, |
| 1370 | .floatcast, |
| 1371 | .loop, |
| 1372 | .slice_start, |
| 1373 | .slice_end, |
| 1374 | .slice_sentinel, |
| 1375 | .typeof_peer, |
| 1376 | .suspend_block, |
| 1377 | => try self.writePlNode(stream, inst), |
| 1378 | |
| 1379 | .breakpoint, |
| 1380 | .dbg_stmt_node, |
| 1381 | .ret_ptr, |
| 1382 | .ret_type, |
| 1383 | .unreachable_unsafe, |
| 1384 | .unreachable_safe, |
| 1385 | => try self.writeNode(stream, inst), |
| 1386 | |
| 1387 | .decl_ref, |
| 1388 | .decl_val, |
| 1389 | => try self.writeDecl(stream, inst), |
| 1390 | |
| 1391 | .error_value, |
| 1392 | .enum_literal, |
| 1393 | => try self.writeStrTok(stream, inst), |
| 1394 | |
| 1395 | .fn_type => try self.writeFnType(stream, inst, false), |
| 1396 | .fn_type_cc => try self.writeFnTypeCc(stream, inst, false), |
| 1397 | .fn_type_var_args => try self.writeFnType(stream, inst, true), |
| 1398 | .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true), |
| 1399 | |
| 1400 | .enum_literal_small => try self.writeSmallStr(stream, inst), |
| 1401 | |
| 1402 | .bitcast, |
| 1403 | .bitcast_ref, |
| 1404 | .bitcast_result_ptr, |
| 1405 | .error_union_type, |
| 1406 | .error_set, |
| 1407 | .nosuspend_await, |
| 1408 | .@"resume", |
| 1409 | .store, |
| 1410 | .store_to_block_ptr, |
| 1411 | .store_to_inferred_ptr, |
| 1412 | => try stream.writeAll("TODO)"), |
| 1413 | } |
| 1414 | } |
| 1415 | |
| 1416 | fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1417 | const inst_data = self.code.instructions.items(.data)[inst].bin; |
| 1418 | try self.writeInstRef(stream, inst_data.lhs); |
| 1419 | try stream.writeAll(", "); |
| 1420 | try self.writeInstRef(stream, inst_data.rhs); |
| 1421 | try stream.writeByte(')'); |
| 1422 | } |
| 1423 | |
| 1424 | fn writeUnNode( |
| 1425 | self: *Writer, |
| 1426 | stream: anytype, |
| 1427 | inst: Inst.Index, |
| 1428 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1429 | const inst_data = self.code.instructions.items(.data)[inst].un_node; |
| 1430 | try self.writeInstRef(stream, inst_data.operand); |
| 1431 | try stream.writeAll(") "); |
| 1432 | try self.writeSrc(stream, inst_data.src()); |
| 1433 | } |
| 1434 | |
| 1435 | fn writeUnTok( |
| 1436 | self: *Writer, |
| 1437 | stream: anytype, |
| 1438 | inst: Inst.Index, |
| 1439 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1440 | const inst_data = self.code.instructions.items(.data)[inst].un_tok; |
| 1441 | try self.writeInstRef(stream, inst_data.operand); |
| 1442 | try stream.writeAll(") "); |
| 1443 | try self.writeSrc(stream, inst_data.src()); |
| 1444 | } |
| 1445 | |
| 1446 | fn writeArrayTypeSentinel( |
| 1447 | self: *Writer, |
| 1448 | stream: anytype, |
| 1449 | inst: Inst.Index, |
| 1450 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1451 | const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel; |
| 1452 | try stream.writeAll("TODO)"); |
| 1453 | } |
| 1454 | |
| 1455 | fn writeConst( |
| 1456 | self: *Writer, |
| 1457 | stream: anytype, |
| 1458 | inst: Inst.Index, |
| 1459 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1460 | const inst_data = self.code.instructions.items(.data)[inst].@"const"; |
| 1461 | try stream.writeAll("TODO)"); |
| 1462 | } |
| 1463 | |
| 1464 | fn writeParamType( |
| 1465 | self: *Writer, |
| 1466 | stream: anytype, |
| 1467 | inst: Inst.Index, |
| 1468 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1469 | const inst_data = self.code.instructions.items(.data)[inst].param_type; |
| 1470 | try stream.writeAll("TODO)"); |
| 1471 | } |
| 1472 | |
| 1473 | fn writePtrTypeSimple( |
| 1474 | self: *Writer, |
| 1475 | stream: anytype, |
| 1476 | inst: Inst.Index, |
| 1477 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1478 | const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple; |
| 1479 | try stream.writeAll("TODO)"); |
| 1480 | } |
| 1481 | |
| 1482 | fn writePtrType( |
| 1483 | self: *Writer, |
| 1484 | stream: anytype, |
| 1485 | inst: Inst.Index, |
| 1486 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1487 | const inst_data = self.code.instructions.items(.data)[inst].ptr_type; |
| 1488 | try stream.writeAll("TODO)"); |
| 1489 | } |
| 1490 | |
| 1491 | fn writeInt( |
| 1492 | self: *Writer, |
| 1493 | stream: anytype, |
| 1494 | inst: Inst.Index, |
| 1495 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1496 | const inst_data = self.code.instructions.items(.data)[inst].int; |
| 1497 | try stream.print("{d})", .{inst_data}); |
| 1498 | } |
| 1499 | |
| 1500 | fn writeStr( |
| 1501 | self: *Writer, |
| 1502 | stream: anytype, |
| 1503 | inst: Inst.Index, |
| 1504 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1505 | const inst_data = self.code.instructions.items(.data)[inst].str; |
| 1506 | const str = inst_data.get(self.code); |
| 1507 | try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); |
| 1508 | } |
| 1509 | |
| 1510 | fn writePlNode( |
| 1511 | self: *Writer, |
| 1512 | stream: anytype, |
| 1513 | inst: Inst.Index, |
| 1514 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1515 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1516 | try stream.writeAll("TODO) "); |
| 1517 | try self.writeSrc(stream, inst_data.src()); |
| 1518 | } |
| 1519 | |
| 1520 | fn writeNode( |
| 1521 | self: *Writer, |
| 1522 | stream: anytype, |
| 1523 | inst: Inst.Index, |
| 1524 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1525 | const src_node = self.code.instructions.items(.data)[inst].node; |
| 1526 | const src: LazySrcLoc = .{ .node_offset = src_node }; |
| 1527 | try stream.writeAll(") "); |
| 1528 | try self.writeSrc(stream, src); |
| 1529 | } |
| 1530 | |
| 1531 | fn writeDecl( |
| 1532 | self: *Writer, |
| 1533 | stream: anytype, |
| 1534 | inst: Inst.Index, |
| 1535 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1536 | const inst_data = self.code.instructions.items(.data)[inst].decl; |
| 1537 | try stream.writeAll("TODO)"); |
| 1538 | } |
| 1539 | |
| 1540 | fn writeStrTok( |
| 1541 | self: *Writer, |
| 1542 | stream: anytype, |
| 1543 | inst: Inst.Index, |
| 1544 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1545 | const inst_data = self.code.instructions.items(.data)[inst].str_tok; |
| 1546 | const str = inst_data.get(self.code); |
| 1547 | try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); |
| 1548 | try self.writeSrc(stream, inst_data.src()); |
| 1549 | } |
| 1550 | |
| 1551 | fn writeFnType( |
| 1552 | self: *Writer, |
| 1553 | stream: anytype, |
| 1554 | inst: Inst.Index, |
| 1555 | var_args: bool, |
| 1556 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1557 | const inst_data = self.code.instructions.items(.data)[inst].fn_type; |
| 1558 | const extra = self.code.extraData(Inst.FnType, inst_data.payload_index); |
| 1559 | const param_types = self.code.extra[extra.end..][0..extra.data.param_types_len]; |
| 1560 | const cc: Inst.Ref = 0; |
| 1561 | return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc); |
| 1562 | } |
| 1563 | |
| 1564 | fn writeFnTypeCc( |
| 1565 | self: *Writer, |
| 1566 | stream: anytype, |
| 1567 | inst: Inst.Index, |
| 1568 | var_args: bool, |
| 1569 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1570 | const inst_data = self.code.instructions.items(.data)[inst].fn_type; |
| 1571 | const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index); |
| 1572 | const param_types = self.code.extra[extra.end..][0..extra.data.param_types_len]; |
| 1573 | const cc = extra.data.cc; |
| 1574 | return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc); |
| 1575 | } |
| 1576 | |
| 1577 | fn writeFnTypeCommon( |
| 1578 | self: *Writer, |
| 1579 | stream: anytype, |
| 1580 | param_types: []const Inst.Ref, |
| 1581 | ret_ty: Inst.Ref, |
| 1582 | var_args: bool, |
| 1583 | cc: Inst.Ref, |
| 1584 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1585 | try stream.writeAll("("); |
| 1586 | for (param_types) |param_type, i| { |
| 1587 | if (i != 0) try stream.writeAll(", "); |
| 1588 | try self.writeInstRef(stream, param_type); |
| 1589 | } |
| 1590 | try stream.writeAll("), "); |
| 1591 | try self.writeInstRef(stream, ret_ty); |
| 1592 | try self.writeOptionalInstRef(stream, ", cc=", cc); |
| 1593 | try self.writeFlag(stream, ", var_args", var_args); |
| 1594 | try stream.writeAll(")"); |
| 1595 | } |
| 1596 | |
| 1597 | fn writeSmallStr( |
| 1598 | self: *Writer, |
| 1599 | stream: anytype, |
| 1600 | inst: Inst.Index, |
| 1601 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1602 | const str = self.code.instructions.items(.data)[inst].small_str.get(); |
| 1603 | try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); |
| 1604 | } |
| 1605 | |
| 1606 | fn writeInstRef(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1607 | var i: usize = inst; |
| 1608 | |
| 1609 | if (i < const_inst_list.len) { |
| 1610 | return stream.print("@{d}", .{i}); |
| 1611 | } |
| 1612 | i -= const_inst_list.len; |
| 1613 | |
| 1614 | if (i < self.param_count) { |
| 1615 | return stream.print("${d}", .{i}); |
| 1616 | } |
| 1617 | i -= self.param_count; |
| 1618 | |
| 1619 | return stream.print("%{d}", .{i}); |
| 1620 | } |
| 1621 | |
| 1622 | fn writeOptionalInstRef( |
| 1623 | self: *Writer, |
| 1624 | stream: anytype, |
| 1625 | prefix: []const u8, |
| 1626 | inst: Inst.Index, |
| 1627 | ) !void { |
| 1628 | if (inst == 0) return; |
| 1629 | try stream.writeAll(prefix); |
| 1630 | try self.writeInstRef(stream, inst); |
| 1631 | } |
| 1632 | |
| 1633 | fn writeFlag( |
| 1634 | self: *Writer, |
| 1635 | stream: anytype, |
| 1636 | name: []const u8, |
| 1637 | flag: bool, |
| 1638 | ) !void { |
| 1639 | if (!flag) return; |
| 1640 | try stream.writeAll(name); |
| 1641 | } |
| 1642 | |
| 1643 | fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { |
| 1644 | try stream.print("TODOsrc({s})", .{@tagName(src)}); |
| 1645 | } |
| 1646 | }; |