| author | |
| committer | |
| log | 5769c963e0748088ba2636e870cbc6f887d10454 |
| tree | 1fee68ec22c0e7fcdc7666f4fd2e683eb241fb09 |
| parent | 07c204393ff18b5503d9995fecabdbac154d385e |
4 files changed, 121 insertions(+), 94 deletions(-)
src/Module.zig+26| ... | ... | @@ -1667,6 +1667,9 @@ pub const SrcLoc = struct { |
| 1667 | 1667 | .node_offset_asm_ret_ty, |
| 1668 | 1668 | .node_offset_if_cond, |
| 1669 | 1669 | .node_offset_anyframe_type, |
| 1670 | .node_offset_bin_op, | |
| 1671 | .node_offset_bin_lhs, | |
| 1672 | .node_offset_bin_rhs, | |
| 1670 | 1673 | => src_loc.container.decl.container.file_scope, |
| 1671 | 1674 | }; |
| 1672 | 1675 | } |
| ... | ... | @@ -1722,6 +1725,9 @@ pub const SrcLoc = struct { |
| 1722 | 1725 | .node_offset_asm_ret_ty => @panic("TODO"), |
| 1723 | 1726 | .node_offset_if_cond => @panic("TODO"), |
| 1724 | 1727 | .node_offset_anyframe_type => @panic("TODO"), |
| 1728 | .node_offset_bin_op => @panic("TODO"), | |
| 1729 | .node_offset_bin_lhs => @panic("TODO"), | |
| 1730 | .node_offset_bin_rhs => @panic("TODO"), | |
| 1725 | 1731 | } |
| 1726 | 1732 | } |
| 1727 | 1733 | }; |
| ... | ... | @@ -1846,6 +1852,20 @@ pub const LazySrcLoc = union(enum) { |
| 1846 | 1852 | /// to the type expression. |
| 1847 | 1853 | /// The Decl is determined contextually. |
| 1848 | 1854 | node_offset_anyframe_type: i32, |
| 1855 | /// The source location points to a binary expression, such as `a + b`, found | |
| 1856 | /// by taking this AST node index offset from the containing Decl AST node. | |
| 1857 | /// The Decl is determined contextually. | |
| 1858 | node_offset_bin_op: i32, | |
| 1859 | /// The source location points to the LHS of a binary expression, found | |
| 1860 | /// by taking this AST node index offset from the containing Decl AST node, | |
| 1861 | /// which points to a binary expression AST node. Next, nagivate to the LHS. | |
| 1862 | /// The Decl is determined contextually. | |
| 1863 | node_offset_bin_lhs: i32, | |
| 1864 | /// The source location points to the RHS of a binary expression, found | |
| 1865 | /// by taking this AST node index offset from the containing Decl AST node, | |
| 1866 | /// which points to a binary expression AST node. Next, nagivate to the RHS. | |
| 1867 | /// The Decl is determined contextually. | |
| 1868 | node_offset_bin_rhs: i32, | |
| 1849 | 1869 | |
| 1850 | 1870 | /// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope. |
| 1851 | 1871 | pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc { |
| ... | ... | @@ -1877,6 +1897,9 @@ pub const LazySrcLoc = union(enum) { |
| 1877 | 1897 | .node_offset_asm_ret_ty, |
| 1878 | 1898 | .node_offset_if_cond, |
| 1879 | 1899 | .node_offset_anyframe_type, |
| 1900 | .node_offset_bin_op, | |
| 1901 | .node_offset_bin_lhs, | |
| 1902 | .node_offset_bin_rhs, | |
| 1880 | 1903 | => .{ |
| 1881 | 1904 | .container = .{ .decl = scope.srcDecl().? }, |
| 1882 | 1905 | .lazy = lazy, |
| ... | ... | @@ -1914,6 +1937,9 @@ pub const LazySrcLoc = union(enum) { |
| 1914 | 1937 | .node_offset_asm_ret_ty, |
| 1915 | 1938 | .node_offset_if_cond, |
| 1916 | 1939 | .node_offset_anyframe_type, |
| 1940 | .node_offset_bin_op, | |
| 1941 | .node_offset_bin_lhs, | |
| 1942 | .node_offset_bin_rhs, | |
| 1917 | 1943 | => .{ |
| 1918 | 1944 | .container = .{ .decl = decl }, |
| 1919 | 1945 | .lazy = lazy, |
src/Sema.zig+46-59| ... | ... | @@ -2419,17 +2419,18 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 2419 | 2419 | const tracy = trace(@src()); |
| 2420 | 2420 | defer tracy.end(); |
| 2421 | 2421 | |
| 2422 | if (true) @panic("TODO rework with zir-memory-layout in mind"); | |
| 2423 | ||
| 2424 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; | |
| 2425 | const src: LazySrcLoc = .todo; | |
| 2426 | const lhs = try sema.resolveInst(bin_inst.lhs); | |
| 2427 | const rhs = try sema.resolveInst(bin_inst.rhs); | |
| 2422 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 2423 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 2424 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 2425 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 2426 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | |
| 2427 | const lhs = try sema.resolveInst(extra.lhs); | |
| 2428 | const rhs = try sema.resolveInst(extra.rhs); | |
| 2428 | 2429 | |
| 2429 | 2430 | const instructions = &[_]*Inst{ lhs, rhs }; |
| 2430 | 2431 | const resolved_type = try sema.resolvePeerTypes(block, instructions); |
| 2431 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs.src); | |
| 2432 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs.src); | |
| 2432 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | |
| 2433 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | |
| 2433 | 2434 | |
| 2434 | 2435 | const scalar_type = if (resolved_type.zigTypeTag() == .Vector) |
| 2435 | 2436 | resolved_type.elemType() |
| ... | ... | @@ -2455,8 +2456,9 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 2455 | 2456 | |
| 2456 | 2457 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 2457 | 2458 | const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat; |
| 2459 | const zir_tags = block.sema.code.instructions.items(.tag); | |
| 2458 | 2460 | |
| 2459 | if (!is_int and !(is_float and floatOpAllowed(inst.base.tag))) { | |
| 2461 | if (!is_int and !(is_float and floatOpAllowed(zir_tags[inst]))) { | |
| 2460 | 2462 | return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) }); |
| 2461 | 2463 | } |
| 2462 | 2464 | |
| ... | ... | @@ -2468,71 +2470,56 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 2468 | 2470 | .val = Value.initTag(.undef), |
| 2469 | 2471 | }); |
| 2470 | 2472 | } |
| 2471 | return sema.analyzeInstComptimeOp(block, scalar_type, inst, lhs_val, rhs_val); | |
| 2473 | // incase rhs is 0, simply return lhs without doing any calculations | |
| 2474 | // TODO Once division is implemented we should throw an error when dividing by 0. | |
| 2475 | if (rhs_val.compareWithZero(.eq)) { | |
| 2476 | return sema.mod.constInst(sema.arena, src, .{ | |
| 2477 | .ty = scalar_type, | |
| 2478 | .val = lhs_val, | |
| 2479 | }); | |
| 2480 | } | |
| 2481 | ||
| 2482 | const value = switch (zir_tags[inst]) { | |
| 2483 | .add => blk: { | |
| 2484 | const val = if (is_int) | |
| 2485 | try Module.intAdd(sema.arena, lhs_val, rhs_val) | |
| 2486 | else | |
| 2487 | try Module.floatAdd(sema.arena, scalar_type, src, lhs_val, rhs_val); | |
| 2488 | break :blk val; | |
| 2489 | }, | |
| 2490 | .sub => blk: { | |
| 2491 | const val = if (is_int) | |
| 2492 | try Module.intSub(sema.arena, lhs_val, rhs_val) | |
| 2493 | else | |
| 2494 | try Module.floatSub(sema.arena, scalar_type, src, lhs_val, rhs_val); | |
| 2495 | break :blk val; | |
| 2496 | }, | |
| 2497 | else => return sema.mod.fail(&block.base, src, "TODO Implement arithmetic operand '{s}'", .{@tagName(zir_tags[inst])}), | |
| 2498 | }; | |
| 2499 | ||
| 2500 | log.debug("{s}({}, {}) result: {}", .{ @tagName(zir_tags[inst]), lhs_val, rhs_val, value }); | |
| 2501 | ||
| 2502 | return sema.mod.constInst(sema.arena, src, .{ | |
| 2503 | .ty = scalar_type, | |
| 2504 | .val = value, | |
| 2505 | }); | |
| 2472 | 2506 | } |
| 2473 | 2507 | } |
| 2474 | 2508 | |
| 2475 | 2509 | try sema.requireRuntimeBlock(block, src); |
| 2476 | const ir_tag: Inst.Tag = switch (inst.base.tag) { | |
| 2510 | const ir_tag: Inst.Tag = switch (zir_tags[inst]) { | |
| 2477 | 2511 | .add => .add, |
| 2478 | 2512 | .addwrap => .addwrap, |
| 2479 | 2513 | .sub => .sub, |
| 2480 | 2514 | .subwrap => .subwrap, |
| 2481 | 2515 | .mul => .mul, |
| 2482 | 2516 | .mulwrap => .mulwrap, |
| 2483 | else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}), | |
| 2517 | else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tags[inst])}), | |
| 2484 | 2518 | }; |
| 2485 | 2519 | |
| 2486 | 2520 | return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs); |
| 2487 | 2521 | } |
| 2488 | 2522 | |
| 2489 | /// Analyzes operands that are known at comptime | |
| 2490 | fn analyzeInstComptimeOp( | |
| 2491 | sema: *Sema, | |
| 2492 | block: *Scope.Block, | |
| 2493 | res_type: Type, | |
| 2494 | inst: zir.Inst.Index, | |
| 2495 | lhs_val: Value, | |
| 2496 | rhs_val: Value, | |
| 2497 | ) InnerError!*Inst { | |
| 2498 | if (true) @panic("TODO rework analyzeInstComptimeOp for zir-memory-layout"); | |
| 2499 | ||
| 2500 | // incase rhs is 0, simply return lhs without doing any calculations | |
| 2501 | // TODO Once division is implemented we should throw an error when dividing by 0. | |
| 2502 | if (rhs_val.compareWithZero(.eq)) { | |
| 2503 | return sema.mod.constInst(sema.arena, inst.base.src, .{ | |
| 2504 | .ty = res_type, | |
| 2505 | .val = lhs_val, | |
| 2506 | }); | |
| 2507 | } | |
| 2508 | const is_int = res_type.isInt() or res_type.zigTypeTag() == .ComptimeInt; | |
| 2509 | ||
| 2510 | const value = switch (inst.base.tag) { | |
| 2511 | .add => blk: { | |
| 2512 | const val = if (is_int) | |
| 2513 | try Module.intAdd(sema.arena, lhs_val, rhs_val) | |
| 2514 | else | |
| 2515 | try Module.floatAdd(sema.arena, res_type, inst.base.src, lhs_val, rhs_val); | |
| 2516 | break :blk val; | |
| 2517 | }, | |
| 2518 | .sub => blk: { | |
| 2519 | const val = if (is_int) | |
| 2520 | try Module.intSub(sema.arena, lhs_val, rhs_val) | |
| 2521 | else | |
| 2522 | try Module.floatSub(sema.arena, res_type, inst.base.src, lhs_val, rhs_val); | |
| 2523 | break :blk val; | |
| 2524 | }, | |
| 2525 | else => return sema.mod.fail(&block.base, inst.base.src, "TODO Implement arithmetic operand '{s}'", .{@tagName(inst.base.tag)}), | |
| 2526 | }; | |
| 2527 | ||
| 2528 | log.debug("{s}({}, {}) result: {}", .{ @tagName(inst.base.tag), lhs_val, rhs_val, value }); | |
| 2529 | ||
| 2530 | return sema.mod.constInst(sema.arena, inst.base.src, .{ | |
| 2531 | .ty = res_type, | |
| 2532 | .val = value, | |
| 2533 | }); | |
| 2534 | } | |
| 2535 | ||
| 2536 | 2523 | fn zirDerefNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { |
| 2537 | 2524 | const tracy = trace(@src()); |
| 2538 | 2525 | defer tracy.end(); |
src/astgen.zig+15-14| ... | ... | @@ -3000,19 +3000,18 @@ fn as( |
| 3000 | 3000 | lhs: ast.Node.Index, |
| 3001 | 3001 | rhs: ast.Node.Index, |
| 3002 | 3002 | ) InnerError!zir.Inst.Ref { |
| 3003 | if (true) @panic("TODO update for zir-memory-layout"); | |
| 3004 | 3003 | const dest_type = try typeExpr(mod, scope, lhs); |
| 3005 | 3004 | switch (rl) { |
| 3006 | 3005 | .none, .discard, .ref, .ty => { |
| 3007 | 3006 | const result = try expr(mod, scope, .{ .ty = dest_type }, rhs); |
| 3008 | return rvalue(mod, scope, rl, result); | |
| 3007 | return rvalue(mod, scope, rl, result, node); | |
| 3009 | 3008 | }, |
| 3010 | 3009 | |
| 3011 | 3010 | .ptr => |result_ptr| { |
| 3012 | return asRlPtr(mod, scope, rl, src, result_ptr, rhs, dest_type); | |
| 3011 | return asRlPtr(mod, scope, rl, result_ptr, rhs, dest_type); | |
| 3013 | 3012 | }, |
| 3014 | 3013 | .block_ptr => |block_scope| { |
| 3015 | return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, rhs, dest_type); | |
| 3014 | return asRlPtr(mod, scope, rl, block_scope.rl_ptr, rhs, dest_type); | |
| 3016 | 3015 | }, |
| 3017 | 3016 | |
| 3018 | 3017 | .bitcasted_ptr => |bitcasted_ptr| { |
| ... | ... | @@ -3030,7 +3029,6 @@ fn asRlPtr( |
| 3030 | 3029 | mod: *Module, |
| 3031 | 3030 | scope: *Scope, |
| 3032 | 3031 | rl: ResultLoc, |
| 3033 | src: usize, | |
| 3034 | 3032 | result_ptr: zir.Inst.Ref, |
| 3035 | 3033 | operand_node: ast.Node.Index, |
| 3036 | 3034 | dest_type: zir.Inst.Ref, |
| ... | ... | @@ -3038,32 +3036,35 @@ fn asRlPtr( |
| 3038 | 3036 | // Detect whether this expr() call goes into rvalue() to store the result into the |
| 3039 | 3037 | // result location. If it does, elide the coerce_result_ptr instruction |
| 3040 | 3038 | // as well as the store instruction, instead passing the result as an rvalue. |
| 3039 | const parent_gz = scope.getGenZir(); | |
| 3040 | ||
| 3041 | 3041 | var as_scope: Scope.GenZir = .{ |
| 3042 | 3042 | .parent = scope, |
| 3043 | .decl = scope.ownerDecl().?, | |
| 3044 | .arena = scope.arena(), | |
| 3043 | .zir_code = parent_gz.zir_code, | |
| 3045 | 3044 | .force_comptime = scope.isComptime(), |
| 3046 | 3045 | .instructions = .{}, |
| 3047 | 3046 | }; |
| 3048 | 3047 | defer as_scope.instructions.deinit(mod.gpa); |
| 3049 | 3048 | |
| 3050 | as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr); | |
| 3049 | as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr); | |
| 3051 | 3050 | const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); |
| 3052 | const parent_zir = &scope.getGenZir().instructions; | |
| 3051 | const parent_zir = &parent_gz.instructions; | |
| 3053 | 3052 | if (as_scope.rvalue_rl_count == 1) { |
| 3054 | 3053 | // Busted! This expression didn't actually need a pointer. |
| 3054 | const zir_tags = parent_gz.zir_code.instructions.items(.tag); | |
| 3055 | const zir_datas = parent_gz.zir_code.instructions.items(.data); | |
| 3055 | 3056 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; |
| 3056 | 3057 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 3057 | 3058 | for (as_scope.instructions.items) |src_inst| { |
| 3058 | if (src_inst == as_scope.rl_ptr.?) continue; | |
| 3059 | if (src_inst.castTag(.store_to_block_ptr)) |store| { | |
| 3060 | if (store.positionals.lhs == as_scope.rl_ptr.?) continue; | |
| 3059 | if (src_inst == as_scope.rl_ptr) continue; | |
| 3060 | if (zir_tags[src_inst] == .store_to_block_ptr) { | |
| 3061 | if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; | |
| 3061 | 3062 | } |
| 3062 | 3063 | parent_zir.appendAssumeCapacity(src_inst); |
| 3063 | 3064 | } |
| 3064 | 3065 | assert(parent_zir.items.len == expected_len); |
| 3065 | const casted_result = try addZIRBinOp(mod, scope, dest_type.src, .as, dest_type, result); | |
| 3066 | return rvalue(mod, scope, rl, casted_result); | |
| 3066 | const casted_result = try parent_gz.addBin(.as, dest_type, result); | |
| 3067 | return rvalue(mod, scope, rl, casted_result, operand_node); | |
| 3067 | 3068 | } else { |
| 3068 | 3069 | try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); |
| 3069 | 3070 | return result; |
src/zir.zig+34-21| ... | ... | @@ -524,6 +524,7 @@ pub const Inst = struct { |
| 524 | 524 | cmp_neq, |
| 525 | 525 | /// Coerces a result location pointer to a new element type. It is evaluated "backwards"- |
| 526 | 526 | /// as type coercion from the new element type to the old element type. |
| 527 | /// Uses the `bin` union field. | |
| 527 | 528 | /// LHS is destination element type, RHS is result pointer. |
| 528 | 529 | coerce_result_ptr, |
| 529 | 530 | /// Emit an error message and fail compilation. |
| ... | ... | @@ -1327,33 +1328,12 @@ const Writer = struct { |
| 1327 | 1328 | const tag = tags[inst]; |
| 1328 | 1329 | try stream.print("= {s}(", .{@tagName(tags[inst])}); |
| 1329 | 1330 | switch (tag) { |
| 1330 | .add, | |
| 1331 | .addwrap, | |
| 1332 | .array_cat, | |
| 1333 | .array_mul, | |
| 1334 | .mul, | |
| 1335 | .mulwrap, | |
| 1336 | .sub, | |
| 1337 | .subwrap, | |
| 1338 | 1331 | .array_type, |
| 1339 | 1332 | .bit_and, |
| 1340 | 1333 | .bit_or, |
| 1341 | 1334 | .as, |
| 1342 | .bool_and, | |
| 1343 | .bool_or, | |
| 1344 | 1335 | .@"break", |
| 1345 | .cmp_lt, | |
| 1346 | .cmp_lte, | |
| 1347 | .cmp_eq, | |
| 1348 | .cmp_gte, | |
| 1349 | .cmp_gt, | |
| 1350 | .cmp_neq, | |
| 1351 | 1336 | .coerce_result_ptr, |
| 1352 | .div, | |
| 1353 | .mod_rem, | |
| 1354 | .shl, | |
| 1355 | .shr, | |
| 1356 | .xor, | |
| 1357 | 1337 | .elem_ptr, |
| 1358 | 1338 | .elem_val, |
| 1359 | 1339 | .intcast, |
| ... | ... | @@ -1447,6 +1427,29 @@ const Writer = struct { |
| 1447 | 1427 | .suspend_block, |
| 1448 | 1428 | => try self.writePlNode(stream, inst), |
| 1449 | 1429 | |
| 1430 | .add, | |
| 1431 | .addwrap, | |
| 1432 | .array_cat, | |
| 1433 | .array_mul, | |
| 1434 | .mul, | |
| 1435 | .mulwrap, | |
| 1436 | .sub, | |
| 1437 | .subwrap, | |
| 1438 | .bool_and, | |
| 1439 | .bool_or, | |
| 1440 | .cmp_lt, | |
| 1441 | .cmp_lte, | |
| 1442 | .cmp_eq, | |
| 1443 | .cmp_gte, | |
| 1444 | .cmp_gt, | |
| 1445 | .cmp_neq, | |
| 1446 | .div, | |
| 1447 | .mod_rem, | |
| 1448 | .shl, | |
| 1449 | .shr, | |
| 1450 | .xor, | |
| 1451 | => try self.writePlNodeBin(stream, inst), | |
| 1452 | ||
| 1450 | 1453 | .as_node => try self.writeAs(stream, inst), |
| 1451 | 1454 | |
| 1452 | 1455 | .breakpoint, |
| ... | ... | @@ -1589,6 +1592,16 @@ const Writer = struct { |
| 1589 | 1592 | try self.writeSrc(stream, inst_data.src()); |
| 1590 | 1593 | } |
| 1591 | 1594 | |
| 1595 | fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { | |
| 1596 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | |
| 1597 | const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data; | |
| 1598 | try self.writeInstRef(stream, extra.lhs); | |
| 1599 | try stream.writeAll(", "); | |
| 1600 | try self.writeInstRef(stream, extra.rhs); | |
| 1601 | try stream.writeAll(") "); | |
| 1602 | try self.writeSrc(stream, inst_data.src()); | |
| 1603 | } | |
| 1604 | ||
| 1592 | 1605 | fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1593 | 1606 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1594 | 1607 | const extra = self.code.extraData(Inst.As, inst_data.payload_index).data; |