| author | |
| committer | |
| log | bf76501b5d46277d3706a1f0b92ba52f2a47d894 |
| tree | 7a40c904b9246092009c02f5b09a2a8732b69175 |
| parent | fdc875ed0080cd2542a854a8cd6c627b25e9b7a4 |
| parent | 0f5eda973e0c17b3f792cdb06674bf8d2863c8fb |
| signature |
stage2: rework astgen result locations7 files changed, 1280 insertions(+), 1398 deletions(-)
src/Module.zig+62-11| ... | @@ -375,6 +375,10 @@ pub const Scope = struct { | ... | @@ -375,6 +375,10 @@ pub const Scope = struct { |
| 375 | } | 375 | } |
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | pub fn isComptime(self: *Scope) bool { | ||
| 379 | return self.getGenZIR().force_comptime; | ||
| 380 | } | ||
| 381 | |||
| 378 | pub fn ownerDecl(self: *Scope) ?*Decl { | 382 | pub fn ownerDecl(self: *Scope) ?*Decl { |
| 379 | return switch (self.tag) { | 383 | return switch (self.tag) { |
| 380 | .block => self.cast(Block).?.owner_decl, | 384 | .block => self.cast(Block).?.owner_decl, |
| ... | @@ -671,14 +675,36 @@ pub const Scope = struct { | ... | @@ -671,14 +675,36 @@ pub const Scope = struct { |
| 671 | }; | 675 | }; |
| 672 | 676 | ||
| 673 | pub const Merges = struct { | 677 | pub const Merges = struct { |
| 674 | results: ArrayListUnmanaged(*Inst), | ||
| 675 | block_inst: *Inst.Block, | 678 | block_inst: *Inst.Block, |
| 679 | /// Separate array list from break_inst_list so that it can be passed directly | ||
| 680 | /// to resolvePeerTypes. | ||
| 681 | results: ArrayListUnmanaged(*Inst), | ||
| 682 | /// Keeps track of the break instructions so that the operand can be replaced | ||
| 683 | /// if we need to add type coercion at the end of block analysis. | ||
| 684 | /// Same indexes, capacity, length as `results`. | ||
| 685 | br_list: ArrayListUnmanaged(*Inst.Br), | ||
| 676 | }; | 686 | }; |
| 677 | 687 | ||
| 678 | /// For debugging purposes. | 688 | /// For debugging purposes. |
| 679 | pub fn dump(self: *Block, mod: Module) void { | 689 | pub fn dump(self: *Block, mod: Module) void { |
| 680 | zir.dumpBlock(mod, self); | 690 | zir.dumpBlock(mod, self); |
| 681 | } | 691 | } |
| 692 | |||
| 693 | pub fn makeSubBlock(parent: *Block) Block { | ||
| 694 | return .{ | ||
| 695 | .parent = parent, | ||
| 696 | .inst_table = parent.inst_table, | ||
| 697 | .func = parent.func, | ||
| 698 | .owner_decl = parent.owner_decl, | ||
| 699 | .src_decl = parent.src_decl, | ||
| 700 | .instructions = .{}, | ||
| 701 | .arena = parent.arena, | ||
| 702 | .label = null, | ||
| 703 | .inlining = parent.inlining, | ||
| 704 | .is_comptime = parent.is_comptime, | ||
| 705 | .branch_quota = parent.branch_quota, | ||
| 706 | }; | ||
| 707 | } | ||
| 682 | }; | 708 | }; |
| 683 | 709 | ||
| 684 | /// This is a temporary structure, references to it are valid only | 710 | /// This is a temporary structure, references to it are valid only |
| ... | @@ -690,13 +716,32 @@ pub const Scope = struct { | ... | @@ -690,13 +716,32 @@ pub const Scope = struct { |
| 690 | parent: *Scope, | 716 | parent: *Scope, |
| 691 | decl: *Decl, | 717 | decl: *Decl, |
| 692 | arena: *Allocator, | 718 | arena: *Allocator, |
| 719 | force_comptime: bool, | ||
| 693 | /// The first N instructions in a function body ZIR are arg instructions. | 720 | /// The first N instructions in a function body ZIR are arg instructions. |
| 694 | instructions: std.ArrayListUnmanaged(*zir.Inst) = .{}, | 721 | instructions: std.ArrayListUnmanaged(*zir.Inst) = .{}, |
| 695 | label: ?Label = null, | 722 | label: ?Label = null, |
| 696 | break_block: ?*zir.Inst.Block = null, | 723 | break_block: ?*zir.Inst.Block = null, |
| 697 | continue_block: ?*zir.Inst.Block = null, | 724 | continue_block: ?*zir.Inst.Block = null, |
| 698 | /// only valid if label != null or (continue_block and break_block) != null | 725 | /// Only valid when setBlockResultLoc is called. |
| 699 | break_result_loc: astgen.ResultLoc = undefined, | 726 | break_result_loc: astgen.ResultLoc = undefined, |
| 727 | /// When a block has a pointer result location, here it is. | ||
| 728 | rl_ptr: ?*zir.Inst = null, | ||
| 729 | /// Keeps track of how many branches of a block did not actually | ||
| 730 | /// consume the result location. astgen uses this to figure out | ||
| 731 | /// whether to rely on break instructions or writing to the result | ||
| 732 | /// pointer for the result instruction. | ||
| 733 | rvalue_rl_count: usize = 0, | ||
| 734 | /// Keeps track of how many break instructions there are. When astgen is finished | ||
| 735 | /// with a block, it can check this against rvalue_rl_count to find out whether | ||
| 736 | /// the break instructions should be downgraded to break_void. | ||
| 737 | break_count: usize = 0, | ||
| 738 | /// Tracks `break :foo bar` instructions so they can possibly be elided later if | ||
| 739 | /// the labeled block ends up not needing a result location pointer. | ||
| 740 | labeled_breaks: std.ArrayListUnmanaged(*zir.Inst.Break) = .{}, | ||
| 741 | /// Tracks `store_to_block_ptr` instructions that correspond to break instructions | ||
| 742 | /// so they can possibly be elided later if the labeled block ends up not needing | ||
| 743 | /// a result location pointer. | ||
| 744 | labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(*zir.Inst.BinOp) = .{}, | ||
| 700 | 745 | ||
| 701 | pub const Label = struct { | 746 | pub const Label = struct { |
| 702 | token: ast.TokenIndex, | 747 | token: ast.TokenIndex, |
| ... | @@ -968,6 +1013,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -968,6 +1013,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 968 | .decl = decl, | 1013 | .decl = decl, |
| 969 | .arena = &fn_type_scope_arena.allocator, | 1014 | .arena = &fn_type_scope_arena.allocator, |
| 970 | .parent = &decl.container.base, | 1015 | .parent = &decl.container.base, |
| 1016 | .force_comptime = true, | ||
| 971 | }; | 1017 | }; |
| 972 | defer fn_type_scope.instructions.deinit(self.gpa); | 1018 | defer fn_type_scope.instructions.deinit(self.gpa); |
| 973 | 1019 | ||
| ... | @@ -1131,6 +1177,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1131,6 +1177,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1131 | .decl = decl, | 1177 | .decl = decl, |
| 1132 | .arena = &decl_arena.allocator, | 1178 | .arena = &decl_arena.allocator, |
| 1133 | .parent = &decl.container.base, | 1179 | .parent = &decl.container.base, |
| 1180 | .force_comptime = false, | ||
| 1134 | }; | 1181 | }; |
| 1135 | defer gen_scope.instructions.deinit(self.gpa); | 1182 | defer gen_scope.instructions.deinit(self.gpa); |
| 1136 | 1183 | ||
| ... | @@ -1171,7 +1218,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1171,7 +1218,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1171 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) | 1218 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) |
| 1172 | { | 1219 | { |
| 1173 | const src = tree.token_locs[body_block.rbrace].start; | 1220 | const src = tree.token_locs[body_block.rbrace].start; |
| 1174 | _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid); | 1221 | _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .return_void); |
| 1175 | } | 1222 | } |
| 1176 | 1223 | ||
| 1177 | if (std.builtin.mode == .Debug and self.comp.verbose_ir) { | 1224 | if (std.builtin.mode == .Debug and self.comp.verbose_ir) { |
| ... | @@ -1329,6 +1376,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1329,6 +1376,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1329 | .decl = decl, | 1376 | .decl = decl, |
| 1330 | .arena = &gen_scope_arena.allocator, | 1377 | .arena = &gen_scope_arena.allocator, |
| 1331 | .parent = &decl.container.base, | 1378 | .parent = &decl.container.base, |
| 1379 | .force_comptime = false, | ||
| 1332 | }; | 1380 | }; |
| 1333 | defer gen_scope.instructions.deinit(self.gpa); | 1381 | defer gen_scope.instructions.deinit(self.gpa); |
| 1334 | 1382 | ||
| ... | @@ -1388,6 +1436,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1388,6 +1436,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1388 | .decl = decl, | 1436 | .decl = decl, |
| 1389 | .arena = &type_scope_arena.allocator, | 1437 | .arena = &type_scope_arena.allocator, |
| 1390 | .parent = &decl.container.base, | 1438 | .parent = &decl.container.base, |
| 1439 | .force_comptime = true, | ||
| 1391 | }; | 1440 | }; |
| 1392 | defer type_scope.instructions.deinit(self.gpa); | 1441 | defer type_scope.instructions.deinit(self.gpa); |
| 1393 | 1442 | ||
| ... | @@ -1457,13 +1506,15 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1457,13 +1506,15 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1457 | 1506 | ||
| 1458 | decl.analysis = .in_progress; | 1507 | decl.analysis = .in_progress; |
| 1459 | 1508 | ||
| 1460 | // A comptime decl does not store any value so we can just deinit this arena after analysis is done. | 1509 | // A comptime decl does not store any value so we can just deinit |
| 1510 | // this arena after analysis is done. | ||
| 1461 | var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); | 1511 | var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); |
| 1462 | defer analysis_arena.deinit(); | 1512 | defer analysis_arena.deinit(); |
| 1463 | var gen_scope: Scope.GenZIR = .{ | 1513 | var gen_scope: Scope.GenZIR = .{ |
| 1464 | .decl = decl, | 1514 | .decl = decl, |
| 1465 | .arena = &analysis_arena.allocator, | 1515 | .arena = &analysis_arena.allocator, |
| 1466 | .parent = &decl.container.base, | 1516 | .parent = &decl.container.base, |
| 1517 | .force_comptime = true, | ||
| 1467 | }; | 1518 | }; |
| 1468 | defer gen_scope.instructions.deinit(self.gpa); | 1519 | defer gen_scope.instructions.deinit(self.gpa); |
| 1469 | 1520 | ||
| ... | @@ -2100,7 +2151,7 @@ pub fn addBr( | ... | @@ -2100,7 +2151,7 @@ pub fn addBr( |
| 2100 | src: usize, | 2151 | src: usize, |
| 2101 | target_block: *Inst.Block, | 2152 | target_block: *Inst.Block, |
| 2102 | operand: *Inst, | 2153 | operand: *Inst, |
| 2103 | ) !*Inst { | 2154 | ) !*Inst.Br { |
| 2104 | const inst = try scope_block.arena.create(Inst.Br); | 2155 | const inst = try scope_block.arena.create(Inst.Br); |
| 2105 | inst.* = .{ | 2156 | inst.* = .{ |
| 2106 | .base = .{ | 2157 | .base = .{ |
| ... | @@ -2112,7 +2163,7 @@ pub fn addBr( | ... | @@ -2112,7 +2163,7 @@ pub fn addBr( |
| 2112 | .block = target_block, | 2163 | .block = target_block, |
| 2113 | }; | 2164 | }; |
| 2114 | try scope_block.instructions.append(self.gpa, &inst.base); | 2165 | try scope_block.instructions.append(self.gpa, &inst.base); |
| 2115 | return &inst.base; | 2166 | return inst; |
| 2116 | } | 2167 | } |
| 2117 | 2168 | ||
| 2118 | pub fn addCondBr( | 2169 | pub fn addCondBr( |
| ... | @@ -3466,18 +3517,18 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic | ... | @@ -3466,18 +3517,18 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic |
| 3466 | }; | 3517 | }; |
| 3467 | 3518 | ||
| 3468 | const ok_body: ir.Body = .{ | 3519 | const ok_body: ir.Body = .{ |
| 3469 | .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the brvoid. | 3520 | .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the br_void. |
| 3470 | }; | 3521 | }; |
| 3471 | const brvoid = try parent_block.arena.create(Inst.BrVoid); | 3522 | const br_void = try parent_block.arena.create(Inst.BrVoid); |
| 3472 | brvoid.* = .{ | 3523 | br_void.* = .{ |
| 3473 | .base = .{ | 3524 | .base = .{ |
| 3474 | .tag = .brvoid, | 3525 | .tag = .br_void, |
| 3475 | .ty = Type.initTag(.noreturn), | 3526 | .ty = Type.initTag(.noreturn), |
| 3476 | .src = ok.src, | 3527 | .src = ok.src, |
| 3477 | }, | 3528 | }, |
| 3478 | .block = block_inst, | 3529 | .block = block_inst, |
| 3479 | }; | 3530 | }; |
| 3480 | ok_body.instructions[0] = &brvoid.base; | 3531 | ok_body.instructions[0] = &br_void.base; |
| 3481 | 3532 | ||
| 3482 | var fail_block: Scope.Block = .{ | 3533 | var fail_block: Scope.Block = .{ |
| 3483 | .parent = parent_block, | 3534 | .parent = parent_block, |
src/astgen.zig+674-611| ... | @@ -14,25 +14,45 @@ const InnerError = Module.InnerError; | ... | @@ -14,25 +14,45 @@ const InnerError = Module.InnerError; |
| 14 | 14 | ||
| 15 | pub const ResultLoc = union(enum) { | 15 | pub const ResultLoc = union(enum) { |
| 16 | /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the | 16 | /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the |
| 17 | /// expression should be generated. | 17 | /// expression should be generated. The result instruction from the expression must |
| 18 | /// be ignored. | ||
| 18 | discard, | 19 | discard, |
| 19 | /// The expression has an inferred type, and it will be evaluated as an rvalue. | 20 | /// The expression has an inferred type, and it will be evaluated as an rvalue. |
| 20 | none, | 21 | none, |
| 21 | /// The expression must generate a pointer rather than a value. For example, the left hand side | 22 | /// The expression must generate a pointer rather than a value. For example, the left hand side |
| 22 | /// of an assignment uses this kind of result location. | 23 | /// of an assignment uses this kind of result location. |
| 23 | ref, | 24 | ref, |
| 24 | /// The expression will be type coerced into this type, but it will be evaluated as an rvalue. | 25 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 25 | ty: *zir.Inst, | 26 | ty: *zir.Inst, |
| 26 | /// The expression must store its result into this typed pointer. | 27 | /// The expression must store its result into this typed pointer. The result instruction |
| 28 | /// from the expression must be ignored. | ||
| 27 | ptr: *zir.Inst, | 29 | ptr: *zir.Inst, |
| 28 | /// The expression must store its result into this allocation, which has an inferred type. | 30 | /// The expression must store its result into this allocation, which has an inferred type. |
| 31 | /// The result instruction from the expression must be ignored. | ||
| 29 | inferred_ptr: *zir.Inst.Tag.alloc_inferred.Type(), | 32 | inferred_ptr: *zir.Inst.Tag.alloc_inferred.Type(), |
| 30 | /// The expression must store its result into this pointer, which is a typed pointer that | 33 | /// The expression must store its result into this pointer, which is a typed pointer that |
| 31 | /// has been bitcasted to whatever the expression's type is. | 34 | /// has been bitcasted to whatever the expression's type is. |
| 35 | /// The result instruction from the expression must be ignored. | ||
| 32 | bitcasted_ptr: *zir.Inst.UnOp, | 36 | bitcasted_ptr: *zir.Inst.UnOp, |
| 33 | /// There is a pointer for the expression to store its result into, however, its type | 37 | /// There is a pointer for the expression to store its result into, however, its type |
| 34 | /// is inferred based on peer type resolution for a `zir.Inst.Block`. | 38 | /// is inferred based on peer type resolution for a `zir.Inst.Block`. |
| 35 | block_ptr: *zir.Inst.Block, | 39 | /// The result instruction from the expression must be ignored. |
| 40 | block_ptr: *Module.Scope.GenZIR, | ||
| 41 | |||
| 42 | pub const Strategy = struct { | ||
| 43 | elide_store_to_block_ptr_instructions: bool, | ||
| 44 | tag: Tag, | ||
| 45 | |||
| 46 | pub const Tag = enum { | ||
| 47 | /// Both branches will use break_void; result location is used to communicate the | ||
| 48 | /// result instruction. | ||
| 49 | break_void, | ||
| 50 | /// Use break statements to pass the block result value, and call rvalue() at | ||
| 51 | /// the end depending on rl. Also elide the store_to_block_ptr instructions | ||
| 52 | /// depending on rl. | ||
| 53 | break_operand, | ||
| 54 | }; | ||
| 55 | }; | ||
| 36 | }; | 56 | }; |
| 37 | 57 | ||
| 38 | pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*zir.Inst { | 58 | pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*zir.Inst { |
| ... | @@ -179,6 +199,9 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { | ... | @@ -179,6 +199,9 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { |
| 179 | } | 199 | } |
| 180 | 200 | ||
| 181 | /// Turn Zig AST into untyped ZIR istructions. | 201 | /// Turn Zig AST into untyped ZIR istructions. |
| 202 | /// When `rl` is discard, ptr, inferred_ptr, bitcasted_ptr, or inferred_ptr, the | ||
| 203 | /// result instruction can be used to inspect whether it is isNoReturn() but that is it, | ||
| 204 | /// it must otherwise not be used. | ||
| 182 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | 205 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { |
| 183 | switch (node.tag) { | 206 | switch (node.tag) { |
| 184 | .Root => unreachable, // Top-level declaration. | 207 | .Root => unreachable, // Top-level declaration. |
| ... | @@ -197,20 +220,20 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -197,20 +220,20 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 197 | .FieldInitializer => unreachable, // Handled explicitly. | 220 | .FieldInitializer => unreachable, // Handled explicitly. |
| 198 | .ContainerField => unreachable, // Handled explicitly. | 221 | .ContainerField => unreachable, // Handled explicitly. |
| 199 | 222 | ||
| 200 | .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), | 223 | .Assign => return rvalueVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), |
| 201 | .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)), | 224 | .AssignBitAnd => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bit_and)), |
| 202 | .AssignBitOr => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitOr).?, .bitor)), | 225 | .AssignBitOr => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitOr).?, .bit_or)), |
| 203 | .AssignBitShiftLeft => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftLeft).?, .shl)), | 226 | .AssignBitShiftLeft => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftLeft).?, .shl)), |
| 204 | .AssignBitShiftRight => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftRight).?, .shr)), | 227 | .AssignBitShiftRight => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftRight).?, .shr)), |
| 205 | .AssignBitXor => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitXor).?, .xor)), | 228 | .AssignBitXor => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitXor).?, .xor)), |
| 206 | .AssignDiv => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignDiv).?, .div)), | 229 | .AssignDiv => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignDiv).?, .div)), |
| 207 | .AssignSub => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSub).?, .sub)), | 230 | .AssignSub => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSub).?, .sub)), |
| 208 | .AssignSubWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSubWrap).?, .subwrap)), | 231 | .AssignSubWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSubWrap).?, .subwrap)), |
| 209 | .AssignMod => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMod).?, .mod_rem)), | 232 | .AssignMod => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMod).?, .mod_rem)), |
| 210 | .AssignAdd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAdd).?, .add)), | 233 | .AssignAdd => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAdd).?, .add)), |
| 211 | .AssignAddWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAddWrap).?, .addwrap)), | 234 | .AssignAddWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAddWrap).?, .addwrap)), |
| 212 | .AssignMul => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMul).?, .mul)), | 235 | .AssignMul => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMul).?, .mul)), |
| 213 | .AssignMulWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMulWrap).?, .mulwrap)), | 236 | .AssignMulWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMulWrap).?, .mulwrap)), |
| 214 | 237 | ||
| 215 | .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), | 238 | .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), |
| 216 | .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap), | 239 | .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap), |
| ... | @@ -220,8 +243,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -220,8 +243,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 220 | .MulWrap => return simpleBinOp(mod, scope, rl, node.castTag(.MulWrap).?, .mulwrap), | 243 | .MulWrap => return simpleBinOp(mod, scope, rl, node.castTag(.MulWrap).?, .mulwrap), |
| 221 | .Div => return simpleBinOp(mod, scope, rl, node.castTag(.Div).?, .div), | 244 | .Div => return simpleBinOp(mod, scope, rl, node.castTag(.Div).?, .div), |
| 222 | .Mod => return simpleBinOp(mod, scope, rl, node.castTag(.Mod).?, .mod_rem), | 245 | .Mod => return simpleBinOp(mod, scope, rl, node.castTag(.Mod).?, .mod_rem), |
| 223 | .BitAnd => return simpleBinOp(mod, scope, rl, node.castTag(.BitAnd).?, .bitand), | 246 | .BitAnd => return simpleBinOp(mod, scope, rl, node.castTag(.BitAnd).?, .bit_and), |
| 224 | .BitOr => return simpleBinOp(mod, scope, rl, node.castTag(.BitOr).?, .bitor), | 247 | .BitOr => return simpleBinOp(mod, scope, rl, node.castTag(.BitOr).?, .bit_or), |
| 225 | .BitShiftLeft => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftLeft).?, .shl), | 248 | .BitShiftLeft => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftLeft).?, .shl), |
| 226 | .BitShiftRight => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftRight).?, .shr), | 249 | .BitShiftRight => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftRight).?, .shr), |
| 227 | .BitXor => return simpleBinOp(mod, scope, rl, node.castTag(.BitXor).?, .xor), | 250 | .BitXor => return simpleBinOp(mod, scope, rl, node.castTag(.BitXor).?, .xor), |
| ... | @@ -239,15 +262,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -239,15 +262,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 239 | .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?), | 262 | .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?), |
| 240 | .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?), | 263 | .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?), |
| 241 | 264 | ||
| 242 | .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)), | 265 | .BoolNot => return rvalue(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)), |
| 243 | .BitNot => return rlWrap(mod, scope, rl, try bitNot(mod, scope, node.castTag(.BitNot).?)), | 266 | .BitNot => return rvalue(mod, scope, rl, try bitNot(mod, scope, node.castTag(.BitNot).?)), |
| 244 | .Negation => return rlWrap(mod, scope, rl, try negation(mod, scope, node.castTag(.Negation).?, .sub)), | 267 | .Negation => return rvalue(mod, scope, rl, try negation(mod, scope, node.castTag(.Negation).?, .sub)), |
| 245 | .NegationWrap => return rlWrap(mod, scope, rl, try negation(mod, scope, node.castTag(.NegationWrap).?, .subwrap)), | 268 | .NegationWrap => return rvalue(mod, scope, rl, try negation(mod, scope, node.castTag(.NegationWrap).?, .subwrap)), |
| 246 | 269 | ||
| 247 | .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?), | 270 | .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?), |
| 248 | .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)), | 271 | .Asm => return rvalue(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)), |
| 249 | .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)), | 272 | .StringLiteral => return rvalue(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)), |
| 250 | .IntegerLiteral => return rlWrap(mod, scope, rl, try integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?)), | 273 | .IntegerLiteral => return rvalue(mod, scope, rl, try integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?)), |
| 251 | .BuiltinCall => return builtinCall(mod, scope, rl, node.castTag(.BuiltinCall).?), | 274 | .BuiltinCall => return builtinCall(mod, scope, rl, node.castTag(.BuiltinCall).?), |
| 252 | .Call => return callExpr(mod, scope, rl, node.castTag(.Call).?), | 275 | .Call => return callExpr(mod, scope, rl, node.castTag(.Call).?), |
| 253 | .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), | 276 | .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), |
| ... | @@ -255,38 +278,38 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -255,38 +278,38 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 255 | .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), | 278 | .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), |
| 256 | .While => return whileExpr(mod, scope, rl, node.castTag(.While).?), | 279 | .While => return whileExpr(mod, scope, rl, node.castTag(.While).?), |
| 257 | .Period => return field(mod, scope, rl, node.castTag(.Period).?), | 280 | .Period => return field(mod, scope, rl, node.castTag(.Period).?), |
| 258 | .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), | 281 | .Deref => return rvalue(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), |
| 259 | .AddressOf => return rlWrap(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)), | 282 | .AddressOf => return rvalue(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)), |
| 260 | .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)), | 283 | .FloatLiteral => return rvalue(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)), |
| 261 | .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)), | 284 | .UndefinedLiteral => return rvalue(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)), |
| 262 | .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)), | 285 | .BoolLiteral => return rvalue(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)), |
| 263 | .NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)), | 286 | .NullLiteral => return rvalue(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)), |
| 264 | .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), | 287 | .OptionalType => return rvalue(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), |
| 265 | .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), | 288 | .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), |
| 266 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), | 289 | .Block => return rvalueVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), |
| 267 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), | 290 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), |
| 268 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), | 291 | .Break => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), |
| 269 | .Continue => return rlWrap(mod, scope, rl, try continueExpr(mod, scope, node.castTag(.Continue).?)), | 292 | .Continue => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node.castTag(.Continue).?)), |
| 270 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), | 293 | .PtrType => return rvalue(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), |
| 271 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), | 294 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), |
| 272 | .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), | 295 | .ArrayType => return rvalue(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), |
| 273 | .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), | 296 | .ArrayTypeSentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), |
| 274 | .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), | 297 | .EnumLiteral => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), |
| 275 | .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), | 298 | .MultilineStringLiteral => return rvalue(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), |
| 276 | .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), | 299 | .CharLiteral => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), |
| 277 | .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), | 300 | .SliceType => return rvalue(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), |
| 278 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), | 301 | .ErrorUnion => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), |
| 279 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), | 302 | .MergeErrorSets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), |
| 280 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), | 303 | .AnyFrameType => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), |
| 281 | .ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)), | 304 | .ErrorSetDecl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)), |
| 282 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), | 305 | .ErrorType => return rvalue(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 283 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), | 306 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 284 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), | 307 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| 285 | .Slice => return rlWrap(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)), | 308 | .Slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)), |
| 286 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), | 309 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), |
| 287 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), | 310 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), |
| 288 | .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), | 311 | .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), |
| 289 | .Switch => return switchExpr(mod, scope, rl, node.castTag(.Switch).?), | 312 | .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}), |
| 290 | .ContainerDecl => return containerDecl(mod, scope, rl, node.castTag(.ContainerDecl).?), | 313 | .ContainerDecl => return containerDecl(mod, scope, rl, node.castTag(.ContainerDecl).?), |
| 291 | 314 | ||
| 292 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), | 315 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| ... | @@ -311,11 +334,19 @@ fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.C | ... | @@ -311,11 +334,19 @@ fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.C |
| 311 | return comptimeExpr(mod, scope, rl, node.expr); | 334 | return comptimeExpr(mod, scope, rl, node.expr); |
| 312 | } | 335 | } |
| 313 | 336 | ||
| 314 | pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | 337 | pub fn comptimeExpr( |
| 315 | const tree = parent_scope.tree(); | 338 | mod: *Module, |
| 316 | const src = tree.token_locs[node.firstToken()].start; | 339 | parent_scope: *Scope, |
| 340 | rl: ResultLoc, | ||
| 341 | node: *ast.Node, | ||
| 342 | ) InnerError!*zir.Inst { | ||
| 343 | // If we are already in a comptime scope, no need to make another one. | ||
| 344 | if (parent_scope.isComptime()) { | ||
| 345 | return expr(mod, parent_scope, rl, node); | ||
| 346 | } | ||
| 317 | 347 | ||
| 318 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, we can reuse the existing one. | 348 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, |
| 349 | // we can reuse the existing one. | ||
| 319 | if (node.castTag(.LabeledBlock)) |block_node| { | 350 | if (node.castTag(.LabeledBlock)) |block_node| { |
| 320 | return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); | 351 | return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); |
| 321 | } | 352 | } |
| ... | @@ -325,6 +356,7 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as | ... | @@ -325,6 +356,7 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as |
| 325 | .parent = parent_scope, | 356 | .parent = parent_scope, |
| 326 | .decl = parent_scope.ownerDecl().?, | 357 | .decl = parent_scope.ownerDecl().?, |
| 327 | .arena = parent_scope.arena(), | 358 | .arena = parent_scope.arena(), |
| 359 | .force_comptime = true, | ||
| 328 | .instructions = .{}, | 360 | .instructions = .{}, |
| 329 | }; | 361 | }; |
| 330 | defer block_scope.instructions.deinit(mod.gpa); | 362 | defer block_scope.instructions.deinit(mod.gpa); |
| ... | @@ -333,6 +365,9 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as | ... | @@ -333,6 +365,9 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as |
| 333 | // instruction is the block's result value. | 365 | // instruction is the block's result value. |
| 334 | _ = try expr(mod, &block_scope.base, rl, node); | 366 | _ = try expr(mod, &block_scope.base, rl, node); |
| 335 | 367 | ||
| 368 | const tree = parent_scope.tree(); | ||
| 369 | const src = tree.token_locs[node.firstToken()].start; | ||
| 370 | |||
| 336 | const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ | 371 | const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ |
| 337 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | 372 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 338 | }); | 373 | }); |
| ... | @@ -340,7 +375,11 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as | ... | @@ -340,7 +375,11 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as |
| 340 | return &block.base; | 375 | return &block.base; |
| 341 | } | 376 | } |
| 342 | 377 | ||
| 343 | fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { | 378 | fn breakExpr( |
| 379 | mod: *Module, | ||
| 380 | parent_scope: *Scope, | ||
| 381 | node: *ast.Node.ControlFlowExpression, | ||
| 382 | ) InnerError!*zir.Inst { | ||
| 344 | const tree = parent_scope.tree(); | 383 | const tree = parent_scope.tree(); |
| 345 | const src = tree.token_locs[node.ltoken].start; | 384 | const src = tree.token_locs[node.ltoken].start; |
| 346 | 385 | ||
| ... | @@ -366,25 +405,31 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr | ... | @@ -366,25 +405,31 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr |
| 366 | continue; | 405 | continue; |
| 367 | }; | 406 | }; |
| 368 | 407 | ||
| 369 | if (node.getRHS()) |rhs| { | 408 | const rhs = node.getRHS() orelse { |
| 370 | // Most result location types can be forwarded directly; however | 409 | return addZirInstTag(mod, parent_scope, src, .break_void, .{ |
| 371 | // if we need to write to a pointer which has an inferred type, | ||
| 372 | // proper type inference requires peer type resolution on the block's | ||
| 373 | // break operand expressions. | ||
| 374 | const branch_rl: ResultLoc = switch (gen_zir.break_result_loc) { | ||
| 375 | .discard, .none, .ty, .ptr, .ref => gen_zir.break_result_loc, | ||
| 376 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block_inst }, | ||
| 377 | }; | ||
| 378 | const operand = try expr(mod, parent_scope, branch_rl, rhs); | ||
| 379 | return try addZIRInst(mod, parent_scope, src, zir.Inst.Break, .{ | ||
| 380 | .block = block_inst, | 410 | .block = block_inst, |
| 381 | .operand = operand, | 411 | }); |
| 382 | }, .{}); | 412 | }; |
| 383 | } else { | 413 | gen_zir.break_count += 1; |
| 384 | return try addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{ | 414 | const prev_rvalue_rl_count = gen_zir.rvalue_rl_count; |
| 385 | .block = block_inst, | 415 | const operand = try expr(mod, parent_scope, gen_zir.break_result_loc, rhs); |
| 386 | }, .{}); | 416 | const have_store_to_block = gen_zir.rvalue_rl_count != prev_rvalue_rl_count; |
| 417 | const br = try addZirInstTag(mod, parent_scope, src, .@"break", .{ | ||
| 418 | .block = block_inst, | ||
| 419 | .operand = operand, | ||
| 420 | }); | ||
| 421 | if (gen_zir.break_result_loc == .block_ptr) { | ||
| 422 | try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?); | ||
| 423 | |||
| 424 | if (have_store_to_block) { | ||
| 425 | const inst_list = parent_scope.getGenZIR().instructions.items; | ||
| 426 | const last_inst = inst_list[inst_list.len - 2]; | ||
| 427 | const store_inst = last_inst.castTag(.store_to_block_ptr).?; | ||
| 428 | assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?); | ||
| 429 | try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst); | ||
| 430 | } | ||
| 387 | } | 431 | } |
| 432 | return br; | ||
| 388 | }, | 433 | }, |
| 389 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | 434 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 390 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | 435 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| ... | @@ -424,9 +469,9 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE | ... | @@ -424,9 +469,9 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE |
| 424 | continue; | 469 | continue; |
| 425 | } | 470 | } |
| 426 | 471 | ||
| 427 | return addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{ | 472 | return addZirInstTag(mod, parent_scope, src, .break_void, .{ |
| 428 | .block = continue_block, | 473 | .block = continue_block, |
| 429 | }, .{}); | 474 | }); |
| 430 | }, | 475 | }, |
| 431 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | 476 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 432 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | 477 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| ... | @@ -526,28 +571,65 @@ fn labeledBlockExpr( | ... | @@ -526,28 +571,65 @@ fn labeledBlockExpr( |
| 526 | .parent = parent_scope, | 571 | .parent = parent_scope, |
| 527 | .decl = parent_scope.ownerDecl().?, | 572 | .decl = parent_scope.ownerDecl().?, |
| 528 | .arena = gen_zir.arena, | 573 | .arena = gen_zir.arena, |
| 574 | .force_comptime = parent_scope.isComptime(), | ||
| 529 | .instructions = .{}, | 575 | .instructions = .{}, |
| 530 | .break_result_loc = rl, | ||
| 531 | // TODO @as here is working around a stage1 miscompilation bug :( | 576 | // TODO @as here is working around a stage1 miscompilation bug :( |
| 532 | .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ | 577 | .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ |
| 533 | .token = block_node.label, | 578 | .token = block_node.label, |
| 534 | .block_inst = block_inst, | 579 | .block_inst = block_inst, |
| 535 | }), | 580 | }), |
| 536 | }; | 581 | }; |
| 582 | setBlockResultLoc(&block_scope, rl); | ||
| 537 | defer block_scope.instructions.deinit(mod.gpa); | 583 | defer block_scope.instructions.deinit(mod.gpa); |
| 584 | defer block_scope.labeled_breaks.deinit(mod.gpa); | ||
| 585 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); | ||
| 538 | 586 | ||
| 539 | try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); | 587 | try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); |
| 588 | |||
| 540 | if (!block_scope.label.?.used) { | 589 | if (!block_scope.label.?.used) { |
| 541 | return mod.fail(parent_scope, tree.token_locs[block_node.label].start, "unused block label", .{}); | 590 | return mod.fail(parent_scope, tree.token_locs[block_node.label].start, "unused block label", .{}); |
| 542 | } | 591 | } |
| 543 | 592 | ||
| 544 | block_inst.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); | ||
| 545 | try gen_zir.instructions.append(mod.gpa, &block_inst.base); | 593 | try gen_zir.instructions.append(mod.gpa, &block_inst.base); |
| 546 | 594 | ||
| 547 | return &block_inst.base; | 595 | const strat = rlStrategy(rl, &block_scope); |
| 596 | switch (strat.tag) { | ||
| 597 | .break_void => { | ||
| 598 | // The code took advantage of the result location as a pointer. | ||
| 599 | // Turn the break instructions into break_void instructions. | ||
| 600 | for (block_scope.labeled_breaks.items) |br| { | ||
| 601 | br.base.tag = .break_void; | ||
| 602 | } | ||
| 603 | // TODO technically not needed since we changed the tag to break_void but | ||
| 604 | // would be better still to elide the ones that are in this list. | ||
| 605 | try copyBodyNoEliding(&block_inst.positionals.body, block_scope); | ||
| 606 | |||
| 607 | return &block_inst.base; | ||
| 608 | }, | ||
| 609 | .break_operand => { | ||
| 610 | // All break operands are values that did not use the result location pointer. | ||
| 611 | if (strat.elide_store_to_block_ptr_instructions) { | ||
| 612 | for (block_scope.labeled_store_to_block_ptr_list.items) |inst| { | ||
| 613 | inst.base.tag = .void_value; | ||
| 614 | } | ||
| 615 | // TODO technically not needed since we changed the tag to void_value but | ||
| 616 | // would be better still to elide the ones that are in this list. | ||
| 617 | } | ||
| 618 | try copyBodyNoEliding(&block_inst.positionals.body, block_scope); | ||
| 619 | switch (rl) { | ||
| 620 | .ref => return &block_inst.base, | ||
| 621 | else => return rvalue(mod, parent_scope, rl, &block_inst.base), | ||
| 622 | } | ||
| 623 | }, | ||
| 624 | } | ||
| 548 | } | 625 | } |
| 549 | 626 | ||
| 550 | fn blockExprStmts(mod: *Module, parent_scope: *Scope, node: *ast.Node, statements: []*ast.Node) !void { | 627 | fn blockExprStmts( |
| 628 | mod: *Module, | ||
| 629 | parent_scope: *Scope, | ||
| 630 | node: *ast.Node, | ||
| 631 | statements: []*ast.Node, | ||
| 632 | ) !void { | ||
| 551 | const tree = parent_scope.tree(); | 633 | const tree = parent_scope.tree(); |
| 552 | 634 | ||
| 553 | var block_arena = std.heap.ArenaAllocator.init(mod.gpa); | 635 | var block_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| ... | @@ -563,8 +645,8 @@ fn blockExprStmts(mod: *Module, parent_scope: *Scope, node: *ast.Node, statement | ... | @@ -563,8 +645,8 @@ fn blockExprStmts(mod: *Module, parent_scope: *Scope, node: *ast.Node, statement |
| 563 | scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); | 645 | scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); |
| 564 | }, | 646 | }, |
| 565 | .Assign => try assign(mod, scope, statement.castTag(.Assign).?), | 647 | .Assign => try assign(mod, scope, statement.castTag(.Assign).?), |
| 566 | .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bitand), | 648 | .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bit_and), |
| 567 | .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bitor), | 649 | .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bit_or), |
| 568 | .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl), | 650 | .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl), |
| 569 | .AssignBitShiftRight => try assignOp(mod, scope, statement.castTag(.AssignBitShiftRight).?, .shr), | 651 | .AssignBitShiftRight => try assignOp(mod, scope, statement.castTag(.AssignBitShiftRight).?, .shr), |
| 570 | .AssignBitXor => try assignOp(mod, scope, statement.castTag(.AssignBitXor).?, .xor), | 652 | .AssignBitXor => try assignOp(mod, scope, statement.castTag(.AssignBitXor).?, .xor), |
| ... | @@ -644,6 +726,7 @@ fn varDecl( | ... | @@ -644,6 +726,7 @@ fn varDecl( |
| 644 | 726 | ||
| 645 | // Namespace vars shadowing detection | 727 | // Namespace vars shadowing detection |
| 646 | if (mod.lookupDeclName(scope, ident_name)) |_| { | 728 | if (mod.lookupDeclName(scope, ident_name)) |_| { |
| 729 | // TODO add note for other definition | ||
| 647 | return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); | 730 | return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); |
| 648 | } | 731 | } |
| 649 | const init_node = node.getInitNode() orelse | 732 | const init_node = node.getInitNode() orelse |
| ... | @@ -651,36 +734,103 @@ fn varDecl( | ... | @@ -651,36 +734,103 @@ fn varDecl( |
| 651 | 734 | ||
| 652 | switch (tree.token_ids[node.mut_token]) { | 735 | switch (tree.token_ids[node.mut_token]) { |
| 653 | .Keyword_const => { | 736 | .Keyword_const => { |
| 654 | var resolve_inferred_alloc: ?*zir.Inst = null; | ||
| 655 | // Depending on the type of AST the initialization expression is, we may need an lvalue | 737 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 656 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as | 738 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 657 | // the variable, no memory location needed. | 739 | // the variable, no memory location needed. |
| 658 | const result_loc = if (nodeMayNeedMemoryLocation(init_node, scope)) r: { | 740 | if (!nodeMayNeedMemoryLocation(init_node, scope)) { |
| 659 | if (node.getTypeNode()) |type_node| { | 741 | const result_loc: ResultLoc = if (node.getTypeNode()) |type_node| |
| 660 | const type_inst = try typeExpr(mod, scope, type_node); | 742 | .{ .ty = try typeExpr(mod, scope, type_node) } |
| 661 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); | ||
| 662 | break :r ResultLoc{ .ptr = alloc }; | ||
| 663 | } else { | ||
| 664 | const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred); | ||
| 665 | resolve_inferred_alloc = &alloc.base; | ||
| 666 | break :r ResultLoc{ .inferred_ptr = alloc }; | ||
| 667 | } | ||
| 668 | } else r: { | ||
| 669 | if (node.getTypeNode()) |type_node| | ||
| 670 | break :r ResultLoc{ .ty = try typeExpr(mod, scope, type_node) } | ||
| 671 | else | 743 | else |
| 672 | break :r .none; | 744 | .none; |
| 745 | const init_inst = try expr(mod, scope, result_loc, init_node); | ||
| 746 | const sub_scope = try block_arena.create(Scope.LocalVal); | ||
| 747 | sub_scope.* = .{ | ||
| 748 | .parent = scope, | ||
| 749 | .gen_zir = scope.getGenZIR(), | ||
| 750 | .name = ident_name, | ||
| 751 | .inst = init_inst, | ||
| 752 | }; | ||
| 753 | return &sub_scope.base; | ||
| 754 | } | ||
| 755 | |||
| 756 | // Detect whether the initialization expression actually uses the | ||
| 757 | // result location pointer. | ||
| 758 | var init_scope: Scope.GenZIR = .{ | ||
| 759 | .parent = scope, | ||
| 760 | .decl = scope.ownerDecl().?, | ||
| 761 | .arena = scope.arena(), | ||
| 762 | .force_comptime = scope.isComptime(), | ||
| 763 | .instructions = .{}, | ||
| 673 | }; | 764 | }; |
| 674 | const init_inst = try expr(mod, scope, result_loc, init_node); | 765 | defer init_scope.instructions.deinit(mod.gpa); |
| 766 | |||
| 767 | var resolve_inferred_alloc: ?*zir.Inst = null; | ||
| 768 | var opt_type_inst: ?*zir.Inst = null; | ||
| 769 | if (node.getTypeNode()) |type_node| { | ||
| 770 | const type_inst = try typeExpr(mod, &init_scope.base, type_node); | ||
| 771 | opt_type_inst = type_inst; | ||
| 772 | init_scope.rl_ptr = try addZIRUnOp(mod, &init_scope.base, name_src, .alloc, type_inst); | ||
| 773 | } else { | ||
| 774 | const alloc = try addZIRNoOpT(mod, &init_scope.base, name_src, .alloc_inferred); | ||
| 775 | resolve_inferred_alloc = &alloc.base; | ||
| 776 | init_scope.rl_ptr = &alloc.base; | ||
| 777 | } | ||
| 778 | const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; | ||
| 779 | const init_inst = try expr(mod, &init_scope.base, init_result_loc, init_node); | ||
| 780 | const parent_zir = &scope.getGenZIR().instructions; | ||
| 781 | if (init_scope.rvalue_rl_count == 1) { | ||
| 782 | // Result location pointer not used. We don't need an alloc for this | ||
| 783 | // const local, and type inference becomes trivial. | ||
| 784 | // Move the init_scope instructions into the parent scope, eliding | ||
| 785 | // the alloc instruction and the store_to_block_ptr instruction. | ||
| 786 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2; | ||
| 787 | try parent_zir.ensureCapacity(mod.gpa, expected_len); | ||
| 788 | for (init_scope.instructions.items) |src_inst| { | ||
| 789 | if (src_inst == init_scope.rl_ptr.?) continue; | ||
| 790 | if (src_inst.castTag(.store_to_block_ptr)) |store| { | ||
| 791 | if (store.positionals.lhs == init_scope.rl_ptr.?) continue; | ||
| 792 | } | ||
| 793 | parent_zir.appendAssumeCapacity(src_inst); | ||
| 794 | } | ||
| 795 | assert(parent_zir.items.len == expected_len); | ||
| 796 | const casted_init = if (opt_type_inst) |type_inst| | ||
| 797 | try addZIRBinOp(mod, scope, type_inst.src, .as, type_inst, init_inst) | ||
| 798 | else | ||
| 799 | init_inst; | ||
| 800 | |||
| 801 | const sub_scope = try block_arena.create(Scope.LocalVal); | ||
| 802 | sub_scope.* = .{ | ||
| 803 | .parent = scope, | ||
| 804 | .gen_zir = scope.getGenZIR(), | ||
| 805 | .name = ident_name, | ||
| 806 | .inst = casted_init, | ||
| 807 | }; | ||
| 808 | return &sub_scope.base; | ||
| 809 | } | ||
| 810 | // The initialization expression took advantage of the result location | ||
| 811 | // of the const local. In this case we will create an alloc and a LocalPtr for it. | ||
| 812 | // Move the init_scope instructions into the parent scope, swapping | ||
| 813 | // store_to_block_ptr for store_to_inferred_ptr. | ||
| 814 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len; | ||
| 815 | try parent_zir.ensureCapacity(mod.gpa, expected_len); | ||
| 816 | for (init_scope.instructions.items) |src_inst| { | ||
| 817 | if (src_inst.castTag(.store_to_block_ptr)) |store| { | ||
| 818 | if (store.positionals.lhs == init_scope.rl_ptr.?) { | ||
| 819 | src_inst.tag = .store_to_inferred_ptr; | ||
| 820 | } | ||
| 821 | } | ||
| 822 | parent_zir.appendAssumeCapacity(src_inst); | ||
| 823 | } | ||
| 824 | assert(parent_zir.items.len == expected_len); | ||
| 675 | if (resolve_inferred_alloc) |inst| { | 825 | if (resolve_inferred_alloc) |inst| { |
| 676 | _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); | 826 | _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); |
| 677 | } | 827 | } |
| 678 | const sub_scope = try block_arena.create(Scope.LocalVal); | 828 | const sub_scope = try block_arena.create(Scope.LocalPtr); |
| 679 | sub_scope.* = .{ | 829 | sub_scope.* = .{ |
| 680 | .parent = scope, | 830 | .parent = scope, |
| 681 | .gen_zir = scope.getGenZIR(), | 831 | .gen_zir = scope.getGenZIR(), |
| 682 | .name = ident_name, | 832 | .name = ident_name, |
| 683 | .inst = init_inst, | 833 | .ptr = init_scope.rl_ptr.?, |
| 684 | }; | 834 | }; |
| 685 | return &sub_scope.base; | 835 | return &sub_scope.base; |
| 686 | }, | 836 | }, |
| ... | @@ -751,14 +901,14 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr | ... | @@ -751,14 +901,14 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr |
| 751 | .val = Value.initTag(.bool_type), | 901 | .val = Value.initTag(.bool_type), |
| 752 | }); | 902 | }); |
| 753 | const operand = try expr(mod, scope, .{ .ty = bool_type }, node.rhs); | 903 | const operand = try expr(mod, scope, .{ .ty = bool_type }, node.rhs); |
| 754 | return addZIRUnOp(mod, scope, src, .boolnot, operand); | 904 | return addZIRUnOp(mod, scope, src, .bool_not, operand); |
| 755 | } | 905 | } |
| 756 | 906 | ||
| 757 | fn bitNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | 907 | fn bitNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { |
| 758 | const tree = scope.tree(); | 908 | const tree = scope.tree(); |
| 759 | const src = tree.token_locs[node.op_token].start; | 909 | const src = tree.token_locs[node.op_token].start; |
| 760 | const operand = try expr(mod, scope, .none, node.rhs); | 910 | const operand = try expr(mod, scope, .none, node.rhs); |
| 761 | return addZIRUnOp(mod, scope, src, .bitnot, operand); | 911 | return addZIRUnOp(mod, scope, src, .bit_not, operand); |
| 762 | } | 912 | } |
| 763 | 913 | ||
| 764 | fn negation(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { | 914 | fn negation(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { |
| ... | @@ -971,6 +1121,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con | ... | @@ -971,6 +1121,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 971 | .parent = scope, | 1121 | .parent = scope, |
| 972 | .decl = scope.ownerDecl().?, | 1122 | .decl = scope.ownerDecl().?, |
| 973 | .arena = scope.arena(), | 1123 | .arena = scope.arena(), |
| 1124 | .force_comptime = scope.isComptime(), | ||
| 974 | .instructions = .{}, | 1125 | .instructions = .{}, |
| 975 | }; | 1126 | }; |
| 976 | defer gen_scope.instructions.deinit(mod.gpa); | 1127 | defer gen_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1101,7 +1252,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con | ... | @@ -1101,7 +1252,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1101 | if (rl == .ref) { | 1252 | if (rl == .ref) { |
| 1102 | return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{}); | 1253 | return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{}); |
| 1103 | } else { | 1254 | } else { |
| 1104 | return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{ | 1255 | return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{ |
| 1105 | .decl = decl, | 1256 | .decl = decl, |
| 1106 | }, .{})); | 1257 | }, .{})); |
| 1107 | } | 1258 | } |
| ... | @@ -1207,24 +1358,15 @@ fn orelseCatchExpr( | ... | @@ -1207,24 +1358,15 @@ fn orelseCatchExpr( |
| 1207 | .parent = scope, | 1358 | .parent = scope, |
| 1208 | .decl = scope.ownerDecl().?, | 1359 | .decl = scope.ownerDecl().?, |
| 1209 | .arena = scope.arena(), | 1360 | .arena = scope.arena(), |
| 1361 | .force_comptime = scope.isComptime(), | ||
| 1210 | .instructions = .{}, | 1362 | .instructions = .{}, |
| 1211 | }; | 1363 | }; |
| 1364 | setBlockResultLoc(&block_scope, rl); | ||
| 1212 | defer block_scope.instructions.deinit(mod.gpa); | 1365 | defer block_scope.instructions.deinit(mod.gpa); |
| 1213 | 1366 | ||
| 1214 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | ||
| 1215 | .instructions = undefined, // populated below | ||
| 1216 | }); | ||
| 1217 | |||
| 1218 | // Most result location types can be forwarded directly; however | ||
| 1219 | // if we need to write to a pointer which has an inferred type, | ||
| 1220 | // proper type inference requires peer type resolution on the if's | ||
| 1221 | // branches. | ||
| 1222 | const branch_rl: ResultLoc = switch (rl) { | ||
| 1223 | .discard, .none, .ty, .ptr, .ref => rl, | ||
| 1224 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | ||
| 1225 | }; | ||
| 1226 | // This could be a pointer or value depending on the `rl` parameter. | 1367 | // This could be a pointer or value depending on the `rl` parameter. |
| 1227 | const operand = try expr(mod, &block_scope.base, branch_rl, lhs); | 1368 | block_scope.break_count += 1; |
| 1369 | const operand = try expr(mod, &block_scope.base, block_scope.break_result_loc, lhs); | ||
| 1228 | const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); | 1370 | const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); |
| 1229 | 1371 | ||
| 1230 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ | 1372 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ |
| ... | @@ -1233,18 +1375,22 @@ fn orelseCatchExpr( | ... | @@ -1233,18 +1375,22 @@ fn orelseCatchExpr( |
| 1233 | .else_body = undefined, // populated below | 1375 | .else_body = undefined, // populated below |
| 1234 | }, .{}); | 1376 | }, .{}); |
| 1235 | 1377 | ||
| 1378 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | ||
| 1379 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | ||
| 1380 | }); | ||
| 1381 | |||
| 1236 | var then_scope: Scope.GenZIR = .{ | 1382 | var then_scope: Scope.GenZIR = .{ |
| 1237 | .parent = &block_scope.base, | 1383 | .parent = &block_scope.base, |
| 1238 | .decl = block_scope.decl, | 1384 | .decl = block_scope.decl, |
| 1239 | .arena = block_scope.arena, | 1385 | .arena = block_scope.arena, |
| 1386 | .force_comptime = block_scope.force_comptime, | ||
| 1240 | .instructions = .{}, | 1387 | .instructions = .{}, |
| 1241 | }; | 1388 | }; |
| 1242 | defer then_scope.instructions.deinit(mod.gpa); | 1389 | defer then_scope.instructions.deinit(mod.gpa); |
| 1243 | 1390 | ||
| 1244 | var err_val_scope: Scope.LocalVal = undefined; | 1391 | var err_val_scope: Scope.LocalVal = undefined; |
| 1245 | const then_sub_scope = blk: { | 1392 | const then_sub_scope = blk: { |
| 1246 | const payload = payload_node orelse | 1393 | const payload = payload_node orelse break :blk &then_scope.base; |
| 1247 | break :blk &then_scope.base; | ||
| 1248 | 1394 | ||
| 1249 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); | 1395 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 1250 | if (mem.eql(u8, err_name, "_")) | 1396 | if (mem.eql(u8, err_name, "_")) |
| ... | @@ -1259,32 +1405,113 @@ fn orelseCatchExpr( | ... | @@ -1259,32 +1405,113 @@ fn orelseCatchExpr( |
| 1259 | break :blk &err_val_scope.base; | 1405 | break :blk &err_val_scope.base; |
| 1260 | }; | 1406 | }; |
| 1261 | 1407 | ||
| 1262 | _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ | 1408 | block_scope.break_count += 1; |
| 1263 | .block = block, | 1409 | const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, rhs); |
| 1264 | .operand = try expr(mod, then_sub_scope, branch_rl, rhs), | ||
| 1265 | }, .{}); | ||
| 1266 | 1410 | ||
| 1267 | var else_scope: Scope.GenZIR = .{ | 1411 | var else_scope: Scope.GenZIR = .{ |
| 1268 | .parent = &block_scope.base, | 1412 | .parent = &block_scope.base, |
| 1269 | .decl = block_scope.decl, | 1413 | .decl = block_scope.decl, |
| 1270 | .arena = block_scope.arena, | 1414 | .arena = block_scope.arena, |
| 1415 | .force_comptime = block_scope.force_comptime, | ||
| 1271 | .instructions = .{}, | 1416 | .instructions = .{}, |
| 1272 | }; | 1417 | }; |
| 1273 | defer else_scope.instructions.deinit(mod.gpa); | 1418 | defer else_scope.instructions.deinit(mod.gpa); |
| 1274 | 1419 | ||
| 1275 | // This could be a pointer or value depending on `unwrap_op`. | 1420 | // This could be a pointer or value depending on `unwrap_op`. |
| 1276 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); | 1421 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); |
| 1277 | _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ | ||
| 1278 | .block = block, | ||
| 1279 | .operand = unwrapped_payload, | ||
| 1280 | }, .{}); | ||
| 1281 | 1422 | ||
| 1282 | // All branches have been generated, add the instructions to the block. | 1423 | return finishThenElseBlock( |
| 1283 | block.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); | 1424 | mod, |
| 1425 | scope, | ||
| 1426 | rl, | ||
| 1427 | &block_scope, | ||
| 1428 | &then_scope, | ||
| 1429 | &else_scope, | ||
| 1430 | &condbr.positionals.then_body, | ||
| 1431 | &condbr.positionals.else_body, | ||
| 1432 | src, | ||
| 1433 | src, | ||
| 1434 | then_result, | ||
| 1435 | unwrapped_payload, | ||
| 1436 | block, | ||
| 1437 | block, | ||
| 1438 | ); | ||
| 1439 | } | ||
| 1284 | 1440 | ||
| 1285 | condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; | 1441 | fn finishThenElseBlock( |
| 1286 | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; | 1442 | mod: *Module, |
| 1287 | return &block.base; | 1443 | parent_scope: *Scope, |
| 1444 | rl: ResultLoc, | ||
| 1445 | block_scope: *Scope.GenZIR, | ||
| 1446 | then_scope: *Scope.GenZIR, | ||
| 1447 | else_scope: *Scope.GenZIR, | ||
| 1448 | then_body: *zir.Body, | ||
| 1449 | else_body: *zir.Body, | ||
| 1450 | then_src: usize, | ||
| 1451 | else_src: usize, | ||
| 1452 | then_result: *zir.Inst, | ||
| 1453 | else_result: ?*zir.Inst, | ||
| 1454 | main_block: *zir.Inst.Block, | ||
| 1455 | then_break_block: *zir.Inst.Block, | ||
| 1456 | ) InnerError!*zir.Inst { | ||
| 1457 | // We now have enough information to decide whether the result instruction should | ||
| 1458 | // be communicated via result location pointer or break instructions. | ||
| 1459 | const strat = rlStrategy(rl, block_scope); | ||
| 1460 | switch (strat.tag) { | ||
| 1461 | .break_void => { | ||
| 1462 | if (!then_result.tag.isNoReturn()) { | ||
| 1463 | _ = try addZirInstTag(mod, &then_scope.base, then_src, .break_void, .{ | ||
| 1464 | .block = then_break_block, | ||
| 1465 | }); | ||
| 1466 | } | ||
| 1467 | if (else_result) |inst| { | ||
| 1468 | if (!inst.tag.isNoReturn()) { | ||
| 1469 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ | ||
| 1470 | .block = main_block, | ||
| 1471 | }); | ||
| 1472 | } | ||
| 1473 | } else { | ||
| 1474 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ | ||
| 1475 | .block = main_block, | ||
| 1476 | }); | ||
| 1477 | } | ||
| 1478 | assert(!strat.elide_store_to_block_ptr_instructions); | ||
| 1479 | try copyBodyNoEliding(then_body, then_scope.*); | ||
| 1480 | try copyBodyNoEliding(else_body, else_scope.*); | ||
| 1481 | return &main_block.base; | ||
| 1482 | }, | ||
| 1483 | .break_operand => { | ||
| 1484 | if (!then_result.tag.isNoReturn()) { | ||
| 1485 | _ = try addZirInstTag(mod, &then_scope.base, then_src, .@"break", .{ | ||
| 1486 | .block = then_break_block, | ||
| 1487 | .operand = then_result, | ||
| 1488 | }); | ||
| 1489 | } | ||
| 1490 | if (else_result) |inst| { | ||
| 1491 | if (!inst.tag.isNoReturn()) { | ||
| 1492 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .@"break", .{ | ||
| 1493 | .block = main_block, | ||
| 1494 | .operand = inst, | ||
| 1495 | }); | ||
| 1496 | } | ||
| 1497 | } else { | ||
| 1498 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ | ||
| 1499 | .block = main_block, | ||
| 1500 | }); | ||
| 1501 | } | ||
| 1502 | if (strat.elide_store_to_block_ptr_instructions) { | ||
| 1503 | try copyBodyWithElidedStoreBlockPtr(then_body, then_scope.*); | ||
| 1504 | try copyBodyWithElidedStoreBlockPtr(else_body, else_scope.*); | ||
| 1505 | } else { | ||
| 1506 | try copyBodyNoEliding(then_body, then_scope.*); | ||
| 1507 | try copyBodyNoEliding(else_body, else_scope.*); | ||
| 1508 | } | ||
| 1509 | switch (rl) { | ||
| 1510 | .ref => return &main_block.base, | ||
| 1511 | else => return rvalue(mod, parent_scope, rl, &main_block.base), | ||
| 1512 | } | ||
| 1513 | }, | ||
| 1514 | } | ||
| 1288 | } | 1515 | } |
| 1289 | 1516 | ||
| 1290 | /// Return whether the identifier names of two tokens are equal. Resolves @"" | 1517 | /// Return whether the identifier names of two tokens are equal. Resolves @"" |
| ... | @@ -1308,7 +1535,7 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleI | ... | @@ -1308,7 +1535,7 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleI |
| 1308 | .field_name = field_name, | 1535 | .field_name = field_name, |
| 1309 | }); | 1536 | }); |
| 1310 | } | 1537 | } |
| 1311 | return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{ | 1538 | return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{ |
| 1312 | .object = try expr(mod, scope, .none, node.lhs), | 1539 | .object = try expr(mod, scope, .none, node.lhs), |
| 1313 | .field_name = field_name, | 1540 | .field_name = field_name, |
| 1314 | })); | 1541 | })); |
| ... | @@ -1338,7 +1565,7 @@ fn namedField( | ... | @@ -1338,7 +1565,7 @@ fn namedField( |
| 1338 | .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), | 1565 | .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), |
| 1339 | }); | 1566 | }); |
| 1340 | } | 1567 | } |
| 1341 | return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{ | 1568 | return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{ |
| 1342 | .object = try expr(mod, scope, .none, params[0]), | 1569 | .object = try expr(mod, scope, .none, params[0]), |
| 1343 | .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), | 1570 | .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), |
| 1344 | })); | 1571 | })); |
| ... | @@ -1359,7 +1586,7 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array | ... | @@ -1359,7 +1586,7 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array |
| 1359 | .index = try expr(mod, scope, index_rl, node.index_expr), | 1586 | .index = try expr(mod, scope, index_rl, node.index_expr), |
| 1360 | }); | 1587 | }); |
| 1361 | } | 1588 | } |
| 1362 | return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{ | 1589 | return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{ |
| 1363 | .array = try expr(mod, scope, .none, node.lhs), | 1590 | .array = try expr(mod, scope, .none, node.lhs), |
| 1364 | .index = try expr(mod, scope, index_rl, node.index_expr), | 1591 | .index = try expr(mod, scope, index_rl, node.index_expr), |
| 1365 | })); | 1592 | })); |
| ... | @@ -1416,7 +1643,7 @@ fn simpleBinOp( | ... | @@ -1416,7 +1643,7 @@ fn simpleBinOp( |
| 1416 | const rhs = try expr(mod, scope, .none, infix_node.rhs); | 1643 | const rhs = try expr(mod, scope, .none, infix_node.rhs); |
| 1417 | 1644 | ||
| 1418 | const result = try addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); | 1645 | const result = try addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); |
| 1419 | return rlWrap(mod, scope, rl, result); | 1646 | return rvalue(mod, scope, rl, result); |
| 1420 | } | 1647 | } |
| 1421 | 1648 | ||
| 1422 | fn boolBinOp( | 1649 | fn boolBinOp( |
| ... | @@ -1436,6 +1663,7 @@ fn boolBinOp( | ... | @@ -1436,6 +1663,7 @@ fn boolBinOp( |
| 1436 | .parent = scope, | 1663 | .parent = scope, |
| 1437 | .decl = scope.ownerDecl().?, | 1664 | .decl = scope.ownerDecl().?, |
| 1438 | .arena = scope.arena(), | 1665 | .arena = scope.arena(), |
| 1666 | .force_comptime = scope.isComptime(), | ||
| 1439 | .instructions = .{}, | 1667 | .instructions = .{}, |
| 1440 | }; | 1668 | }; |
| 1441 | defer block_scope.instructions.deinit(mod.gpa); | 1669 | defer block_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1455,6 +1683,7 @@ fn boolBinOp( | ... | @@ -1455,6 +1683,7 @@ fn boolBinOp( |
| 1455 | .parent = scope, | 1683 | .parent = scope, |
| 1456 | .decl = block_scope.decl, | 1684 | .decl = block_scope.decl, |
| 1457 | .arena = block_scope.arena, | 1685 | .arena = block_scope.arena, |
| 1686 | .force_comptime = block_scope.force_comptime, | ||
| 1458 | .instructions = .{}, | 1687 | .instructions = .{}, |
| 1459 | }; | 1688 | }; |
| 1460 | defer rhs_scope.instructions.deinit(mod.gpa); | 1689 | defer rhs_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1469,6 +1698,7 @@ fn boolBinOp( | ... | @@ -1469,6 +1698,7 @@ fn boolBinOp( |
| 1469 | .parent = scope, | 1698 | .parent = scope, |
| 1470 | .decl = block_scope.decl, | 1699 | .decl = block_scope.decl, |
| 1471 | .arena = block_scope.arena, | 1700 | .arena = block_scope.arena, |
| 1701 | .force_comptime = block_scope.force_comptime, | ||
| 1472 | .instructions = .{}, | 1702 | .instructions = .{}, |
| 1473 | }; | 1703 | }; |
| 1474 | defer const_scope.instructions.deinit(mod.gpa); | 1704 | defer const_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1498,7 +1728,7 @@ fn boolBinOp( | ... | @@ -1498,7 +1728,7 @@ fn boolBinOp( |
| 1498 | condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; | 1728 | condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; |
| 1499 | } | 1729 | } |
| 1500 | 1730 | ||
| 1501 | return rlWrap(mod, scope, rl, &block.base); | 1731 | return rvalue(mod, scope, rl, &block.base); |
| 1502 | } | 1732 | } |
| 1503 | 1733 | ||
| 1504 | const CondKind = union(enum) { | 1734 | const CondKind = union(enum) { |
| ... | @@ -1582,8 +1812,10 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -1582,8 +1812,10 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1582 | .parent = scope, | 1812 | .parent = scope, |
| 1583 | .decl = scope.ownerDecl().?, | 1813 | .decl = scope.ownerDecl().?, |
| 1584 | .arena = scope.arena(), | 1814 | .arena = scope.arena(), |
| 1815 | .force_comptime = scope.isComptime(), | ||
| 1585 | .instructions = .{}, | 1816 | .instructions = .{}, |
| 1586 | }; | 1817 | }; |
| 1818 | setBlockResultLoc(&block_scope, rl); | ||
| 1587 | defer block_scope.instructions.deinit(mod.gpa); | 1819 | defer block_scope.instructions.deinit(mod.gpa); |
| 1588 | 1820 | ||
| 1589 | const tree = scope.tree(); | 1821 | const tree = scope.tree(); |
| ... | @@ -1605,6 +1837,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -1605,6 +1837,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1605 | .parent = scope, | 1837 | .parent = scope, |
| 1606 | .decl = block_scope.decl, | 1838 | .decl = block_scope.decl, |
| 1607 | .arena = block_scope.arena, | 1839 | .arena = block_scope.arena, |
| 1840 | .force_comptime = block_scope.force_comptime, | ||
| 1608 | .instructions = .{}, | 1841 | .instructions = .{}, |
| 1609 | }; | 1842 | }; |
| 1610 | defer then_scope.instructions.deinit(mod.gpa); | 1843 | defer then_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1612,62 +1845,81 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -1612,62 +1845,81 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1612 | // declare payload to the then_scope | 1845 | // declare payload to the then_scope |
| 1613 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload); | 1846 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload); |
| 1614 | 1847 | ||
| 1615 | // Most result location types can be forwarded directly; however | 1848 | block_scope.break_count += 1; |
| 1616 | // if we need to write to a pointer which has an inferred type, | 1849 | const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, if_node.body); |
| 1617 | // proper type inference requires peer type resolution on the if's | 1850 | // We hold off on the break instructions as well as copying the then/else |
| 1618 | // branches. | 1851 | // instructions into place until we know whether to keep store_to_block_ptr |
| 1619 | const branch_rl: ResultLoc = switch (rl) { | 1852 | // instructions or not. |
| 1620 | .discard, .none, .ty, .ptr, .ref => rl, | ||
| 1621 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | ||
| 1622 | }; | ||
| 1623 | |||
| 1624 | const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body); | ||
| 1625 | if (!then_result.tag.isNoReturn()) { | ||
| 1626 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ | ||
| 1627 | .block = block, | ||
| 1628 | .operand = then_result, | ||
| 1629 | }, .{}); | ||
| 1630 | } | ||
| 1631 | condbr.positionals.then_body = .{ | ||
| 1632 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), | ||
| 1633 | }; | ||
| 1634 | 1853 | ||
| 1635 | var else_scope: Scope.GenZIR = .{ | 1854 | var else_scope: Scope.GenZIR = .{ |
| 1636 | .parent = scope, | 1855 | .parent = scope, |
| 1637 | .decl = block_scope.decl, | 1856 | .decl = block_scope.decl, |
| 1638 | .arena = block_scope.arena, | 1857 | .arena = block_scope.arena, |
| 1858 | .force_comptime = block_scope.force_comptime, | ||
| 1639 | .instructions = .{}, | 1859 | .instructions = .{}, |
| 1640 | }; | 1860 | }; |
| 1641 | defer else_scope.instructions.deinit(mod.gpa); | 1861 | defer else_scope.instructions.deinit(mod.gpa); |
| 1642 | 1862 | ||
| 1643 | if (if_node.@"else") |else_node| { | 1863 | var else_src: usize = undefined; |
| 1644 | const else_src = tree.token_locs[else_node.body.lastToken()].start; | 1864 | var else_sub_scope: *Module.Scope = undefined; |
| 1865 | const else_result: ?*zir.Inst = if (if_node.@"else") |else_node| blk: { | ||
| 1866 | else_src = tree.token_locs[else_node.body.lastToken()].start; | ||
| 1645 | // declare payload to the then_scope | 1867 | // declare payload to the then_scope |
| 1646 | const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); | 1868 | else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); |
| 1869 | |||
| 1870 | block_scope.break_count += 1; | ||
| 1871 | break :blk try expr(mod, else_sub_scope, block_scope.break_result_loc, else_node.body); | ||
| 1872 | } else blk: { | ||
| 1873 | else_src = tree.token_locs[if_node.lastToken()].start; | ||
| 1874 | else_sub_scope = &else_scope.base; | ||
| 1875 | break :blk null; | ||
| 1876 | }; | ||
| 1647 | 1877 | ||
| 1648 | const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body); | 1878 | return finishThenElseBlock( |
| 1649 | if (!else_result.tag.isNoReturn()) { | 1879 | mod, |
| 1650 | _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{ | 1880 | scope, |
| 1651 | .block = block, | 1881 | rl, |
| 1652 | .operand = else_result, | 1882 | &block_scope, |
| 1653 | }, .{}); | 1883 | &then_scope, |
| 1884 | &else_scope, | ||
| 1885 | &condbr.positionals.then_body, | ||
| 1886 | &condbr.positionals.else_body, | ||
| 1887 | then_src, | ||
| 1888 | else_src, | ||
| 1889 | then_result, | ||
| 1890 | else_result, | ||
| 1891 | block, | ||
| 1892 | block, | ||
| 1893 | ); | ||
| 1894 | } | ||
| 1895 | |||
| 1896 | /// Expects to find exactly 1 .store_to_block_ptr instruction. | ||
| 1897 | fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZIR) !void { | ||
| 1898 | body.* = .{ | ||
| 1899 | .instructions = try scope.arena.alloc(*zir.Inst, scope.instructions.items.len - 1), | ||
| 1900 | }; | ||
| 1901 | var dst_index: usize = 0; | ||
| 1902 | for (scope.instructions.items) |src_inst| { | ||
| 1903 | if (src_inst.tag != .store_to_block_ptr) { | ||
| 1904 | body.instructions[dst_index] = src_inst; | ||
| 1905 | dst_index += 1; | ||
| 1654 | } | 1906 | } |
| 1655 | } else { | ||
| 1656 | // TODO Optimization opportunity: we can avoid an allocation and a memcpy here | ||
| 1657 | // by directly allocating the body for this one instruction. | ||
| 1658 | const else_src = tree.token_locs[if_node.lastToken()].start; | ||
| 1659 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ | ||
| 1660 | .block = block, | ||
| 1661 | }, .{}); | ||
| 1662 | } | 1907 | } |
| 1663 | condbr.positionals.else_body = .{ | 1908 | assert(dst_index == body.instructions.len); |
| 1664 | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), | 1909 | } |
| 1665 | }; | ||
| 1666 | 1910 | ||
| 1667 | return &block.base; | 1911 | fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZIR) !void { |
| 1912 | body.* = .{ | ||
| 1913 | .instructions = try scope.arena.dupe(*zir.Inst, scope.instructions.items), | ||
| 1914 | }; | ||
| 1668 | } | 1915 | } |
| 1669 | 1916 | ||
| 1670 | fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { | 1917 | fn whileExpr( |
| 1918 | mod: *Module, | ||
| 1919 | scope: *Scope, | ||
| 1920 | rl: ResultLoc, | ||
| 1921 | while_node: *ast.Node.While, | ||
| 1922 | ) InnerError!*zir.Inst { | ||
| 1671 | var cond_kind: CondKind = .bool; | 1923 | var cond_kind: CondKind = .bool; |
| 1672 | if (while_node.payload) |_| cond_kind = .{ .optional = null }; | 1924 | if (while_node.payload) |_| cond_kind = .{ .optional = null }; |
| 1673 | if (while_node.@"else") |else_node| { | 1925 | if (while_node.@"else") |else_node| { |
| ... | @@ -1683,27 +1935,21 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1683,27 +1935,21 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1683 | if (while_node.inline_token) |tok| | 1935 | if (while_node.inline_token) |tok| |
| 1684 | return mod.failTok(scope, tok, "TODO inline while", .{}); | 1936 | return mod.failTok(scope, tok, "TODO inline while", .{}); |
| 1685 | 1937 | ||
| 1686 | var expr_scope: Scope.GenZIR = .{ | 1938 | var loop_scope: Scope.GenZIR = .{ |
| 1687 | .parent = scope, | 1939 | .parent = scope, |
| 1688 | .decl = scope.ownerDecl().?, | 1940 | .decl = scope.ownerDecl().?, |
| 1689 | .arena = scope.arena(), | 1941 | .arena = scope.arena(), |
| 1942 | .force_comptime = scope.isComptime(), | ||
| 1690 | .instructions = .{}, | 1943 | .instructions = .{}, |
| 1691 | }; | 1944 | }; |
| 1692 | defer expr_scope.instructions.deinit(mod.gpa); | 1945 | setBlockResultLoc(&loop_scope, rl); |
| 1693 | |||
| 1694 | var loop_scope: Scope.GenZIR = .{ | ||
| 1695 | .parent = &expr_scope.base, | ||
| 1696 | .decl = expr_scope.decl, | ||
| 1697 | .arena = expr_scope.arena, | ||
| 1698 | .instructions = .{}, | ||
| 1699 | .break_result_loc = rl, | ||
| 1700 | }; | ||
| 1701 | defer loop_scope.instructions.deinit(mod.gpa); | 1946 | defer loop_scope.instructions.deinit(mod.gpa); |
| 1702 | 1947 | ||
| 1703 | var continue_scope: Scope.GenZIR = .{ | 1948 | var continue_scope: Scope.GenZIR = .{ |
| 1704 | .parent = &loop_scope.base, | 1949 | .parent = &loop_scope.base, |
| 1705 | .decl = loop_scope.decl, | 1950 | .decl = loop_scope.decl, |
| 1706 | .arena = loop_scope.arena, | 1951 | .arena = loop_scope.arena, |
| 1952 | .force_comptime = loop_scope.force_comptime, | ||
| 1707 | .instructions = .{}, | 1953 | .instructions = .{}, |
| 1708 | }; | 1954 | }; |
| 1709 | defer continue_scope.instructions.deinit(mod.gpa); | 1955 | defer continue_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1731,11 +1977,21 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1731,11 +1977,21 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1731 | if (while_node.continue_expr) |cont_expr| { | 1977 | if (while_node.continue_expr) |cont_expr| { |
| 1732 | _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr); | 1978 | _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr); |
| 1733 | } | 1979 | } |
| 1734 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ | 1980 | const loop = try scope.arena().create(zir.Inst.Loop); |
| 1735 | .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), | 1981 | loop.* = .{ |
| 1736 | }); | 1982 | .base = .{ |
| 1983 | .tag = .loop, | ||
| 1984 | .src = while_src, | ||
| 1985 | }, | ||
| 1986 | .positionals = .{ | ||
| 1987 | .body = .{ | ||
| 1988 | .instructions = try scope.arena().dupe(*zir.Inst, loop_scope.instructions.items), | ||
| 1989 | }, | ||
| 1990 | }, | ||
| 1991 | .kw_args = .{}, | ||
| 1992 | }; | ||
| 1737 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ | 1993 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ |
| 1738 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), | 1994 | .instructions = try scope.arena().dupe(*zir.Inst, &[1]*zir.Inst{&loop.base}), |
| 1739 | }); | 1995 | }); |
| 1740 | loop_scope.break_block = while_block; | 1996 | loop_scope.break_block = while_block; |
| 1741 | loop_scope.continue_block = cond_block; | 1997 | loop_scope.continue_block = cond_block; |
| ... | @@ -1751,6 +2007,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1751,6 +2007,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1751 | .parent = &continue_scope.base, | 2007 | .parent = &continue_scope.base, |
| 1752 | .decl = continue_scope.decl, | 2008 | .decl = continue_scope.decl, |
| 1753 | .arena = continue_scope.arena, | 2009 | .arena = continue_scope.arena, |
| 2010 | .force_comptime = continue_scope.force_comptime, | ||
| 1754 | .instructions = .{}, | 2011 | .instructions = .{}, |
| 1755 | }; | 2012 | }; |
| 1756 | defer then_scope.instructions.deinit(mod.gpa); | 2013 | defer then_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1758,61 +2015,51 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1758,61 +2015,51 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1758 | // declare payload to the then_scope | 2015 | // declare payload to the then_scope |
| 1759 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload); | 2016 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload); |
| 1760 | 2017 | ||
| 1761 | // Most result location types can be forwarded directly; however | 2018 | loop_scope.break_count += 1; |
| 1762 | // if we need to write to a pointer which has an inferred type, | 2019 | const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, while_node.body); |
| 1763 | // proper type inference requires peer type resolution on the while's | ||
| 1764 | // branches. | ||
| 1765 | const branch_rl: ResultLoc = switch (rl) { | ||
| 1766 | .discard, .none, .ty, .ptr, .ref => rl, | ||
| 1767 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, | ||
| 1768 | }; | ||
| 1769 | |||
| 1770 | const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body); | ||
| 1771 | if (!then_result.tag.isNoReturn()) { | ||
| 1772 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ | ||
| 1773 | .block = cond_block, | ||
| 1774 | .operand = then_result, | ||
| 1775 | }, .{}); | ||
| 1776 | } | ||
| 1777 | condbr.positionals.then_body = .{ | ||
| 1778 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), | ||
| 1779 | }; | ||
| 1780 | 2020 | ||
| 1781 | var else_scope: Scope.GenZIR = .{ | 2021 | var else_scope: Scope.GenZIR = .{ |
| 1782 | .parent = &continue_scope.base, | 2022 | .parent = &continue_scope.base, |
| 1783 | .decl = continue_scope.decl, | 2023 | .decl = continue_scope.decl, |
| 1784 | .arena = continue_scope.arena, | 2024 | .arena = continue_scope.arena, |
| 2025 | .force_comptime = continue_scope.force_comptime, | ||
| 1785 | .instructions = .{}, | 2026 | .instructions = .{}, |
| 1786 | }; | 2027 | }; |
| 1787 | defer else_scope.instructions.deinit(mod.gpa); | 2028 | defer else_scope.instructions.deinit(mod.gpa); |
| 1788 | 2029 | ||
| 1789 | if (while_node.@"else") |else_node| { | 2030 | var else_src: usize = undefined; |
| 1790 | const else_src = tree.token_locs[else_node.body.lastToken()].start; | 2031 | const else_result: ?*zir.Inst = if (while_node.@"else") |else_node| blk: { |
| 2032 | else_src = tree.token_locs[else_node.body.lastToken()].start; | ||
| 1791 | // declare payload to the then_scope | 2033 | // declare payload to the then_scope |
| 1792 | const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); | 2034 | const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); |
| 1793 | 2035 | ||
| 1794 | const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body); | 2036 | loop_scope.break_count += 1; |
| 1795 | if (!else_result.tag.isNoReturn()) { | 2037 | break :blk try expr(mod, else_sub_scope, loop_scope.break_result_loc, else_node.body); |
| 1796 | _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{ | 2038 | } else blk: { |
| 1797 | .block = while_block, | 2039 | else_src = tree.token_locs[while_node.lastToken()].start; |
| 1798 | .operand = else_result, | 2040 | break :blk null; |
| 1799 | }, .{}); | ||
| 1800 | } | ||
| 1801 | } else { | ||
| 1802 | const else_src = tree.token_locs[while_node.lastToken()].start; | ||
| 1803 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ | ||
| 1804 | .block = while_block, | ||
| 1805 | }, .{}); | ||
| 1806 | } | ||
| 1807 | condbr.positionals.else_body = .{ | ||
| 1808 | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), | ||
| 1809 | }; | 2041 | }; |
| 1810 | if (loop_scope.label) |some| { | 2042 | if (loop_scope.label) |some| { |
| 1811 | if (!some.used) { | 2043 | if (!some.used) { |
| 1812 | return mod.fail(scope, tree.token_locs[some.token].start, "unused while label", .{}); | 2044 | return mod.fail(scope, tree.token_locs[some.token].start, "unused while label", .{}); |
| 1813 | } | 2045 | } |
| 1814 | } | 2046 | } |
| 1815 | return &while_block.base; | 2047 | return finishThenElseBlock( |
| 2048 | mod, | ||
| 2049 | scope, | ||
| 2050 | rl, | ||
| 2051 | &loop_scope, | ||
| 2052 | &then_scope, | ||
| 2053 | &else_scope, | ||
| 2054 | &condbr.positionals.then_body, | ||
| 2055 | &condbr.positionals.else_body, | ||
| 2056 | then_src, | ||
| 2057 | else_src, | ||
| 2058 | then_result, | ||
| 2059 | else_result, | ||
| 2060 | while_block, | ||
| 2061 | cond_block, | ||
| 2062 | ); | ||
| 1816 | } | 2063 | } |
| 1817 | 2064 | ||
| 1818 | fn forExpr( | 2065 | fn forExpr( |
| ... | @@ -1828,48 +2075,42 @@ fn forExpr( | ... | @@ -1828,48 +2075,42 @@ fn forExpr( |
| 1828 | if (for_node.inline_token) |tok| | 2075 | if (for_node.inline_token) |tok| |
| 1829 | return mod.failTok(scope, tok, "TODO inline for", .{}); | 2076 | return mod.failTok(scope, tok, "TODO inline for", .{}); |
| 1830 | 2077 | ||
| 1831 | var for_scope: Scope.GenZIR = .{ | ||
| 1832 | .parent = scope, | ||
| 1833 | .decl = scope.ownerDecl().?, | ||
| 1834 | .arena = scope.arena(), | ||
| 1835 | .instructions = .{}, | ||
| 1836 | }; | ||
| 1837 | defer for_scope.instructions.deinit(mod.gpa); | ||
| 1838 | |||
| 1839 | // setup variables and constants | 2078 | // setup variables and constants |
| 1840 | const tree = scope.tree(); | 2079 | const tree = scope.tree(); |
| 1841 | const for_src = tree.token_locs[for_node.for_token].start; | 2080 | const for_src = tree.token_locs[for_node.for_token].start; |
| 1842 | const index_ptr = blk: { | 2081 | const index_ptr = blk: { |
| 1843 | const usize_type = try addZIRInstConst(mod, &for_scope.base, for_src, .{ | 2082 | const usize_type = try addZIRInstConst(mod, scope, for_src, .{ |
| 1844 | .ty = Type.initTag(.type), | 2083 | .ty = Type.initTag(.type), |
| 1845 | .val = Value.initTag(.usize_type), | 2084 | .val = Value.initTag(.usize_type), |
| 1846 | }); | 2085 | }); |
| 1847 | const index_ptr = try addZIRUnOp(mod, &for_scope.base, for_src, .alloc, usize_type); | 2086 | const index_ptr = try addZIRUnOp(mod, scope, for_src, .alloc, usize_type); |
| 1848 | // initialize to zero | 2087 | // initialize to zero |
| 1849 | const zero = try addZIRInstConst(mod, &for_scope.base, for_src, .{ | 2088 | const zero = try addZIRInstConst(mod, scope, for_src, .{ |
| 1850 | .ty = Type.initTag(.usize), | 2089 | .ty = Type.initTag(.usize), |
| 1851 | .val = Value.initTag(.zero), | 2090 | .val = Value.initTag(.zero), |
| 1852 | }); | 2091 | }); |
| 1853 | _ = try addZIRBinOp(mod, &for_scope.base, for_src, .store, index_ptr, zero); | 2092 | _ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero); |
| 1854 | break :blk index_ptr; | 2093 | break :blk index_ptr; |
| 1855 | }; | 2094 | }; |
| 1856 | const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr); | 2095 | const array_ptr = try expr(mod, scope, .ref, for_node.array_expr); |
| 1857 | const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; | 2096 | const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; |
| 1858 | const len = try addZIRUnOp(mod, &for_scope.base, cond_src, .indexable_ptr_len, array_ptr); | 2097 | const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr); |
| 1859 | 2098 | ||
| 1860 | var loop_scope: Scope.GenZIR = .{ | 2099 | var loop_scope: Scope.GenZIR = .{ |
| 1861 | .parent = &for_scope.base, | 2100 | .parent = scope, |
| 1862 | .decl = for_scope.decl, | 2101 | .decl = scope.ownerDecl().?, |
| 1863 | .arena = for_scope.arena, | 2102 | .arena = scope.arena(), |
| 2103 | .force_comptime = scope.isComptime(), | ||
| 1864 | .instructions = .{}, | 2104 | .instructions = .{}, |
| 1865 | .break_result_loc = rl, | ||
| 1866 | }; | 2105 | }; |
| 2106 | setBlockResultLoc(&loop_scope, rl); | ||
| 1867 | defer loop_scope.instructions.deinit(mod.gpa); | 2107 | defer loop_scope.instructions.deinit(mod.gpa); |
| 1868 | 2108 | ||
| 1869 | var cond_scope: Scope.GenZIR = .{ | 2109 | var cond_scope: Scope.GenZIR = .{ |
| 1870 | .parent = &loop_scope.base, | 2110 | .parent = &loop_scope.base, |
| 1871 | .decl = loop_scope.decl, | 2111 | .decl = loop_scope.decl, |
| 1872 | .arena = loop_scope.arena, | 2112 | .arena = loop_scope.arena, |
| 2113 | .force_comptime = loop_scope.force_comptime, | ||
| 1873 | .instructions = .{}, | 2114 | .instructions = .{}, |
| 1874 | }; | 2115 | }; |
| 1875 | defer cond_scope.instructions.deinit(mod.gpa); | 2116 | defer cond_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1896,12 +2137,21 @@ fn forExpr( | ... | @@ -1896,12 +2137,21 @@ fn forExpr( |
| 1896 | const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one); | 2137 | const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one); |
| 1897 | _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); | 2138 | _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); |
| 1898 | 2139 | ||
| 1899 | // looping stuff | 2140 | const loop = try scope.arena().create(zir.Inst.Loop); |
| 1900 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ | 2141 | loop.* = .{ |
| 1901 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), | 2142 | .base = .{ |
| 1902 | }); | 2143 | .tag = .loop, |
| 2144 | .src = for_src, | ||
| 2145 | }, | ||
| 2146 | .positionals = .{ | ||
| 2147 | .body = .{ | ||
| 2148 | .instructions = try scope.arena().dupe(*zir.Inst, loop_scope.instructions.items), | ||
| 2149 | }, | ||
| 2150 | }, | ||
| 2151 | .kw_args = .{}, | ||
| 2152 | }; | ||
| 1903 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ | 2153 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ |
| 1904 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), | 2154 | .instructions = try scope.arena().dupe(*zir.Inst, &[1]*zir.Inst{&loop.base}), |
| 1905 | }); | 2155 | }); |
| 1906 | loop_scope.break_block = for_block; | 2156 | loop_scope.break_block = for_block; |
| 1907 | loop_scope.continue_block = cond_block; | 2157 | loop_scope.continue_block = cond_block; |
| ... | @@ -1918,19 +2168,11 @@ fn forExpr( | ... | @@ -1918,19 +2168,11 @@ fn forExpr( |
| 1918 | .parent = &cond_scope.base, | 2168 | .parent = &cond_scope.base, |
| 1919 | .decl = cond_scope.decl, | 2169 | .decl = cond_scope.decl, |
| 1920 | .arena = cond_scope.arena, | 2170 | .arena = cond_scope.arena, |
| 2171 | .force_comptime = cond_scope.force_comptime, | ||
| 1921 | .instructions = .{}, | 2172 | .instructions = .{}, |
| 1922 | }; | 2173 | }; |
| 1923 | defer then_scope.instructions.deinit(mod.gpa); | 2174 | defer then_scope.instructions.deinit(mod.gpa); |
| 1924 | 2175 | ||
| 1925 | // Most result location types can be forwarded directly; however | ||
| 1926 | // if we need to write to a pointer which has an inferred type, | ||
| 1927 | // proper type inference requires peer type resolution on the while's | ||
| 1928 | // branches. | ||
| 1929 | const branch_rl: ResultLoc = switch (rl) { | ||
| 1930 | .discard, .none, .ty, .ptr, .ref => rl, | ||
| 1931 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, | ||
| 1932 | }; | ||
| 1933 | |||
| 1934 | var index_scope: Scope.LocalPtr = undefined; | 2176 | var index_scope: Scope.LocalPtr = undefined; |
| 1935 | const then_sub_scope = blk: { | 2177 | const then_sub_scope = blk: { |
| 1936 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; | 2178 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; |
| ... | @@ -1959,319 +2201,49 @@ fn forExpr( | ... | @@ -1959,319 +2201,49 @@ fn forExpr( |
| 1959 | break :blk &index_scope.base; | 2201 | break :blk &index_scope.base; |
| 1960 | }; | 2202 | }; |
| 1961 | 2203 | ||
| 1962 | const then_result = try expr(mod, then_sub_scope, branch_rl, for_node.body); | 2204 | loop_scope.break_count += 1; |
| 1963 | if (!then_result.tag.isNoReturn()) { | 2205 | const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_node.body); |
| 1964 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ | ||
| 1965 | .block = cond_block, | ||
| 1966 | .operand = then_result, | ||
| 1967 | }, .{}); | ||
| 1968 | } | ||
| 1969 | condbr.positionals.then_body = .{ | ||
| 1970 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), | ||
| 1971 | }; | ||
| 1972 | 2206 | ||
| 1973 | // else branch | 2207 | // else branch |
| 1974 | var else_scope: Scope.GenZIR = .{ | 2208 | var else_scope: Scope.GenZIR = .{ |
| 1975 | .parent = &cond_scope.base, | 2209 | .parent = &cond_scope.base, |
| 1976 | .decl = cond_scope.decl, | 2210 | .decl = cond_scope.decl, |
| 1977 | .arena = cond_scope.arena, | 2211 | .arena = cond_scope.arena, |
| 2212 | .force_comptime = cond_scope.force_comptime, | ||
| 1978 | .instructions = .{}, | 2213 | .instructions = .{}, |
| 1979 | }; | 2214 | }; |
| 1980 | defer else_scope.instructions.deinit(mod.gpa); | 2215 | defer else_scope.instructions.deinit(mod.gpa); |
| 1981 | 2216 | ||
| 1982 | if (for_node.@"else") |else_node| { | 2217 | var else_src: usize = undefined; |
| 1983 | const else_src = tree.token_locs[else_node.body.lastToken()].start; | 2218 | const else_result: ?*zir.Inst = if (for_node.@"else") |else_node| blk: { |
| 1984 | const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); | 2219 | else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 1985 | if (!else_result.tag.isNoReturn()) { | 2220 | loop_scope.break_count += 1; |
| 1986 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ | 2221 | break :blk try expr(mod, &else_scope.base, loop_scope.break_result_loc, else_node.body); |
| 1987 | .block = for_block, | 2222 | } else blk: { |
| 1988 | .operand = else_result, | 2223 | else_src = tree.token_locs[for_node.lastToken()].start; |
| 1989 | }, .{}); | 2224 | break :blk null; |
| 1990 | } | ||
| 1991 | } else { | ||
| 1992 | const else_src = tree.token_locs[for_node.lastToken()].start; | ||
| 1993 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ | ||
| 1994 | .block = for_block, | ||
| 1995 | }, .{}); | ||
| 1996 | } | ||
| 1997 | condbr.positionals.else_body = .{ | ||
| 1998 | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), | ||
| 1999 | }; | 2225 | }; |
| 2000 | if (loop_scope.label) |some| { | 2226 | if (loop_scope.label) |some| { |
| 2001 | if (!some.used) { | 2227 | if (!some.used) { |
| 2002 | return mod.fail(scope, tree.token_locs[some.token].start, "unused for label", .{}); | 2228 | return mod.fail(scope, tree.token_locs[some.token].start, "unused for label", .{}); |
| 2003 | } | 2229 | } |
| 2004 | } | 2230 | } |
| 2005 | return &for_block.base; | 2231 | return finishThenElseBlock( |
| 2006 | } | 2232 | mod, |
| 2007 | 2233 | scope, | |
| 2008 | fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp { | 2234 | rl, |
| 2009 | var cur = node; | 2235 | &loop_scope, |
| 2010 | while (true) { | 2236 | &then_scope, |
| 2011 | switch (cur.tag) { | 2237 | &else_scope, |
| 2012 | .Range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur), | 2238 | &condbr.positionals.then_body, |
| 2013 | .GroupedExpression => cur = @fieldParentPtr(ast.Node.GroupedExpression, "base", cur).expr, | 2239 | &condbr.positionals.else_body, |
| 2014 | else => return null, | 2240 | then_src, |
| 2015 | } | 2241 | else_src, |
| 2016 | } | 2242 | then_result, |
| 2017 | } | 2243 | else_result, |
| 2018 | 2244 | for_block, | |
| 2019 | fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst { | 2245 | cond_block, |
| 2020 | var block_scope: Scope.GenZIR = .{ | 2246 | ); |
| 2021 | .parent = scope, | ||
| 2022 | .decl = scope.ownerDecl().?, | ||
| 2023 | .arena = scope.arena(), | ||
| 2024 | .instructions = .{}, | ||
| 2025 | }; | ||
| 2026 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 2027 | |||
| 2028 | const tree = scope.tree(); | ||
| 2029 | const switch_src = tree.token_locs[switch_node.switch_token].start; | ||
| 2030 | const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr); | ||
| 2031 | const target = try addZIRUnOp(mod, &block_scope.base, target_ptr.src, .deref, target_ptr); | ||
| 2032 | // Add the switch instruction here so that it comes before any range checks. | ||
| 2033 | const switch_inst = (try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{ | ||
| 2034 | .target_ptr = target_ptr, | ||
| 2035 | .cases = undefined, // populated below | ||
| 2036 | .items = &[_]*zir.Inst{}, // populated below | ||
| 2037 | .else_body = undefined, // populated below | ||
| 2038 | }, .{})).castTag(.switchbr).?; | ||
| 2039 | |||
| 2040 | var items = std.ArrayList(*zir.Inst).init(mod.gpa); | ||
| 2041 | defer items.deinit(); | ||
| 2042 | var cases = std.ArrayList(zir.Inst.SwitchBr.Case).init(mod.gpa); | ||
| 2043 | defer cases.deinit(); | ||
| 2044 | |||
| 2045 | // Add comptime block containing all prong items first, | ||
| 2046 | const item_block = try addZIRInstBlock(mod, scope, switch_src, .block_comptime_flat, .{ | ||
| 2047 | .instructions = undefined, // populated below | ||
| 2048 | }); | ||
| 2049 | // then add block containing the switch. | ||
| 2050 | const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{ | ||
| 2051 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | ||
| 2052 | }); | ||
| 2053 | |||
| 2054 | // Most result location types can be forwarded directly; however | ||
| 2055 | // if we need to write to a pointer which has an inferred type, | ||
| 2056 | // proper type inference requires peer type resolution on the switch case. | ||
| 2057 | const case_rl: ResultLoc = switch (rl) { | ||
| 2058 | .discard, .none, .ty, .ptr, .ref => rl, | ||
| 2059 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | ||
| 2060 | }; | ||
| 2061 | |||
| 2062 | var item_scope: Scope.GenZIR = .{ | ||
| 2063 | .parent = scope, | ||
| 2064 | .decl = scope.ownerDecl().?, | ||
| 2065 | .arena = scope.arena(), | ||
| 2066 | .instructions = .{}, | ||
| 2067 | }; | ||
| 2068 | defer item_scope.instructions.deinit(mod.gpa); | ||
| 2069 | |||
| 2070 | var case_scope: Scope.GenZIR = .{ | ||
| 2071 | .parent = scope, | ||
| 2072 | .decl = block_scope.decl, | ||
| 2073 | .arena = block_scope.arena, | ||
| 2074 | .instructions = .{}, | ||
| 2075 | }; | ||
| 2076 | defer case_scope.instructions.deinit(mod.gpa); | ||
| 2077 | |||
| 2078 | var else_scope: Scope.GenZIR = .{ | ||
| 2079 | .parent = scope, | ||
| 2080 | .decl = block_scope.decl, | ||
| 2081 | .arena = block_scope.arena, | ||
| 2082 | .instructions = .{}, | ||
| 2083 | }; | ||
| 2084 | defer else_scope.instructions.deinit(mod.gpa); | ||
| 2085 | |||
| 2086 | // first we gather all the switch items and check else/'_' prongs | ||
| 2087 | var else_src: ?usize = null; | ||
| 2088 | var underscore_src: ?usize = null; | ||
| 2089 | var first_range: ?*zir.Inst = null; | ||
| 2090 | var special_case: ?*ast.Node.SwitchCase = null; | ||
| 2091 | for (switch_node.cases()) |uncasted_case| { | ||
| 2092 | const case = uncasted_case.castTag(.SwitchCase).?; | ||
| 2093 | const case_src = tree.token_locs[case.firstToken()].start; | ||
| 2094 | // reset without freeing to reduce allocations. | ||
| 2095 | case_scope.instructions.items.len = 0; | ||
| 2096 | assert(case.items_len != 0); | ||
| 2097 | |||
| 2098 | // Check for else/_ prong, those are handled last. | ||
| 2099 | if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { | ||
| 2100 | if (else_src) |src| { | ||
| 2101 | const msg = msg: { | ||
| 2102 | const msg = try mod.errMsg( | ||
| 2103 | scope, | ||
| 2104 | case_src, | ||
| 2105 | "multiple else prongs in switch expression", | ||
| 2106 | .{}, | ||
| 2107 | ); | ||
| 2108 | errdefer msg.destroy(mod.gpa); | ||
| 2109 | try mod.errNote(scope, src, msg, "previous else prong is here", .{}); | ||
| 2110 | break :msg msg; | ||
| 2111 | }; | ||
| 2112 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 2113 | } | ||
| 2114 | else_src = case_src; | ||
| 2115 | special_case = case; | ||
| 2116 | continue; | ||
| 2117 | } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and | ||
| 2118 | mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) | ||
| 2119 | { | ||
| 2120 | if (underscore_src) |src| { | ||
| 2121 | const msg = msg: { | ||
| 2122 | const msg = try mod.errMsg( | ||
| 2123 | scope, | ||
| 2124 | case_src, | ||
| 2125 | "multiple '_' prongs in switch expression", | ||
| 2126 | .{}, | ||
| 2127 | ); | ||
| 2128 | errdefer msg.destroy(mod.gpa); | ||
| 2129 | try mod.errNote(scope, src, msg, "previous '_' prong is here", .{}); | ||
| 2130 | break :msg msg; | ||
| 2131 | }; | ||
| 2132 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 2133 | } | ||
| 2134 | underscore_src = case_src; | ||
| 2135 | special_case = case; | ||
| 2136 | continue; | ||
| 2137 | } | ||
| 2138 | |||
| 2139 | if (else_src) |some_else| { | ||
| 2140 | if (underscore_src) |some_underscore| { | ||
| 2141 | const msg = msg: { | ||
| 2142 | const msg = try mod.errMsg( | ||
| 2143 | scope, | ||
| 2144 | switch_src, | ||
| 2145 | "else and '_' prong in switch expression", | ||
| 2146 | .{}, | ||
| 2147 | ); | ||
| 2148 | errdefer msg.destroy(mod.gpa); | ||
| 2149 | try mod.errNote(scope, some_else, msg, "else prong is here", .{}); | ||
| 2150 | try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{}); | ||
| 2151 | break :msg msg; | ||
| 2152 | }; | ||
| 2153 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 2154 | } | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | // If this is a simple one item prong then it is handled by the switchbr. | ||
| 2158 | if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) { | ||
| 2159 | const item = try expr(mod, &item_scope.base, .none, case.items()[0]); | ||
| 2160 | try items.append(item); | ||
| 2161 | try switchCaseExpr(mod, &case_scope.base, case_rl, block, case); | ||
| 2162 | |||
| 2163 | try cases.append(.{ | ||
| 2164 | .item = item, | ||
| 2165 | .body = .{ .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items) }, | ||
| 2166 | }); | ||
| 2167 | continue; | ||
| 2168 | } | ||
| 2169 | |||
| 2170 | // TODO if the case has few items and no ranges it might be better | ||
| 2171 | // to just handle them as switch prongs. | ||
| 2172 | |||
| 2173 | // Check if the target matches any of the items. | ||
| 2174 | // 1, 2, 3..6 will result in | ||
| 2175 | // target == 1 or target == 2 or (target >= 3 and target <= 6) | ||
| 2176 | var any_ok: ?*zir.Inst = null; | ||
| 2177 | for (case.items()) |item| { | ||
| 2178 | if (getRangeNode(item)) |range| { | ||
| 2179 | const start = try expr(mod, &item_scope.base, .none, range.lhs); | ||
| 2180 | const end = try expr(mod, &item_scope.base, .none, range.rhs); | ||
| 2181 | const range_src = tree.token_locs[range.op_token].start; | ||
| 2182 | const range_inst = try addZIRBinOp(mod, &item_scope.base, range_src, .switch_range, start, end); | ||
| 2183 | try items.append(range_inst); | ||
| 2184 | if (first_range == null) first_range = range_inst; | ||
| 2185 | |||
| 2186 | // target >= start and target <= end | ||
| 2187 | const range_start_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .cmp_gte, target, start); | ||
| 2188 | const range_end_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .cmp_lte, target, end); | ||
| 2189 | const range_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .booland, range_start_ok, range_end_ok); | ||
| 2190 | |||
| 2191 | if (any_ok) |some| { | ||
| 2192 | any_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .boolor, some, range_ok); | ||
| 2193 | } else { | ||
| 2194 | any_ok = range_ok; | ||
| 2195 | } | ||
| 2196 | continue; | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | const item_inst = try expr(mod, &item_scope.base, .none, item); | ||
| 2200 | try items.append(item_inst); | ||
| 2201 | const cpm_ok = try addZIRBinOp(mod, &else_scope.base, item_inst.src, .cmp_eq, target, item_inst); | ||
| 2202 | |||
| 2203 | if (any_ok) |some| { | ||
| 2204 | any_ok = try addZIRBinOp(mod, &else_scope.base, item_inst.src, .boolor, some, cpm_ok); | ||
| 2205 | } else { | ||
| 2206 | any_ok = cpm_ok; | ||
| 2207 | } | ||
| 2208 | } | ||
| 2209 | |||
| 2210 | const condbr = try addZIRInstSpecial(mod, &case_scope.base, case_src, zir.Inst.CondBr, .{ | ||
| 2211 | .condition = any_ok.?, | ||
| 2212 | .then_body = undefined, // populated below | ||
| 2213 | .else_body = undefined, // populated below | ||
| 2214 | }, .{}); | ||
| 2215 | const cond_block = try addZIRInstBlock(mod, &else_scope.base, case_src, .block, .{ | ||
| 2216 | .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), | ||
| 2217 | }); | ||
| 2218 | |||
| 2219 | // reset cond_scope for then_body | ||
| 2220 | case_scope.instructions.items.len = 0; | ||
| 2221 | try switchCaseExpr(mod, &case_scope.base, case_rl, block, case); | ||
| 2222 | condbr.positionals.then_body = .{ | ||
| 2223 | .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), | ||
| 2224 | }; | ||
| 2225 | |||
| 2226 | // reset cond_scope for else_body | ||
| 2227 | case_scope.instructions.items.len = 0; | ||
| 2228 | _ = try addZIRInst(mod, &case_scope.base, case_src, zir.Inst.BreakVoid, .{ | ||
| 2229 | .block = cond_block, | ||
| 2230 | }, .{}); | ||
| 2231 | condbr.positionals.else_body = .{ | ||
| 2232 | .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), | ||
| 2233 | }; | ||
| 2234 | } | ||
| 2235 | |||
| 2236 | // Generate else block or a break last to finish the block. | ||
| 2237 | if (special_case) |case| { | ||
| 2238 | try switchCaseExpr(mod, &else_scope.base, case_rl, block, case); | ||
| 2239 | } else { | ||
| 2240 | // Not handling all possible cases is a compile error. | ||
| 2241 | _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreach_nocheck); | ||
| 2242 | } | ||
| 2243 | |||
| 2244 | // All items have been generated, add the instructions to the comptime block. | ||
| 2245 | item_block.positionals.body = .{ | ||
| 2246 | .instructions = try block_scope.arena.dupe(*zir.Inst, item_scope.instructions.items), | ||
| 2247 | }; | ||
| 2248 | |||
| 2249 | // Actually populate switch instruction values. | ||
| 2250 | if (else_src != null) switch_inst.kw_args.special_prong = .@"else"; | ||
| 2251 | if (underscore_src != null) switch_inst.kw_args.special_prong = .underscore; | ||
| 2252 | switch_inst.positionals.cases = try block_scope.arena.dupe(zir.Inst.SwitchBr.Case, cases.items); | ||
| 2253 | switch_inst.positionals.items = try block_scope.arena.dupe(*zir.Inst, items.items); | ||
| 2254 | switch_inst.kw_args.range = first_range; | ||
| 2255 | switch_inst.positionals.else_body = .{ | ||
| 2256 | .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), | ||
| 2257 | }; | ||
| 2258 | return &block.base; | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | fn switchCaseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, block: *zir.Inst.Block, case: *ast.Node.SwitchCase) !void { | ||
| 2262 | const tree = scope.tree(); | ||
| 2263 | const case_src = tree.token_locs[case.firstToken()].start; | ||
| 2264 | if (case.payload != null) { | ||
| 2265 | return mod.fail(scope, case_src, "TODO switch case payload capture", .{}); | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | const case_body = try expr(mod, scope, rl, case.expr); | ||
| 2269 | if (!case_body.tag.isNoReturn()) { | ||
| 2270 | _ = try addZIRInst(mod, scope, case_src, zir.Inst.Break, .{ | ||
| 2271 | .block = block, | ||
| 2272 | .operand = case_body, | ||
| 2273 | }, .{}); | ||
| 2274 | } | ||
| 2275 | } | 2247 | } |
| 2276 | 2248 | ||
| 2277 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { | 2249 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| ... | @@ -2288,7 +2260,7 @@ fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerE | ... | @@ -2288,7 +2260,7 @@ fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerE |
| 2288 | return addZIRUnOp(mod, scope, src, .@"return", operand); | 2260 | return addZIRUnOp(mod, scope, src, .@"return", operand); |
| 2289 | } | 2261 | } |
| 2290 | } else { | 2262 | } else { |
| 2291 | return addZIRNoOp(mod, scope, src, .returnvoid); | 2263 | return addZIRNoOp(mod, scope, src, .return_void); |
| 2292 | } | 2264 | } |
| 2293 | } | 2265 | } |
| 2294 | 2266 | ||
| ... | @@ -2305,7 +2277,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2305,7 +2277,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2305 | 2277 | ||
| 2306 | if (getSimplePrimitiveValue(ident_name)) |typed_value| { | 2278 | if (getSimplePrimitiveValue(ident_name)) |typed_value| { |
| 2307 | const result = try addZIRInstConst(mod, scope, src, typed_value); | 2279 | const result = try addZIRInstConst(mod, scope, src, typed_value); |
| 2308 | return rlWrap(mod, scope, rl, result); | 2280 | return rvalue(mod, scope, rl, result); |
| 2309 | } | 2281 | } |
| 2310 | 2282 | ||
| 2311 | if (ident_name.len >= 2) integer: { | 2283 | if (ident_name.len >= 2) integer: { |
| ... | @@ -2327,7 +2299,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2327,7 +2299,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2327 | 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type), | 2299 | 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type), |
| 2328 | 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type), | 2300 | 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type), |
| 2329 | else => { | 2301 | else => { |
| 2330 | return rlWrap(mod, scope, rl, try addZIRInstConst(mod, scope, src, .{ | 2302 | return rvalue(mod, scope, rl, try addZIRInstConst(mod, scope, src, .{ |
| 2331 | .ty = Type.initTag(.type), | 2303 | .ty = Type.initTag(.type), |
| 2332 | .val = try Value.Tag.int_type.create(scope.arena(), .{ | 2304 | .val = try Value.Tag.int_type.create(scope.arena(), .{ |
| 2333 | .signed = is_signed, | 2305 | .signed = is_signed, |
| ... | @@ -2340,7 +2312,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2340,7 +2312,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2340 | .ty = Type.initTag(.type), | 2312 | .ty = Type.initTag(.type), |
| 2341 | .val = val, | 2313 | .val = val, |
| 2342 | }); | 2314 | }); |
| 2343 | return rlWrap(mod, scope, rl, result); | 2315 | return rvalue(mod, scope, rl, result); |
| 2344 | } | 2316 | } |
| 2345 | } | 2317 | } |
| 2346 | 2318 | ||
| ... | @@ -2351,7 +2323,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2351,7 +2323,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2351 | .local_val => { | 2323 | .local_val => { |
| 2352 | const local_val = s.cast(Scope.LocalVal).?; | 2324 | const local_val = s.cast(Scope.LocalVal).?; |
| 2353 | if (mem.eql(u8, local_val.name, ident_name)) { | 2325 | if (mem.eql(u8, local_val.name, ident_name)) { |
| 2354 | return rlWrap(mod, scope, rl, local_val.inst); | 2326 | return rvalue(mod, scope, rl, local_val.inst); |
| 2355 | } | 2327 | } |
| 2356 | s = local_val.parent; | 2328 | s = local_val.parent; |
| 2357 | }, | 2329 | }, |
| ... | @@ -2360,7 +2332,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2360,7 +2332,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2360 | if (mem.eql(u8, local_ptr.name, ident_name)) { | 2332 | if (mem.eql(u8, local_ptr.name, ident_name)) { |
| 2361 | if (rl == .ref) return local_ptr.ptr; | 2333 | if (rl == .ref) return local_ptr.ptr; |
| 2362 | const loaded = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr); | 2334 | const loaded = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr); |
| 2363 | return rlWrap(mod, scope, rl, loaded); | 2335 | return rvalue(mod, scope, rl, loaded); |
| 2364 | } | 2336 | } |
| 2365 | s = local_ptr.parent; | 2337 | s = local_ptr.parent; |
| 2366 | }, | 2338 | }, |
| ... | @@ -2373,7 +2345,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2373,7 +2345,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2373 | if (rl == .ref) { | 2345 | if (rl == .ref) { |
| 2374 | return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{}); | 2346 | return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{}); |
| 2375 | } else { | 2347 | } else { |
| 2376 | return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{ | 2348 | return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{ |
| 2377 | .decl = decl, | 2349 | .decl = decl, |
| 2378 | }, .{})); | 2350 | }, .{})); |
| 2379 | } | 2351 | } |
| ... | @@ -2590,7 +2562,7 @@ fn simpleCast( | ... | @@ -2590,7 +2562,7 @@ fn simpleCast( |
| 2590 | const dest_type = try typeExpr(mod, scope, params[0]); | 2562 | const dest_type = try typeExpr(mod, scope, params[0]); |
| 2591 | const rhs = try expr(mod, scope, .none, params[1]); | 2563 | const rhs = try expr(mod, scope, .none, params[1]); |
| 2592 | const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs); | 2564 | const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs); |
| 2593 | return rlWrap(mod, scope, rl, result); | 2565 | return rvalue(mod, scope, rl, result); |
| 2594 | } | 2566 | } |
| 2595 | 2567 | ||
| 2596 | fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | 2568 | fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| ... | @@ -2601,31 +2573,30 @@ fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError | ... | @@ -2601,31 +2573,30 @@ fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError |
| 2601 | return addZIRUnOp(mod, scope, src, .ptrtoint, operand); | 2573 | return addZIRUnOp(mod, scope, src, .ptrtoint, operand); |
| 2602 | } | 2574 | } |
| 2603 | 2575 | ||
| 2604 | fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | 2576 | fn as( |
| 2577 | mod: *Module, | ||
| 2578 | scope: *Scope, | ||
| 2579 | rl: ResultLoc, | ||
| 2580 | call: *ast.Node.BuiltinCall, | ||
| 2581 | ) InnerError!*zir.Inst { | ||
| 2605 | try ensureBuiltinParamCount(mod, scope, call, 2); | 2582 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 2606 | const tree = scope.tree(); | 2583 | const tree = scope.tree(); |
| 2607 | const src = tree.token_locs[call.builtin_token].start; | 2584 | const src = tree.token_locs[call.builtin_token].start; |
| 2608 | const params = call.params(); | 2585 | const params = call.params(); |
| 2609 | const dest_type = try typeExpr(mod, scope, params[0]); | 2586 | const dest_type = try typeExpr(mod, scope, params[0]); |
| 2610 | switch (rl) { | 2587 | switch (rl) { |
| 2611 | .none => return try expr(mod, scope, .{ .ty = dest_type }, params[1]), | 2588 | .none, .discard, .ref, .ty => { |
| 2612 | .discard => { | ||
| 2613 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); | ||
| 2614 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); | ||
| 2615 | return result; | ||
| 2616 | }, | ||
| 2617 | .ref => { | ||
| 2618 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); | ||
| 2619 | return addZIRUnOp(mod, scope, result.src, .ref, result); | ||
| 2620 | }, | ||
| 2621 | .ty => |result_ty| { | ||
| 2622 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); | 2589 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 2623 | return addZIRBinOp(mod, scope, src, .as, result_ty, result); | 2590 | return rvalue(mod, scope, rl, result); |
| 2624 | }, | 2591 | }, |
| 2592 | |||
| 2625 | .ptr => |result_ptr| { | 2593 | .ptr => |result_ptr| { |
| 2626 | const casted_result_ptr = try addZIRBinOp(mod, scope, src, .coerce_result_ptr, dest_type, result_ptr); | 2594 | return asRlPtr(mod, scope, rl, src, result_ptr, params[1], dest_type); |
| 2627 | return expr(mod, scope, .{ .ptr = casted_result_ptr }, params[1]); | 2595 | }, |
| 2596 | .block_ptr => |block_scope| { | ||
| 2597 | return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, params[1], dest_type); | ||
| 2628 | }, | 2598 | }, |
| 2599 | |||
| 2629 | .bitcasted_ptr => |bitcasted_ptr| { | 2600 | .bitcasted_ptr => |bitcasted_ptr| { |
| 2630 | // TODO here we should be able to resolve the inference; we now have a type for the result. | 2601 | // TODO here we should be able to resolve the inference; we now have a type for the result. |
| 2631 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); | 2602 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); |
| ... | @@ -2634,13 +2605,50 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I | ... | @@ -2634,13 +2605,50 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I |
| 2634 | // TODO here we should be able to resolve the inference; we now have a type for the result. | 2605 | // TODO here we should be able to resolve the inference; we now have a type for the result. |
| 2635 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); | 2606 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); |
| 2636 | }, | 2607 | }, |
| 2637 | .block_ptr => |block_ptr| { | 2608 | } |
| 2638 | const casted_block_ptr = try addZIRInst(mod, scope, src, zir.Inst.CoerceResultBlockPtr, .{ | 2609 | } |
| 2639 | .dest_type = dest_type, | 2610 | |
| 2640 | .block = block_ptr, | 2611 | fn asRlPtr( |
| 2641 | }, .{}); | 2612 | mod: *Module, |
| 2642 | return expr(mod, scope, .{ .ptr = casted_block_ptr }, params[1]); | 2613 | scope: *Scope, |
| 2643 | }, | 2614 | rl: ResultLoc, |
| 2615 | src: usize, | ||
| 2616 | result_ptr: *zir.Inst, | ||
| 2617 | operand_node: *ast.Node, | ||
| 2618 | dest_type: *zir.Inst, | ||
| 2619 | ) InnerError!*zir.Inst { | ||
| 2620 | // Detect whether this expr() call goes into rvalue() to store the result into the | ||
| 2621 | // result location. If it does, elide the coerce_result_ptr instruction | ||
| 2622 | // as well as the store instruction, instead passing the result as an rvalue. | ||
| 2623 | var as_scope: Scope.GenZIR = .{ | ||
| 2624 | .parent = scope, | ||
| 2625 | .decl = scope.ownerDecl().?, | ||
| 2626 | .arena = scope.arena(), | ||
| 2627 | .force_comptime = scope.isComptime(), | ||
| 2628 | .instructions = .{}, | ||
| 2629 | }; | ||
| 2630 | defer as_scope.instructions.deinit(mod.gpa); | ||
| 2631 | |||
| 2632 | as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr); | ||
| 2633 | const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); | ||
| 2634 | const parent_zir = &scope.getGenZIR().instructions; | ||
| 2635 | if (as_scope.rvalue_rl_count == 1) { | ||
| 2636 | // Busted! This expression didn't actually need a pointer. | ||
| 2637 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; | ||
| 2638 | try parent_zir.ensureCapacity(mod.gpa, expected_len); | ||
| 2639 | for (as_scope.instructions.items) |src_inst| { | ||
| 2640 | if (src_inst == as_scope.rl_ptr.?) continue; | ||
| 2641 | if (src_inst.castTag(.store_to_block_ptr)) |store| { | ||
| 2642 | if (store.positionals.lhs == as_scope.rl_ptr.?) continue; | ||
| 2643 | } | ||
| 2644 | parent_zir.appendAssumeCapacity(src_inst); | ||
| 2645 | } | ||
| 2646 | assert(parent_zir.items.len == expected_len); | ||
| 2647 | const casted_result = try addZIRBinOp(mod, scope, dest_type.src, .as, dest_type, result); | ||
| 2648 | return rvalue(mod, scope, rl, casted_result); | ||
| 2649 | } else { | ||
| 2650 | try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); | ||
| 2651 | return result; | ||
| 2644 | } | 2652 | } |
| 2645 | } | 2653 | } |
| 2646 | 2654 | ||
| ... | @@ -2703,7 +2711,7 @@ fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerE | ... | @@ -2703,7 +2711,7 @@ fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerE |
| 2703 | const src = tree.token_locs[call.builtin_token].start; | 2711 | const src = tree.token_locs[call.builtin_token].start; |
| 2704 | const params = call.params(); | 2712 | const params = call.params(); |
| 2705 | const target = try expr(mod, scope, .none, params[0]); | 2713 | const target = try expr(mod, scope, .none, params[0]); |
| 2706 | return addZIRUnOp(mod, scope, src, .compileerror, target); | 2714 | return addZIRUnOp(mod, scope, src, .compile_error, target); |
| 2707 | } | 2715 | } |
| 2708 | 2716 | ||
| 2709 | fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | 2717 | fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| ... | @@ -2728,12 +2736,12 @@ fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCal | ... | @@ -2728,12 +2736,12 @@ fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCal |
| 2728 | return mod.failTok(scope, call.builtin_token, "expected at least 1 argument, found 0", .{}); | 2736 | return mod.failTok(scope, call.builtin_token, "expected at least 1 argument, found 0", .{}); |
| 2729 | } | 2737 | } |
| 2730 | if (params.len == 1) { | 2738 | if (params.len == 1) { |
| 2731 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .typeof, try expr(mod, scope, .none, params[0]))); | 2739 | return rvalue(mod, scope, rl, try addZIRUnOp(mod, scope, src, .typeof, try expr(mod, scope, .none, params[0]))); |
| 2732 | } | 2740 | } |
| 2733 | var items = try arena.alloc(*zir.Inst, params.len); | 2741 | var items = try arena.alloc(*zir.Inst, params.len); |
| 2734 | for (params) |param, param_i| | 2742 | for (params) |param, param_i| |
| 2735 | items[param_i] = try expr(mod, scope, .none, param); | 2743 | items[param_i] = try expr(mod, scope, .none, param); |
| 2736 | return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.TypeOfPeer, .{ .items = items }, .{})); | 2744 | return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.TypeOfPeer, .{ .items = items }, .{})); |
| 2737 | } | 2745 | } |
| 2738 | fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | 2746 | fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| 2739 | const tree = scope.tree(); | 2747 | const tree = scope.tree(); |
| ... | @@ -2756,7 +2764,7 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built | ... | @@ -2756,7 +2764,7 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built |
| 2756 | // Also, some builtins have a variable number of parameters. | 2764 | // Also, some builtins have a variable number of parameters. |
| 2757 | 2765 | ||
| 2758 | if (mem.eql(u8, builtin_name, "@ptrToInt")) { | 2766 | if (mem.eql(u8, builtin_name, "@ptrToInt")) { |
| 2759 | return rlWrap(mod, scope, rl, try ptrToInt(mod, scope, call)); | 2767 | return rvalue(mod, scope, rl, try ptrToInt(mod, scope, call)); |
| 2760 | } else if (mem.eql(u8, builtin_name, "@as")) { | 2768 | } else if (mem.eql(u8, builtin_name, "@as")) { |
| 2761 | return as(mod, scope, rl, call); | 2769 | return as(mod, scope, rl, call); |
| 2762 | } else if (mem.eql(u8, builtin_name, "@floatCast")) { | 2770 | } else if (mem.eql(u8, builtin_name, "@floatCast")) { |
| ... | @@ -2769,9 +2777,9 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built | ... | @@ -2769,9 +2777,9 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built |
| 2769 | return typeOf(mod, scope, rl, call); | 2777 | return typeOf(mod, scope, rl, call); |
| 2770 | } else if (mem.eql(u8, builtin_name, "@breakpoint")) { | 2778 | } else if (mem.eql(u8, builtin_name, "@breakpoint")) { |
| 2771 | const src = tree.token_locs[call.builtin_token].start; | 2779 | const src = tree.token_locs[call.builtin_token].start; |
| 2772 | return rlWrap(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint)); | 2780 | return rvalue(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint)); |
| 2773 | } else if (mem.eql(u8, builtin_name, "@import")) { | 2781 | } else if (mem.eql(u8, builtin_name, "@import")) { |
| 2774 | return rlWrap(mod, scope, rl, try import(mod, scope, call)); | 2782 | return rvalue(mod, scope, rl, try import(mod, scope, call)); |
| 2775 | } else if (mem.eql(u8, builtin_name, "@compileError")) { | 2783 | } else if (mem.eql(u8, builtin_name, "@compileError")) { |
| 2776 | return compileError(mod, scope, call); | 2784 | return compileError(mod, scope, call); |
| 2777 | } else if (mem.eql(u8, builtin_name, "@setEvalBranchQuota")) { | 2785 | } else if (mem.eql(u8, builtin_name, "@setEvalBranchQuota")) { |
| ... | @@ -2806,13 +2814,13 @@ fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) In | ... | @@ -2806,13 +2814,13 @@ fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) In |
| 2806 | .args = args, | 2814 | .args = args, |
| 2807 | }, .{}); | 2815 | }, .{}); |
| 2808 | // TODO function call with result location | 2816 | // TODO function call with result location |
| 2809 | return rlWrap(mod, scope, rl, result); | 2817 | return rvalue(mod, scope, rl, result); |
| 2810 | } | 2818 | } |
| 2811 | 2819 | ||
| 2812 | fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst { | 2820 | fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst { |
| 2813 | const tree = scope.tree(); | 2821 | const tree = scope.tree(); |
| 2814 | const src = tree.token_locs[unreach_node.token].start; | 2822 | const src = tree.token_locs[unreach_node.token].start; |
| 2815 | return addZIRNoOp(mod, scope, src, .@"unreachable"); | 2823 | return addZIRNoOp(mod, scope, src, .unreachable_safe); |
| 2816 | } | 2824 | } |
| 2817 | 2825 | ||
| 2818 | fn getSimplePrimitiveValue(name: []const u8) ?TypedValue { | 2826 | fn getSimplePrimitiveValue(name: []const u8) ?TypedValue { |
| ... | @@ -3099,7 +3107,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { | ... | @@ -3099,7 +3107,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3099 | /// result locations must call this function on their result. | 3107 | /// result locations must call this function on their result. |
| 3100 | /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. | 3108 | /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. |
| 3101 | /// If the `ResultLoc` is `ty`, it will coerce the result to the type. | 3109 | /// If the `ResultLoc` is `ty`, it will coerce the result to the type. |
| 3102 | fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerError!*zir.Inst { | 3110 | fn rvalue(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerError!*zir.Inst { |
| 3103 | switch (rl) { | 3111 | switch (rl) { |
| 3104 | .none => return result, | 3112 | .none => return result, |
| 3105 | .discard => { | 3113 | .discard => { |
| ... | @@ -3113,42 +3121,97 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr | ... | @@ -3113,42 +3121,97 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr |
| 3113 | }, | 3121 | }, |
| 3114 | .ty => |ty_inst| return addZIRBinOp(mod, scope, result.src, .as, ty_inst, result), | 3122 | .ty => |ty_inst| return addZIRBinOp(mod, scope, result.src, .as, ty_inst, result), |
| 3115 | .ptr => |ptr_inst| { | 3123 | .ptr => |ptr_inst| { |
| 3116 | const casted_result = try addZIRInst(mod, scope, result.src, zir.Inst.CoerceToPtrElem, .{ | 3124 | _ = try addZIRBinOp(mod, scope, result.src, .store, ptr_inst, result); |
| 3117 | .ptr = ptr_inst, | 3125 | return result; |
| 3118 | .value = result, | ||
| 3119 | }, .{}); | ||
| 3120 | _ = try addZIRBinOp(mod, scope, result.src, .store, ptr_inst, casted_result); | ||
| 3121 | return casted_result; | ||
| 3122 | }, | 3126 | }, |
| 3123 | .bitcasted_ptr => |bitcasted_ptr| { | 3127 | .bitcasted_ptr => |bitcasted_ptr| { |
| 3124 | return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{}); | 3128 | return mod.fail(scope, result.src, "TODO implement rvalue .bitcasted_ptr", .{}); |
| 3125 | }, | 3129 | }, |
| 3126 | .inferred_ptr => |alloc| { | 3130 | .inferred_ptr => |alloc| { |
| 3127 | _ = try addZIRBinOp(mod, scope, result.src, .store_to_inferred_ptr, &alloc.base, result); | 3131 | _ = try addZIRBinOp(mod, scope, result.src, .store_to_inferred_ptr, &alloc.base, result); |
| 3128 | return result; | 3132 | return result; |
| 3129 | }, | 3133 | }, |
| 3130 | .block_ptr => |block_ptr| { | 3134 | .block_ptr => |block_scope| { |
| 3131 | return mod.fail(scope, result.src, "TODO implement rlWrap .block_ptr", .{}); | 3135 | block_scope.rvalue_rl_count += 1; |
| 3136 | _ = try addZIRBinOp(mod, scope, result.src, .store_to_block_ptr, block_scope.rl_ptr.?, result); | ||
| 3137 | return result; | ||
| 3132 | }, | 3138 | }, |
| 3133 | } | 3139 | } |
| 3134 | } | 3140 | } |
| 3135 | 3141 | ||
| 3136 | fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, result: void) InnerError!*zir.Inst { | 3142 | fn rvalueVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, result: void) InnerError!*zir.Inst { |
| 3137 | const src = scope.tree().token_locs[node.firstToken()].start; | 3143 | const src = scope.tree().token_locs[node.firstToken()].start; |
| 3138 | const void_inst = try addZIRInstConst(mod, scope, src, .{ | 3144 | const void_inst = try addZIRInstConst(mod, scope, src, .{ |
| 3139 | .ty = Type.initTag(.void), | 3145 | .ty = Type.initTag(.void), |
| 3140 | .val = Value.initTag(.void_value), | 3146 | .val = Value.initTag(.void_value), |
| 3141 | }); | 3147 | }); |
| 3142 | return rlWrap(mod, scope, rl, void_inst); | 3148 | return rvalue(mod, scope, rl, void_inst); |
| 3149 | } | ||
| 3150 | |||
| 3151 | fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy { | ||
| 3152 | var elide_store_to_block_ptr_instructions = false; | ||
| 3153 | switch (rl) { | ||
| 3154 | // In this branch there will not be any store_to_block_ptr instructions. | ||
| 3155 | .discard, .none, .ty, .ref => return .{ | ||
| 3156 | .tag = .break_operand, | ||
| 3157 | .elide_store_to_block_ptr_instructions = false, | ||
| 3158 | }, | ||
| 3159 | // The pointer got passed through to the sub-expressions, so we will use | ||
| 3160 | // break_void here. | ||
| 3161 | // In this branch there will not be any store_to_block_ptr instructions. | ||
| 3162 | .ptr => return .{ | ||
| 3163 | .tag = .break_void, | ||
| 3164 | .elide_store_to_block_ptr_instructions = false, | ||
| 3165 | }, | ||
| 3166 | .inferred_ptr, .bitcasted_ptr, .block_ptr => { | ||
| 3167 | if (block_scope.rvalue_rl_count == block_scope.break_count) { | ||
| 3168 | // Neither prong of the if consumed the result location, so we can | ||
| 3169 | // use break instructions to create an rvalue. | ||
| 3170 | return .{ | ||
| 3171 | .tag = .break_operand, | ||
| 3172 | .elide_store_to_block_ptr_instructions = true, | ||
| 3173 | }; | ||
| 3174 | } else { | ||
| 3175 | // Allow the store_to_block_ptr instructions to remain so that | ||
| 3176 | // semantic analysis can turn them into bitcasts. | ||
| 3177 | return .{ | ||
| 3178 | .tag = .break_void, | ||
| 3179 | .elide_store_to_block_ptr_instructions = false, | ||
| 3180 | }; | ||
| 3181 | } | ||
| 3182 | }, | ||
| 3183 | } | ||
| 3143 | } | 3184 | } |
| 3144 | 3185 | ||
| 3145 | /// TODO go over all the callsites and see where we can introduce "by-value" ZIR instructions | 3186 | fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void { |
| 3146 | /// to save ZIR memory. For example, see DeclVal vs DeclRef. | 3187 | // Depending on whether the result location is a pointer or value, different |
| 3147 | /// Do not add additional callsites to this function. | 3188 | // ZIR needs to be generated. In the former case we rely on storing to the |
| 3148 | fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst { | 3189 | // pointer to communicate the result, and use breakvoid; in the latter case |
| 3149 | if (rl == .ref) return ptr; | 3190 | // the block break instructions will have the result values. |
| 3191 | // One more complication: when the result location is a pointer, we detect | ||
| 3192 | // the scenario where the result location is not consumed. In this case | ||
| 3193 | // we emit ZIR for the block break instructions to have the result values, | ||
| 3194 | // and then rvalue() on that to pass the value to the result location. | ||
| 3195 | switch (parent_rl) { | ||
| 3196 | .discard, .none, .ty, .ptr, .ref => { | ||
| 3197 | block_scope.break_result_loc = parent_rl; | ||
| 3198 | }, | ||
| 3199 | |||
| 3200 | .inferred_ptr => |ptr| { | ||
| 3201 | block_scope.rl_ptr = &ptr.base; | ||
| 3202 | block_scope.break_result_loc = .{ .block_ptr = block_scope }; | ||
| 3203 | }, | ||
| 3204 | |||
| 3205 | .bitcasted_ptr => |ptr| { | ||
| 3206 | block_scope.rl_ptr = &ptr.base; | ||
| 3207 | block_scope.break_result_loc = .{ .block_ptr = block_scope }; | ||
| 3208 | }, | ||
| 3150 | 3209 | ||
| 3151 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr)); | 3210 | .block_ptr => |parent_block_scope| { |
| 3211 | block_scope.rl_ptr = parent_block_scope.rl_ptr.?; | ||
| 3212 | block_scope.break_result_loc = .{ .block_ptr = block_scope }; | ||
| 3213 | }, | ||
| 3214 | } | ||
| 3152 | } | 3215 | } |
| 3153 | 3216 | ||
| 3154 | pub fn addZirInstTag( | 3217 | pub fn addZirInstTag( |
src/codegen.zig+34-23| ... | @@ -840,14 +840,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -840,14 +840,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 840 | .arg => return self.genArg(inst.castTag(.arg).?), | 840 | .arg => return self.genArg(inst.castTag(.arg).?), |
| 841 | .assembly => return self.genAsm(inst.castTag(.assembly).?), | 841 | .assembly => return self.genAsm(inst.castTag(.assembly).?), |
| 842 | .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), | 842 | .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), |
| 843 | .bitand => return self.genBitAnd(inst.castTag(.bitand).?), | 843 | .bit_and => return self.genBitAnd(inst.castTag(.bit_and).?), |
| 844 | .bitor => return self.genBitOr(inst.castTag(.bitor).?), | 844 | .bit_or => return self.genBitOr(inst.castTag(.bit_or).?), |
| 845 | .block => return self.genBlock(inst.castTag(.block).?), | 845 | .block => return self.genBlock(inst.castTag(.block).?), |
| 846 | .br => return self.genBr(inst.castTag(.br).?), | 846 | .br => return self.genBr(inst.castTag(.br).?), |
| 847 | .br_block_flat => return self.genBrBlockFlat(inst.castTag(.br_block_flat).?), | ||
| 847 | .breakpoint => return self.genBreakpoint(inst.src), | 848 | .breakpoint => return self.genBreakpoint(inst.src), |
| 848 | .brvoid => return self.genBrVoid(inst.castTag(.brvoid).?), | 849 | .br_void => return self.genBrVoid(inst.castTag(.br_void).?), |
| 849 | .booland => return self.genBoolOp(inst.castTag(.booland).?), | 850 | .bool_and => return self.genBoolOp(inst.castTag(.bool_and).?), |
| 850 | .boolor => return self.genBoolOp(inst.castTag(.boolor).?), | 851 | .bool_or => return self.genBoolOp(inst.castTag(.bool_or).?), |
| 851 | .call => return self.genCall(inst.castTag(.call).?), | 852 | .call => return self.genCall(inst.castTag(.call).?), |
| 852 | .cmp_lt => return self.genCmp(inst.castTag(.cmp_lt).?, .lt), | 853 | .cmp_lt => return self.genCmp(inst.castTag(.cmp_lt).?, .lt), |
| 853 | .cmp_lte => return self.genCmp(inst.castTag(.cmp_lte).?, .lte), | 854 | .cmp_lte => return self.genCmp(inst.castTag(.cmp_lte).?, .lte), |
| ... | @@ -1097,7 +1098,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1097,7 +1098,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1097 | if (inst.base.isUnused()) | 1098 | if (inst.base.isUnused()) |
| 1098 | return MCValue.dead; | 1099 | return MCValue.dead; |
| 1099 | switch (arch) { | 1100 | switch (arch) { |
| 1100 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitand), | 1101 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bit_and), |
| 1101 | else => return self.fail(inst.base.src, "TODO implement bitwise and for {}", .{self.target.cpu.arch}), | 1102 | else => return self.fail(inst.base.src, "TODO implement bitwise and for {}", .{self.target.cpu.arch}), |
| 1102 | } | 1103 | } |
| 1103 | } | 1104 | } |
| ... | @@ -1107,7 +1108,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1107,7 +1108,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1107 | if (inst.base.isUnused()) | 1108 | if (inst.base.isUnused()) |
| 1108 | return MCValue.dead; | 1109 | return MCValue.dead; |
| 1109 | switch (arch) { | 1110 | switch (arch) { |
| 1110 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bitor), | 1111 | .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bit_or), |
| 1111 | else => return self.fail(inst.base.src, "TODO implement bitwise or for {}", .{self.target.cpu.arch}), | 1112 | else => return self.fail(inst.base.src, "TODO implement bitwise or for {}", .{self.target.cpu.arch}), |
| 1112 | } | 1113 | } |
| 1113 | } | 1114 | } |
| ... | @@ -1371,10 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1371,10 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1371 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); | 1372 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); |
| 1372 | } | 1373 | } |
| 1373 | }, | 1374 | }, |
| 1374 | .booland, .bitand => { | 1375 | .bool_and, .bit_and => { |
| 1375 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); | 1376 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); |
| 1376 | }, | 1377 | }, |
| 1377 | .boolor, .bitor => { | 1378 | .bool_or, .bit_or => { |
| 1378 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); | 1379 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); |
| 1379 | }, | 1380 | }, |
| 1380 | .not, .xor => { | 1381 | .not, .xor => { |
| ... | @@ -2441,17 +2442,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2441,17 +2442,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2441 | } | 2442 | } |
| 2442 | } | 2443 | } |
| 2443 | 2444 | ||
| 2445 | fn genBrBlockFlat(self: *Self, inst: *ir.Inst.BrBlockFlat) !MCValue { | ||
| 2446 | try self.genBody(inst.body); | ||
| 2447 | const last = inst.body.instructions[inst.body.instructions.len - 1]; | ||
| 2448 | return self.br(inst.base.src, inst.block, last); | ||
| 2449 | } | ||
| 2450 | |||
| 2444 | fn genBr(self: *Self, inst: *ir.Inst.Br) !MCValue { | 2451 | fn genBr(self: *Self, inst: *ir.Inst.Br) !MCValue { |
| 2445 | if (inst.operand.ty.hasCodeGenBits()) { | 2452 | return self.br(inst.base.src, inst.block, inst.operand); |
| 2446 | const operand = try self.resolveInst(inst.operand); | ||
| 2447 | const block_mcv = @bitCast(MCValue, inst.block.codegen.mcv); | ||
| 2448 | if (block_mcv == .none) { | ||
| 2449 | inst.block.codegen.mcv = @bitCast(AnyMCValue, operand); | ||
| 2450 | } else { | ||
| 2451 | try self.setRegOrMem(inst.base.src, inst.block.base.ty, block_mcv, operand); | ||
| 2452 | } | ||
| 2453 | } | ||
| 2454 | return self.brVoid(inst.base.src, inst.block); | ||
| 2455 | } | 2453 | } |
| 2456 | 2454 | ||
| 2457 | fn genBrVoid(self: *Self, inst: *ir.Inst.BrVoid) !MCValue { | 2455 | fn genBrVoid(self: *Self, inst: *ir.Inst.BrVoid) !MCValue { |
| ... | @@ -2464,20 +2462,33 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2464,20 +2462,33 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2464 | switch (arch) { | 2462 | switch (arch) { |
| 2465 | .x86_64 => switch (inst.base.tag) { | 2463 | .x86_64 => switch (inst.base.tag) { |
| 2466 | // lhs AND rhs | 2464 | // lhs AND rhs |
| 2467 | .booland => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 4, 0x20), | 2465 | .bool_and => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 4, 0x20), |
| 2468 | // lhs OR rhs | 2466 | // lhs OR rhs |
| 2469 | .boolor => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 1, 0x08), | 2467 | .bool_or => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 1, 0x08), |
| 2470 | else => unreachable, // Not a boolean operation | 2468 | else => unreachable, // Not a boolean operation |
| 2471 | }, | 2469 | }, |
| 2472 | .arm, .armeb => switch (inst.base.tag) { | 2470 | .arm, .armeb => switch (inst.base.tag) { |
| 2473 | .booland => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .booland), | 2471 | .bool_and => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bool_and), |
| 2474 | .boolor => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .boolor), | 2472 | .bool_or => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bool_or), |
| 2475 | else => unreachable, // Not a boolean operation | 2473 | else => unreachable, // Not a boolean operation |
| 2476 | }, | 2474 | }, |
| 2477 | else => return self.fail(inst.base.src, "TODO implement boolean operations for {}", .{self.target.cpu.arch}), | 2475 | else => return self.fail(inst.base.src, "TODO implement boolean operations for {}", .{self.target.cpu.arch}), |
| 2478 | } | 2476 | } |
| 2479 | } | 2477 | } |
| 2480 | 2478 | ||
| 2479 | fn br(self: *Self, src: usize, block: *ir.Inst.Block, operand: *ir.Inst) !MCValue { | ||
| 2480 | if (operand.ty.hasCodeGenBits()) { | ||
| 2481 | const operand_mcv = try self.resolveInst(operand); | ||
| 2482 | const block_mcv = @bitCast(MCValue, block.codegen.mcv); | ||
| 2483 | if (block_mcv == .none) { | ||
| 2484 | block.codegen.mcv = @bitCast(AnyMCValue, operand_mcv); | ||
| 2485 | } else { | ||
| 2486 | try self.setRegOrMem(src, block.base.ty, block_mcv, operand_mcv); | ||
| 2487 | } | ||
| 2488 | } | ||
| 2489 | return self.brVoid(src, block); | ||
| 2490 | } | ||
| 2491 | |||
| 2481 | fn brVoid(self: *Self, src: usize, block: *ir.Inst.Block) !MCValue { | 2492 | fn brVoid(self: *Self, src: usize, block: *ir.Inst.Block) !MCValue { |
| 2482 | // Emit a jump with a relocation. It will be patched up after the block ends. | 2493 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| 2483 | try block.codegen.relocs.ensureCapacity(self.gpa, block.codegen.relocs.items.len + 1); | 2494 | try block.codegen.relocs.ensureCapacity(self.gpa, block.codegen.relocs.items.len + 1); |
src/ir.zig+43-13| ... | @@ -56,13 +56,20 @@ pub const Inst = struct { | ... | @@ -56,13 +56,20 @@ pub const Inst = struct { |
| 56 | alloc, | 56 | alloc, |
| 57 | arg, | 57 | arg, |
| 58 | assembly, | 58 | assembly, |
| 59 | bitand, | 59 | bit_and, |
| 60 | bitcast, | 60 | bitcast, |
| 61 | bitor, | 61 | bit_or, |
| 62 | block, | 62 | block, |
| 63 | br, | 63 | br, |
| 64 | /// Same as `br` except the operand is a list of instructions to be treated as | ||
| 65 | /// a flat block; that is there is only 1 break instruction from the block, and | ||
| 66 | /// it is implied to be after the last instruction, and the last instruction is | ||
| 67 | /// the break operand. | ||
| 68 | /// This instruction exists for late-stage semantic analysis patch ups, to | ||
| 69 | /// replace one br operand with multiple instructions, without moving anything else around. | ||
| 70 | br_block_flat, | ||
| 64 | breakpoint, | 71 | breakpoint, |
| 65 | brvoid, | 72 | br_void, |
| 66 | call, | 73 | call, |
| 67 | cmp_lt, | 74 | cmp_lt, |
| 68 | cmp_lte, | 75 | cmp_lte, |
| ... | @@ -85,8 +92,8 @@ pub const Inst = struct { | ... | @@ -85,8 +92,8 @@ pub const Inst = struct { |
| 85 | is_err, | 92 | is_err, |
| 86 | // *E!T => bool | 93 | // *E!T => bool |
| 87 | is_err_ptr, | 94 | is_err_ptr, |
| 88 | booland, | 95 | bool_and, |
| 89 | boolor, | 96 | bool_or, |
| 90 | /// Read a value from a pointer. | 97 | /// Read a value from a pointer. |
| 91 | load, | 98 | load, |
| 92 | loop, | 99 | loop, |
| ... | @@ -147,10 +154,10 @@ pub const Inst = struct { | ... | @@ -147,10 +154,10 @@ pub const Inst = struct { |
| 147 | .cmp_gt, | 154 | .cmp_gt, |
| 148 | .cmp_neq, | 155 | .cmp_neq, |
| 149 | .store, | 156 | .store, |
| 150 | .booland, | 157 | .bool_and, |
| 151 | .boolor, | 158 | .bool_or, |
| 152 | .bitand, | 159 | .bit_and, |
| 153 | .bitor, | 160 | .bit_or, |
| 154 | .xor, | 161 | .xor, |
| 155 | => BinOp, | 162 | => BinOp, |
| 156 | 163 | ||
| ... | @@ -158,7 +165,8 @@ pub const Inst = struct { | ... | @@ -158,7 +165,8 @@ pub const Inst = struct { |
| 158 | .assembly => Assembly, | 165 | .assembly => Assembly, |
| 159 | .block => Block, | 166 | .block => Block, |
| 160 | .br => Br, | 167 | .br => Br, |
| 161 | .brvoid => BrVoid, | 168 | .br_block_flat => BrBlockFlat, |
| 169 | .br_void => BrVoid, | ||
| 162 | .call => Call, | 170 | .call => Call, |
| 163 | .condbr => CondBr, | 171 | .condbr => CondBr, |
| 164 | .constant => Constant, | 172 | .constant => Constant, |
| ... | @@ -251,7 +259,8 @@ pub const Inst = struct { | ... | @@ -251,7 +259,8 @@ pub const Inst = struct { |
| 251 | pub fn breakBlock(base: *Inst) ?*Block { | 259 | pub fn breakBlock(base: *Inst) ?*Block { |
| 252 | return switch (base.tag) { | 260 | return switch (base.tag) { |
| 253 | .br => base.castTag(.br).?.block, | 261 | .br => base.castTag(.br).?.block, |
| 254 | .brvoid => base.castTag(.brvoid).?.block, | 262 | .br_void => base.castTag(.br_void).?.block, |
| 263 | .br_block_flat => base.castTag(.br_block_flat).?.block, | ||
| 255 | else => null, | 264 | else => null, |
| 256 | }; | 265 | }; |
| 257 | } | 266 | } |
| ... | @@ -355,6 +364,27 @@ pub const Inst = struct { | ... | @@ -355,6 +364,27 @@ pub const Inst = struct { |
| 355 | } | 364 | } |
| 356 | }; | 365 | }; |
| 357 | 366 | ||
| 367 | pub const convertable_br_size = std.math.max(@sizeOf(BrBlockFlat), @sizeOf(Br)); | ||
| 368 | pub const convertable_br_align = std.math.max(@alignOf(BrBlockFlat), @alignOf(Br)); | ||
| 369 | comptime { | ||
| 370 | assert(@byteOffsetOf(BrBlockFlat, "base") == @byteOffsetOf(Br, "base")); | ||
| 371 | } | ||
| 372 | |||
| 373 | pub const BrBlockFlat = struct { | ||
| 374 | pub const base_tag = Tag.br_block_flat; | ||
| 375 | |||
| 376 | base: Inst, | ||
| 377 | block: *Block, | ||
| 378 | body: Body, | ||
| 379 | |||
| 380 | pub fn operandCount(self: *const BrBlockFlat) usize { | ||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | pub fn getOperand(self: *const BrBlockFlat, index: usize) ?*Inst { | ||
| 384 | return null; | ||
| 385 | } | ||
| 386 | }; | ||
| 387 | |||
| 358 | pub const Br = struct { | 388 | pub const Br = struct { |
| 359 | pub const base_tag = Tag.br; | 389 | pub const base_tag = Tag.br; |
| 360 | 390 | ||
| ... | @@ -363,7 +393,7 @@ pub const Inst = struct { | ... | @@ -363,7 +393,7 @@ pub const Inst = struct { |
| 363 | operand: *Inst, | 393 | operand: *Inst, |
| 364 | 394 | ||
| 365 | pub fn operandCount(self: *const Br) usize { | 395 | pub fn operandCount(self: *const Br) usize { |
| 366 | return 0; | 396 | return 1; |
| 367 | } | 397 | } |
| 368 | pub fn getOperand(self: *const Br, index: usize) ?*Inst { | 398 | pub fn getOperand(self: *const Br, index: usize) ?*Inst { |
| 369 | if (index == 0) | 399 | if (index == 0) |
| ... | @@ -373,7 +403,7 @@ pub const Inst = struct { | ... | @@ -373,7 +403,7 @@ pub const Inst = struct { |
| 373 | }; | 403 | }; |
| 374 | 404 | ||
| 375 | pub const BrVoid = struct { | 405 | pub const BrVoid = struct { |
| 376 | pub const base_tag = Tag.brvoid; | 406 | pub const base_tag = Tag.br_void; |
| 377 | 407 | ||
| 378 | base: Inst, | 408 | base: Inst, |
| 379 | block: *Block, | 409 | block: *Block, |
src/zir.zig+110-165| ... | @@ -59,7 +59,7 @@ pub const Inst = struct { | ... | @@ -59,7 +59,7 @@ pub const Inst = struct { |
| 59 | /// Inline assembly. | 59 | /// Inline assembly. |
| 60 | @"asm", | 60 | @"asm", |
| 61 | /// Bitwise AND. `&` | 61 | /// Bitwise AND. `&` |
| 62 | bitand, | 62 | bit_and, |
| 63 | /// TODO delete this instruction, it has no purpose. | 63 | /// TODO delete this instruction, it has no purpose. |
| 64 | bitcast, | 64 | bitcast, |
| 65 | /// An arbitrary typed pointer is pointer-casted to a new Pointer. | 65 | /// An arbitrary typed pointer is pointer-casted to a new Pointer. |
| ... | @@ -71,9 +71,9 @@ pub const Inst = struct { | ... | @@ -71,9 +71,9 @@ pub const Inst = struct { |
| 71 | /// The new result location pointer has an inferred type. | 71 | /// The new result location pointer has an inferred type. |
| 72 | bitcast_result_ptr, | 72 | bitcast_result_ptr, |
| 73 | /// Bitwise NOT. `~` | 73 | /// Bitwise NOT. `~` |
| 74 | bitnot, | 74 | bit_not, |
| 75 | /// Bitwise OR. `|` | 75 | /// Bitwise OR. `|` |
| 76 | bitor, | 76 | bit_or, |
| 77 | /// A labeled block of code, which can return a value. | 77 | /// A labeled block of code, which can return a value. |
| 78 | block, | 78 | block, |
| 79 | /// A block of code, which can return a value. There are no instructions that break out of | 79 | /// A block of code, which can return a value. There are no instructions that break out of |
| ... | @@ -83,17 +83,17 @@ pub const Inst = struct { | ... | @@ -83,17 +83,17 @@ pub const Inst = struct { |
| 83 | block_comptime, | 83 | block_comptime, |
| 84 | /// Same as `block_flat` but additionally makes the inner instructions execute at comptime. | 84 | /// Same as `block_flat` but additionally makes the inner instructions execute at comptime. |
| 85 | block_comptime_flat, | 85 | block_comptime_flat, |
| 86 | /// Boolean AND. See also `bitand`. | 86 | /// Boolean AND. See also `bit_and`. |
| 87 | booland, | 87 | bool_and, |
| 88 | /// Boolean NOT. See also `bitnot`. | 88 | /// Boolean NOT. See also `bit_not`. |
| 89 | boolnot, | 89 | bool_not, |
| 90 | /// Boolean OR. See also `bitor`. | 90 | /// Boolean OR. See also `bit_or`. |
| 91 | boolor, | 91 | bool_or, |
| 92 | /// Return a value from a `Block`. | 92 | /// Return a value from a `Block`. |
| 93 | @"break", | 93 | @"break", |
| 94 | breakpoint, | 94 | breakpoint, |
| 95 | /// Same as `break` but without an operand; the operand is assumed to be the void value. | 95 | /// Same as `break` but without an operand; the operand is assumed to be the void value. |
| 96 | breakvoid, | 96 | break_void, |
| 97 | /// Function call. | 97 | /// Function call. |
| 98 | call, | 98 | call, |
| 99 | /// `<` | 99 | /// `<` |
| ... | @@ -112,16 +112,10 @@ pub const Inst = struct { | ... | @@ -112,16 +112,10 @@ pub const Inst = struct { |
| 112 | /// as type coercion from the new element type to the old element type. | 112 | /// as type coercion from the new element type to the old element type. |
| 113 | /// LHS is destination element type, RHS is result pointer. | 113 | /// LHS is destination element type, RHS is result pointer. |
| 114 | coerce_result_ptr, | 114 | coerce_result_ptr, |
| 115 | /// This instruction does a `coerce_result_ptr` operation on a `Block`'s | ||
| 116 | /// result location pointer, whose type is inferred by peer type resolution on the | ||
| 117 | /// `Block`'s corresponding `break` instructions. | ||
| 118 | coerce_result_block_ptr, | ||
| 119 | /// Equivalent to `as(ptr_child_type(typeof(ptr)), value)`. | ||
| 120 | coerce_to_ptr_elem, | ||
| 121 | /// Emit an error message and fail compilation. | 115 | /// Emit an error message and fail compilation. |
| 122 | compileerror, | 116 | compile_error, |
| 123 | /// Log compile time variables and emit an error message. | 117 | /// Log compile time variables and emit an error message. |
| 124 | compilelog, | 118 | compile_log, |
| 125 | /// Conditional branch. Splits control flow based on a boolean condition value. | 119 | /// Conditional branch. Splits control flow based on a boolean condition value. |
| 126 | condbr, | 120 | condbr, |
| 127 | /// Special case, has no textual representation. | 121 | /// Special case, has no textual representation. |
| ... | @@ -135,11 +129,11 @@ pub const Inst = struct { | ... | @@ -135,11 +129,11 @@ pub const Inst = struct { |
| 135 | /// Declares the beginning of a statement. Used for debug info. | 129 | /// Declares the beginning of a statement. Used for debug info. |
| 136 | dbg_stmt, | 130 | dbg_stmt, |
| 137 | /// Represents a pointer to a global decl. | 131 | /// Represents a pointer to a global decl. |
| 138 | declref, | 132 | decl_ref, |
| 139 | /// Represents a pointer to a global decl by string name. | 133 | /// Represents a pointer to a global decl by string name. |
| 140 | declref_str, | 134 | decl_ref_str, |
| 141 | /// Equivalent to a declref followed by deref. | 135 | /// Equivalent to a decl_ref followed by deref. |
| 142 | declval, | 136 | decl_val, |
| 143 | /// Load the value from a pointer. | 137 | /// Load the value from a pointer. |
| 144 | deref, | 138 | deref, |
| 145 | /// Arithmetic division. Asserts no integer overflow. | 139 | /// Arithmetic division. Asserts no integer overflow. |
| ... | @@ -185,7 +179,7 @@ pub const Inst = struct { | ... | @@ -185,7 +179,7 @@ pub const Inst = struct { |
| 185 | /// can hold the same mathematical value. | 179 | /// can hold the same mathematical value. |
| 186 | intcast, | 180 | intcast, |
| 187 | /// Make an integer type out of signedness and bit count. | 181 | /// Make an integer type out of signedness and bit count. |
| 188 | inttype, | 182 | int_type, |
| 189 | /// Return a boolean false if an optional is null. `x != null` | 183 | /// Return a boolean false if an optional is null. `x != null` |
| 190 | is_non_null, | 184 | is_non_null, |
| 191 | /// Return a boolean true if an optional is null. `x == null` | 185 | /// Return a boolean true if an optional is null. `x == null` |
| ... | @@ -232,7 +226,7 @@ pub const Inst = struct { | ... | @@ -232,7 +226,7 @@ pub const Inst = struct { |
| 232 | /// Sends control flow back to the function's callee. Takes an operand as the return value. | 226 | /// Sends control flow back to the function's callee. Takes an operand as the return value. |
| 233 | @"return", | 227 | @"return", |
| 234 | /// Same as `return` but there is no operand; the operand is implicitly the void value. | 228 | /// Same as `return` but there is no operand; the operand is implicitly the void value. |
| 235 | returnvoid, | 229 | return_void, |
| 236 | /// Changes the maximum number of backwards branches that compile-time | 230 | /// Changes the maximum number of backwards branches that compile-time |
| 237 | /// code execution can use before giving up and making a compile error. | 231 | /// code execution can use before giving up and making a compile error. |
| 238 | set_eval_branch_quota, | 232 | set_eval_branch_quota, |
| ... | @@ -270,6 +264,9 @@ pub const Inst = struct { | ... | @@ -270,6 +264,9 @@ pub const Inst = struct { |
| 270 | /// Write a value to a pointer. For loading, see `deref`. | 264 | /// Write a value to a pointer. For loading, see `deref`. |
| 271 | store, | 265 | store, |
| 272 | /// Same as `store` but the type of the value being stored will be used to infer | 266 | /// Same as `store` but the type of the value being stored will be used to infer |
| 267 | /// the block type. The LHS is the pointer to store to. | ||
| 268 | store_to_block_ptr, | ||
| 269 | /// Same as `store` but the type of the value being stored will be used to infer | ||
| 273 | /// the pointer type. | 270 | /// the pointer type. |
| 274 | store_to_inferred_ptr, | 271 | store_to_inferred_ptr, |
| 275 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. | 272 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. |
| ... | @@ -286,11 +283,11 @@ pub const Inst = struct { | ... | @@ -286,11 +283,11 @@ pub const Inst = struct { |
| 286 | typeof_peer, | 283 | typeof_peer, |
| 287 | /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler | 284 | /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler |
| 288 | /// will assume the correctness of this instruction. | 285 | /// will assume the correctness of this instruction. |
| 289 | unreach_nocheck, | 286 | unreachable_unsafe, |
| 290 | /// Asserts control-flow will not reach this instruction. In safety-checked modes, | 287 | /// Asserts control-flow will not reach this instruction. In safety-checked modes, |
| 291 | /// this will generate a call to the panic function unless it can be proven unreachable | 288 | /// this will generate a call to the panic function unless it can be proven unreachable |
| 292 | /// by the compiler. | 289 | /// by the compiler. |
| 293 | @"unreachable", | 290 | unreachable_safe, |
| 294 | /// Bitwise XOR. `^` | 291 | /// Bitwise XOR. `^` |
| 295 | xor, | 292 | xor, |
| 296 | /// Create an optional type '?T' | 293 | /// Create an optional type '?T' |
| ... | @@ -339,12 +336,8 @@ pub const Inst = struct { | ... | @@ -339,12 +336,8 @@ pub const Inst = struct { |
| 339 | enum_literal, | 336 | enum_literal, |
| 340 | /// Create an enum type. | 337 | /// Create an enum type. |
| 341 | enum_type, | 338 | enum_type, |
| 342 | /// A switch expression. | 339 | /// Does nothing; returns a void value. |
| 343 | switchbr, | 340 | void_value, |
| 344 | /// A range in a switch case, `lhs...rhs`. | ||
| 345 | /// Only checks that `lhs >= rhs` if they are ints, everything else is | ||
| 346 | /// validated by the .switch instruction. | ||
| 347 | switch_range, | ||
| 348 | 341 | ||
| 349 | pub fn Type(tag: Tag) type { | 342 | pub fn Type(tag: Tag) type { |
| 350 | return switch (tag) { | 343 | return switch (tag) { |
| ... | @@ -352,17 +345,18 @@ pub const Inst = struct { | ... | @@ -352,17 +345,18 @@ pub const Inst = struct { |
| 352 | .alloc_inferred_mut, | 345 | .alloc_inferred_mut, |
| 353 | .breakpoint, | 346 | .breakpoint, |
| 354 | .dbg_stmt, | 347 | .dbg_stmt, |
| 355 | .returnvoid, | 348 | .return_void, |
| 356 | .ret_ptr, | 349 | .ret_ptr, |
| 357 | .ret_type, | 350 | .ret_type, |
| 358 | .unreach_nocheck, | 351 | .unreachable_unsafe, |
| 359 | .@"unreachable", | 352 | .unreachable_safe, |
| 353 | .void_value, | ||
| 360 | => NoOp, | 354 | => NoOp, |
| 361 | 355 | ||
| 362 | .alloc, | 356 | .alloc, |
| 363 | .alloc_mut, | 357 | .alloc_mut, |
| 364 | .boolnot, | 358 | .bool_not, |
| 365 | .compileerror, | 359 | .compile_error, |
| 366 | .deref, | 360 | .deref, |
| 367 | .@"return", | 361 | .@"return", |
| 368 | .is_null, | 362 | .is_null, |
| ... | @@ -400,7 +394,7 @@ pub const Inst = struct { | ... | @@ -400,7 +394,7 @@ pub const Inst = struct { |
| 400 | .err_union_code_ptr, | 394 | .err_union_code_ptr, |
| 401 | .ensure_err_payload_void, | 395 | .ensure_err_payload_void, |
| 402 | .anyframe_type, | 396 | .anyframe_type, |
| 403 | .bitnot, | 397 | .bit_not, |
| 404 | .import, | 398 | .import, |
| 405 | .set_eval_branch_quota, | 399 | .set_eval_branch_quota, |
| 406 | .indexable_ptr_len, | 400 | .indexable_ptr_len, |
| ... | @@ -411,10 +405,10 @@ pub const Inst = struct { | ... | @@ -411,10 +405,10 @@ pub const Inst = struct { |
| 411 | .array_cat, | 405 | .array_cat, |
| 412 | .array_mul, | 406 | .array_mul, |
| 413 | .array_type, | 407 | .array_type, |
| 414 | .bitand, | 408 | .bit_and, |
| 415 | .bitor, | 409 | .bit_or, |
| 416 | .booland, | 410 | .bool_and, |
| 417 | .boolor, | 411 | .bool_or, |
| 418 | .div, | 412 | .div, |
| 419 | .mod_rem, | 413 | .mod_rem, |
| 420 | .mul, | 414 | .mul, |
| ... | @@ -422,6 +416,7 @@ pub const Inst = struct { | ... | @@ -422,6 +416,7 @@ pub const Inst = struct { |
| 422 | .shl, | 416 | .shl, |
| 423 | .shr, | 417 | .shr, |
| 424 | .store, | 418 | .store, |
| 419 | .store_to_block_ptr, | ||
| 425 | .store_to_inferred_ptr, | 420 | .store_to_inferred_ptr, |
| 426 | .sub, | 421 | .sub, |
| 427 | .subwrap, | 422 | .subwrap, |
| ... | @@ -440,7 +435,6 @@ pub const Inst = struct { | ... | @@ -440,7 +435,6 @@ pub const Inst = struct { |
| 440 | .error_union_type, | 435 | .error_union_type, |
| 441 | .merge_error_sets, | 436 | .merge_error_sets, |
| 442 | .slice_start, | 437 | .slice_start, |
| 443 | .switch_range, | ||
| 444 | => BinOp, | 438 | => BinOp, |
| 445 | 439 | ||
| 446 | .block, | 440 | .block, |
| ... | @@ -452,19 +446,17 @@ pub const Inst = struct { | ... | @@ -452,19 +446,17 @@ pub const Inst = struct { |
| 452 | .arg => Arg, | 446 | .arg => Arg, |
| 453 | .array_type_sentinel => ArrayTypeSentinel, | 447 | .array_type_sentinel => ArrayTypeSentinel, |
| 454 | .@"break" => Break, | 448 | .@"break" => Break, |
| 455 | .breakvoid => BreakVoid, | 449 | .break_void => BreakVoid, |
| 456 | .call => Call, | 450 | .call => Call, |
| 457 | .coerce_to_ptr_elem => CoerceToPtrElem, | 451 | .decl_ref => DeclRef, |
| 458 | .declref => DeclRef, | 452 | .decl_ref_str => DeclRefStr, |
| 459 | .declref_str => DeclRefStr, | 453 | .decl_val => DeclVal, |
| 460 | .declval => DeclVal, | 454 | .compile_log => CompileLog, |
| 461 | .coerce_result_block_ptr => CoerceResultBlockPtr, | ||
| 462 | .compilelog => CompileLog, | ||
| 463 | .loop => Loop, | 455 | .loop => Loop, |
| 464 | .@"const" => Const, | 456 | .@"const" => Const, |
| 465 | .str => Str, | 457 | .str => Str, |
| 466 | .int => Int, | 458 | .int => Int, |
| 467 | .inttype => IntType, | 459 | .int_type => IntType, |
| 468 | .field_ptr, .field_val => Field, | 460 | .field_ptr, .field_val => Field, |
| 469 | .field_ptr_named, .field_val_named => FieldNamed, | 461 | .field_ptr_named, .field_val_named => FieldNamed, |
| 470 | .@"asm" => Asm, | 462 | .@"asm" => Asm, |
| ... | @@ -479,7 +471,6 @@ pub const Inst = struct { | ... | @@ -479,7 +471,6 @@ pub const Inst = struct { |
| 479 | .enum_literal => EnumLiteral, | 471 | .enum_literal => EnumLiteral, |
| 480 | .error_set => ErrorSet, | 472 | .error_set => ErrorSet, |
| 481 | .slice => Slice, | 473 | .slice => Slice, |
| 482 | .switchbr => SwitchBr, | ||
| 483 | .typeof_peer => TypeOfPeer, | 474 | .typeof_peer => TypeOfPeer, |
| 484 | .container_field_named => ContainerFieldNamed, | 475 | .container_field_named => ContainerFieldNamed, |
| 485 | .container_field_typed => ContainerFieldTyped, | 476 | .container_field_typed => ContainerFieldTyped, |
| ... | @@ -508,18 +499,18 @@ pub const Inst = struct { | ... | @@ -508,18 +499,18 @@ pub const Inst = struct { |
| 508 | .arg, | 499 | .arg, |
| 509 | .as, | 500 | .as, |
| 510 | .@"asm", | 501 | .@"asm", |
| 511 | .bitand, | 502 | .bit_and, |
| 512 | .bitcast, | 503 | .bitcast, |
| 513 | .bitcast_ref, | 504 | .bitcast_ref, |
| 514 | .bitcast_result_ptr, | 505 | .bitcast_result_ptr, |
| 515 | .bitor, | 506 | .bit_or, |
| 516 | .block, | 507 | .block, |
| 517 | .block_flat, | 508 | .block_flat, |
| 518 | .block_comptime, | 509 | .block_comptime, |
| 519 | .block_comptime_flat, | 510 | .block_comptime_flat, |
| 520 | .boolnot, | 511 | .bool_not, |
| 521 | .booland, | 512 | .bool_and, |
| 522 | .boolor, | 513 | .bool_or, |
| 523 | .breakpoint, | 514 | .breakpoint, |
| 524 | .call, | 515 | .call, |
| 525 | .cmp_lt, | 516 | .cmp_lt, |
| ... | @@ -529,13 +520,11 @@ pub const Inst = struct { | ... | @@ -529,13 +520,11 @@ pub const Inst = struct { |
| 529 | .cmp_gt, | 520 | .cmp_gt, |
| 530 | .cmp_neq, | 521 | .cmp_neq, |
| 531 | .coerce_result_ptr, | 522 | .coerce_result_ptr, |
| 532 | .coerce_result_block_ptr, | ||
| 533 | .coerce_to_ptr_elem, | ||
| 534 | .@"const", | 523 | .@"const", |
| 535 | .dbg_stmt, | 524 | .dbg_stmt, |
| 536 | .declref, | 525 | .decl_ref, |
| 537 | .declref_str, | 526 | .decl_ref_str, |
| 538 | .declval, | 527 | .decl_val, |
| 539 | .deref, | 528 | .deref, |
| 540 | .div, | 529 | .div, |
| 541 | .elem_ptr, | 530 | .elem_ptr, |
| ... | @@ -552,7 +541,7 @@ pub const Inst = struct { | ... | @@ -552,7 +541,7 @@ pub const Inst = struct { |
| 552 | .fntype, | 541 | .fntype, |
| 553 | .int, | 542 | .int, |
| 554 | .intcast, | 543 | .intcast, |
| 555 | .inttype, | 544 | .int_type, |
| 556 | .is_non_null, | 545 | .is_non_null, |
| 557 | .is_null, | 546 | .is_null, |
| 558 | .is_non_null_ptr, | 547 | .is_non_null_ptr, |
| ... | @@ -579,6 +568,7 @@ pub const Inst = struct { | ... | @@ -579,6 +568,7 @@ pub const Inst = struct { |
| 579 | .mut_slice_type, | 568 | .mut_slice_type, |
| 580 | .const_slice_type, | 569 | .const_slice_type, |
| 581 | .store, | 570 | .store, |
| 571 | .store_to_block_ptr, | ||
| 582 | .store_to_inferred_ptr, | 572 | .store_to_inferred_ptr, |
| 583 | .str, | 573 | .str, |
| 584 | .sub, | 574 | .sub, |
| ... | @@ -602,31 +592,30 @@ pub const Inst = struct { | ... | @@ -602,31 +592,30 @@ pub const Inst = struct { |
| 602 | .merge_error_sets, | 592 | .merge_error_sets, |
| 603 | .anyframe_type, | 593 | .anyframe_type, |
| 604 | .error_union_type, | 594 | .error_union_type, |
| 605 | .bitnot, | 595 | .bit_not, |
| 606 | .error_set, | 596 | .error_set, |
| 607 | .slice, | 597 | .slice, |
| 608 | .slice_start, | 598 | .slice_start, |
| 609 | .import, | 599 | .import, |
| 610 | .switch_range, | ||
| 611 | .typeof_peer, | 600 | .typeof_peer, |
| 612 | .resolve_inferred_alloc, | 601 | .resolve_inferred_alloc, |
| 613 | .set_eval_branch_quota, | 602 | .set_eval_branch_quota, |
| 614 | .compilelog, | 603 | .compile_log, |
| 615 | .enum_type, | 604 | .enum_type, |
| 616 | .union_type, | 605 | .union_type, |
| 617 | .struct_type, | 606 | .struct_type, |
| 607 | .void_value, | ||
| 618 | => false, | 608 | => false, |
| 619 | 609 | ||
| 620 | .@"break", | 610 | .@"break", |
| 621 | .breakvoid, | 611 | .break_void, |
| 622 | .condbr, | 612 | .condbr, |
| 623 | .compileerror, | 613 | .compile_error, |
| 624 | .@"return", | 614 | .@"return", |
| 625 | .returnvoid, | 615 | .return_void, |
| 626 | .unreach_nocheck, | 616 | .unreachable_unsafe, |
| 627 | .@"unreachable", | 617 | .unreachable_safe, |
| 628 | .loop, | 618 | .loop, |
| 629 | .switchbr, | ||
| 630 | .container_field_named, | 619 | .container_field_named, |
| 631 | .container_field_typed, | 620 | .container_field_typed, |
| 632 | .container_field, | 621 | .container_field, |
| ... | @@ -717,7 +706,7 @@ pub const Inst = struct { | ... | @@ -717,7 +706,7 @@ pub const Inst = struct { |
| 717 | }; | 706 | }; |
| 718 | 707 | ||
| 719 | pub const BreakVoid = struct { | 708 | pub const BreakVoid = struct { |
| 720 | pub const base_tag = Tag.breakvoid; | 709 | pub const base_tag = Tag.break_void; |
| 721 | base: Inst, | 710 | base: Inst, |
| 722 | 711 | ||
| 723 | positionals: struct { | 712 | positionals: struct { |
| ... | @@ -739,19 +728,8 @@ pub const Inst = struct { | ... | @@ -739,19 +728,8 @@ pub const Inst = struct { |
| 739 | }, | 728 | }, |
| 740 | }; | 729 | }; |
| 741 | 730 | ||
| 742 | pub const CoerceToPtrElem = struct { | ||
| 743 | pub const base_tag = Tag.coerce_to_ptr_elem; | ||
| 744 | base: Inst, | ||
| 745 | |||
| 746 | positionals: struct { | ||
| 747 | ptr: *Inst, | ||
| 748 | value: *Inst, | ||
| 749 | }, | ||
| 750 | kw_args: struct {}, | ||
| 751 | }; | ||
| 752 | |||
| 753 | pub const DeclRef = struct { | 731 | pub const DeclRef = struct { |
| 754 | pub const base_tag = Tag.declref; | 732 | pub const base_tag = Tag.decl_ref; |
| 755 | base: Inst, | 733 | base: Inst, |
| 756 | 734 | ||
| 757 | positionals: struct { | 735 | positionals: struct { |
| ... | @@ -761,7 +739,7 @@ pub const Inst = struct { | ... | @@ -761,7 +739,7 @@ pub const Inst = struct { |
| 761 | }; | 739 | }; |
| 762 | 740 | ||
| 763 | pub const DeclRefStr = struct { | 741 | pub const DeclRefStr = struct { |
| 764 | pub const base_tag = Tag.declref_str; | 742 | pub const base_tag = Tag.decl_ref_str; |
| 765 | base: Inst, | 743 | base: Inst, |
| 766 | 744 | ||
| 767 | positionals: struct { | 745 | positionals: struct { |
| ... | @@ -771,7 +749,7 @@ pub const Inst = struct { | ... | @@ -771,7 +749,7 @@ pub const Inst = struct { |
| 771 | }; | 749 | }; |
| 772 | 750 | ||
| 773 | pub const DeclVal = struct { | 751 | pub const DeclVal = struct { |
| 774 | pub const base_tag = Tag.declval; | 752 | pub const base_tag = Tag.decl_val; |
| 775 | base: Inst, | 753 | base: Inst, |
| 776 | 754 | ||
| 777 | positionals: struct { | 755 | positionals: struct { |
| ... | @@ -780,19 +758,8 @@ pub const Inst = struct { | ... | @@ -780,19 +758,8 @@ pub const Inst = struct { |
| 780 | kw_args: struct {}, | 758 | kw_args: struct {}, |
| 781 | }; | 759 | }; |
| 782 | 760 | ||
| 783 | pub const CoerceResultBlockPtr = struct { | ||
| 784 | pub const base_tag = Tag.coerce_result_block_ptr; | ||
| 785 | base: Inst, | ||
| 786 | |||
| 787 | positionals: struct { | ||
| 788 | dest_type: *Inst, | ||
| 789 | block: *Block, | ||
| 790 | }, | ||
| 791 | kw_args: struct {}, | ||
| 792 | }; | ||
| 793 | |||
| 794 | pub const CompileLog = struct { | 761 | pub const CompileLog = struct { |
| 795 | pub const base_tag = Tag.compilelog; | 762 | pub const base_tag = Tag.compile_log; |
| 796 | base: Inst, | 763 | base: Inst, |
| 797 | 764 | ||
| 798 | positionals: struct { | 765 | positionals: struct { |
| ... | @@ -905,7 +872,7 @@ pub const Inst = struct { | ... | @@ -905,7 +872,7 @@ pub const Inst = struct { |
| 905 | }; | 872 | }; |
| 906 | 873 | ||
| 907 | pub const IntType = struct { | 874 | pub const IntType = struct { |
| 908 | pub const base_tag = Tag.inttype; | 875 | pub const base_tag = Tag.int_type; |
| 909 | base: Inst, | 876 | base: Inst, |
| 910 | 877 | ||
| 911 | positionals: struct { | 878 | positionals: struct { |
| ... | @@ -1114,32 +1081,6 @@ pub const Inst = struct { | ... | @@ -1114,32 +1081,6 @@ pub const Inst = struct { |
| 1114 | }, | 1081 | }, |
| 1115 | }; | 1082 | }; |
| 1116 | 1083 | ||
| 1117 | pub const SwitchBr = struct { | ||
| 1118 | pub const base_tag = Tag.switchbr; | ||
| 1119 | base: Inst, | ||
| 1120 | |||
| 1121 | positionals: struct { | ||
| 1122 | target_ptr: *Inst, | ||
| 1123 | /// List of all individual items and ranges | ||
| 1124 | items: []*Inst, | ||
| 1125 | cases: []Case, | ||
| 1126 | else_body: Body, | ||
| 1127 | }, | ||
| 1128 | kw_args: struct { | ||
| 1129 | /// Pointer to first range if such exists. | ||
| 1130 | range: ?*Inst = null, | ||
| 1131 | special_prong: enum { | ||
| 1132 | none, | ||
| 1133 | @"else", | ||
| 1134 | underscore, | ||
| 1135 | } = .none, | ||
| 1136 | }, | ||
| 1137 | |||
| 1138 | pub const Case = struct { | ||
| 1139 | item: *Inst, | ||
| 1140 | body: Body, | ||
| 1141 | }; | ||
| 1142 | }; | ||
| 1143 | pub const TypeOfPeer = struct { | 1084 | pub const TypeOfPeer = struct { |
| 1144 | pub const base_tag = .typeof_peer; | 1085 | pub const base_tag = .typeof_peer; |
| 1145 | base: Inst, | 1086 | base: Inst, |
| ... | @@ -1473,7 +1414,7 @@ const Writer = struct { | ... | @@ -1473,7 +1414,7 @@ const Writer = struct { |
| 1473 | TypedValue => return stream.print("TypedValue{{ .ty = {}, .val = {}}}", .{ param.ty, param.val }), | 1414 | TypedValue => return stream.print("TypedValue{{ .ty = {}, .val = {}}}", .{ param.ty, param.val }), |
| 1474 | *IrModule.Decl => return stream.print("Decl({s})", .{param.name}), | 1415 | *IrModule.Decl => return stream.print("Decl({s})", .{param.name}), |
| 1475 | *Inst.Block => { | 1416 | *Inst.Block => { |
| 1476 | const name = self.block_table.get(param).?; | 1417 | const name = self.block_table.get(param) orelse "!BADREF!"; |
| 1477 | return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)}); | 1418 | return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)}); |
| 1478 | }, | 1419 | }, |
| 1479 | *Inst.Loop => { | 1420 | *Inst.Loop => { |
| ... | @@ -1490,26 +1431,6 @@ const Writer = struct { | ... | @@ -1490,26 +1431,6 @@ const Writer = struct { |
| 1490 | } | 1431 | } |
| 1491 | try stream.writeByte(']'); | 1432 | try stream.writeByte(']'); |
| 1492 | }, | 1433 | }, |
| 1493 | []Inst.SwitchBr.Case => { | ||
| 1494 | if (param.len == 0) { | ||
| 1495 | return stream.writeAll("{}"); | ||
| 1496 | } | ||
| 1497 | try stream.writeAll("{\n"); | ||
| 1498 | for (param) |*case, i| { | ||
| 1499 | if (i != 0) { | ||
| 1500 | try stream.writeAll(",\n"); | ||
| 1501 | } | ||
| 1502 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1503 | self.indent += 2; | ||
| 1504 | try self.writeParamToStream(stream, &case.item); | ||
| 1505 | try stream.writeAll(" => "); | ||
| 1506 | try self.writeParamToStream(stream, &case.body); | ||
| 1507 | self.indent -= 2; | ||
| 1508 | } | ||
| 1509 | try stream.writeByte('\n'); | ||
| 1510 | try stream.writeByteNTimes(' ', self.indent - 2); | ||
| 1511 | try stream.writeByte('}'); | ||
| 1512 | }, | ||
| 1513 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), | 1434 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), |
| 1514 | } | 1435 | } |
| 1515 | } | 1436 | } |
| ... | @@ -1641,10 +1562,10 @@ const DumpTzir = struct { | ... | @@ -1641,10 +1562,10 @@ const DumpTzir = struct { |
| 1641 | .cmp_gt, | 1562 | .cmp_gt, |
| 1642 | .cmp_neq, | 1563 | .cmp_neq, |
| 1643 | .store, | 1564 | .store, |
| 1644 | .booland, | 1565 | .bool_and, |
| 1645 | .boolor, | 1566 | .bool_or, |
| 1646 | .bitand, | 1567 | .bit_and, |
| 1647 | .bitor, | 1568 | .bit_or, |
| 1648 | .xor, | 1569 | .xor, |
| 1649 | => { | 1570 | => { |
| 1650 | const bin_op = inst.cast(ir.Inst.BinOp).?; | 1571 | const bin_op = inst.cast(ir.Inst.BinOp).?; |
| ... | @@ -1660,9 +1581,15 @@ const DumpTzir = struct { | ... | @@ -1660,9 +1581,15 @@ const DumpTzir = struct { |
| 1660 | try dtz.findConst(br.operand); | 1581 | try dtz.findConst(br.operand); |
| 1661 | }, | 1582 | }, |
| 1662 | 1583 | ||
| 1663 | .brvoid => { | 1584 | .br_block_flat => { |
| 1664 | const brvoid = inst.castTag(.brvoid).?; | 1585 | const br_block_flat = inst.castTag(.br_block_flat).?; |
| 1665 | try dtz.findConst(&brvoid.block.base); | 1586 | try dtz.findConst(&br_block_flat.block.base); |
| 1587 | try dtz.fetchInstsAndResolveConsts(br_block_flat.body); | ||
| 1588 | }, | ||
| 1589 | |||
| 1590 | .br_void => { | ||
| 1591 | const br_void = inst.castTag(.br_void).?; | ||
| 1592 | try dtz.findConst(&br_void.block.base); | ||
| 1666 | }, | 1593 | }, |
| 1667 | 1594 | ||
| 1668 | .block => { | 1595 | .block => { |
| ... | @@ -1753,10 +1680,10 @@ const DumpTzir = struct { | ... | @@ -1753,10 +1680,10 @@ const DumpTzir = struct { |
| 1753 | .cmp_gt, | 1680 | .cmp_gt, |
| 1754 | .cmp_neq, | 1681 | .cmp_neq, |
| 1755 | .store, | 1682 | .store, |
| 1756 | .booland, | 1683 | .bool_and, |
| 1757 | .boolor, | 1684 | .bool_or, |
| 1758 | .bitand, | 1685 | .bit_and, |
| 1759 | .bitor, | 1686 | .bit_or, |
| 1760 | .xor, | 1687 | .xor, |
| 1761 | => { | 1688 | => { |
| 1762 | const bin_op = inst.cast(ir.Inst.BinOp).?; | 1689 | const bin_op = inst.cast(ir.Inst.BinOp).?; |
| ... | @@ -1805,9 +1732,27 @@ const DumpTzir = struct { | ... | @@ -1805,9 +1732,27 @@ const DumpTzir = struct { |
| 1805 | } | 1732 | } |
| 1806 | }, | 1733 | }, |
| 1807 | 1734 | ||
| 1808 | .brvoid => { | 1735 | .br_block_flat => { |
| 1809 | const brvoid = inst.castTag(.brvoid).?; | 1736 | const br_block_flat = inst.castTag(.br_block_flat).?; |
| 1810 | const kinky = try dtz.writeInst(writer, &brvoid.block.base); | 1737 | const block_kinky = try dtz.writeInst(writer, &br_block_flat.block.base); |
| 1738 | if (block_kinky != null) { | ||
| 1739 | try writer.writeAll(", { // Instruction does not dominate all uses!\n"); | ||
| 1740 | } else { | ||
| 1741 | try writer.writeAll(", {\n"); | ||
| 1742 | } | ||
| 1743 | |||
| 1744 | const old_indent = dtz.indent; | ||
| 1745 | dtz.indent += 2; | ||
| 1746 | try dtz.dumpBody(br_block_flat.body, writer); | ||
| 1747 | dtz.indent = old_indent; | ||
| 1748 | |||
| 1749 | try writer.writeByteNTimes(' ', dtz.indent); | ||
| 1750 | try writer.writeAll("})\n"); | ||
| 1751 | }, | ||
| 1752 | |||
| 1753 | .br_void => { | ||
| 1754 | const br_void = inst.castTag(.br_void).?; | ||
| 1755 | const kinky = try dtz.writeInst(writer, &br_void.block.base); | ||
| 1811 | if (kinky) |_| { | 1756 | if (kinky) |_| { |
| 1812 | try writer.writeAll(") // Instruction does not dominate all uses!\n"); | 1757 | try writer.writeAll(") // Instruction does not dominate all uses!\n"); |
| 1813 | } else { | 1758 | } else { |
| ... | @@ -1818,7 +1763,7 @@ const DumpTzir = struct { | ... | @@ -1818,7 +1763,7 @@ const DumpTzir = struct { |
| 1818 | .block => { | 1763 | .block => { |
| 1819 | const block = inst.castTag(.block).?; | 1764 | const block = inst.castTag(.block).?; |
| 1820 | 1765 | ||
| 1821 | try writer.writeAll("\n"); | 1766 | try writer.writeAll("{\n"); |
| 1822 | 1767 | ||
| 1823 | const old_indent = dtz.indent; | 1768 | const old_indent = dtz.indent; |
| 1824 | dtz.indent += 2; | 1769 | dtz.indent += 2; |
| ... | @@ -1826,7 +1771,7 @@ const DumpTzir = struct { | ... | @@ -1826,7 +1771,7 @@ const DumpTzir = struct { |
| 1826 | dtz.indent = old_indent; | 1771 | dtz.indent = old_indent; |
| 1827 | 1772 | ||
| 1828 | try writer.writeByteNTimes(' ', dtz.indent); | 1773 | try writer.writeByteNTimes(' ', dtz.indent); |
| 1829 | try writer.writeAll(")\n"); | 1774 | try writer.writeAll("})\n"); |
| 1830 | }, | 1775 | }, |
| 1831 | 1776 | ||
| 1832 | .condbr => { | 1777 | .condbr => { |
| ... | @@ -1856,7 +1801,7 @@ const DumpTzir = struct { | ... | @@ -1856,7 +1801,7 @@ const DumpTzir = struct { |
| 1856 | .loop => { | 1801 | .loop => { |
| 1857 | const loop = inst.castTag(.loop).?; | 1802 | const loop = inst.castTag(.loop).?; |
| 1858 | 1803 | ||
| 1859 | try writer.writeAll("\n"); | 1804 | try writer.writeAll("{\n"); |
| 1860 | 1805 | ||
| 1861 | const old_indent = dtz.indent; | 1806 | const old_indent = dtz.indent; |
| 1862 | dtz.indent += 2; | 1807 | dtz.indent += 2; |
| ... | @@ -1864,7 +1809,7 @@ const DumpTzir = struct { | ... | @@ -1864,7 +1809,7 @@ const DumpTzir = struct { |
| 1864 | dtz.indent = old_indent; | 1809 | dtz.indent = old_indent; |
| 1865 | 1810 | ||
| 1866 | try writer.writeByteNTimes(' ', dtz.indent); | 1811 | try writer.writeByteNTimes(' ', dtz.indent); |
| 1867 | try writer.writeAll(")\n"); | 1812 | try writer.writeAll("})\n"); |
| 1868 | }, | 1813 | }, |
| 1869 | 1814 | ||
| 1870 | .call => { | 1815 | .call => { |
src/zir_sema.zig+357-538| ... | @@ -28,144 +28,132 @@ const Decl = Module.Decl; | ... | @@ -28,144 +28,132 @@ const Decl = Module.Decl; |
| 28 | 28 | ||
| 29 | pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst { | 29 | pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst { |
| 30 | switch (old_inst.tag) { | 30 | switch (old_inst.tag) { |
| 31 | .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?), | 31 | .alloc => return zirAlloc(mod, scope, old_inst.castTag(.alloc).?), |
| 32 | .alloc_mut => return analyzeInstAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?), | 32 | .alloc_mut => return zirAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?), |
| 33 | .alloc_inferred => return analyzeInstAllocInferred( | 33 | .alloc_inferred => return zirAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?, .inferred_alloc_const), |
| 34 | mod, | 34 | .alloc_inferred_mut => return zirAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred_mut).?, .inferred_alloc_mut), |
| 35 | scope, | 35 | .arg => return zirArg(mod, scope, old_inst.castTag(.arg).?), |
| 36 | old_inst.castTag(.alloc_inferred).?, | 36 | .bitcast_ref => return zirBitcastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), |
| 37 | .inferred_alloc_const, | 37 | .bitcast_result_ptr => return zirBitcastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| 38 | ), | 38 | .block => return zirBlock(mod, scope, old_inst.castTag(.block).?, false), |
| 39 | .alloc_inferred_mut => return analyzeInstAllocInferred( | 39 | .block_comptime => return zirBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), |
| 40 | mod, | 40 | .block_flat => return zirBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), |
| 41 | scope, | 41 | .block_comptime_flat => return zirBlockFlat(mod, scope, old_inst.castTag(.block_comptime_flat).?, true), |
| 42 | old_inst.castTag(.alloc_inferred_mut).?, | 42 | .@"break" => return zirBreak(mod, scope, old_inst.castTag(.@"break").?), |
| 43 | .inferred_alloc_mut, | 43 | .breakpoint => return zirBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), |
| 44 | ), | 44 | .break_void => return zirBreakVoid(mod, scope, old_inst.castTag(.break_void).?), |
| 45 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), | 45 | .call => return zirCall(mod, scope, old_inst.castTag(.call).?), |
| 46 | .bitcast_ref => return bitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), | 46 | .coerce_result_ptr => return zirCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?), |
| 47 | .bitcast_result_ptr => return bitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), | 47 | .compile_error => return zirCompileError(mod, scope, old_inst.castTag(.compile_error).?), |
| 48 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), | 48 | .compile_log => return zirCompileLog(mod, scope, old_inst.castTag(.compile_log).?), |
| 49 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), | 49 | .@"const" => return zirConst(mod, scope, old_inst.castTag(.@"const").?), |
| 50 | .block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), | 50 | .dbg_stmt => return zirDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?), |
| 51 | .block_comptime_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_comptime_flat).?, true), | 51 | .decl_ref => return zirDeclRef(mod, scope, old_inst.castTag(.decl_ref).?), |
| 52 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), | 52 | .decl_ref_str => return zirDeclRefStr(mod, scope, old_inst.castTag(.decl_ref_str).?), |
| 53 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), | 53 | .decl_val => return zirDeclVal(mod, scope, old_inst.castTag(.decl_val).?), |
| 54 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), | 54 | .ensure_result_used => return zirEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?), |
| 55 | .call => return call(mod, scope, old_inst.castTag(.call).?), | 55 | .ensure_result_non_error => return zirEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?), |
| 56 | .coerce_result_block_ptr => return analyzeInstCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?), | 56 | .indexable_ptr_len => return zirIndexablePtrLen(mod, scope, old_inst.castTag(.indexable_ptr_len).?), |
| 57 | .coerce_result_ptr => return analyzeInstCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?), | 57 | .ref => return zirRef(mod, scope, old_inst.castTag(.ref).?), |
| 58 | .coerce_to_ptr_elem => return analyzeInstCoerceToPtrElem(mod, scope, old_inst.castTag(.coerce_to_ptr_elem).?), | 58 | .resolve_inferred_alloc => return zirResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?), |
| 59 | .compileerror => return analyzeInstCompileError(mod, scope, old_inst.castTag(.compileerror).?), | 59 | .ret_ptr => return zirRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), |
| 60 | .compilelog => return analyzeInstCompileLog(mod, scope, old_inst.castTag(.compilelog).?), | 60 | .ret_type => return zirRetType(mod, scope, old_inst.castTag(.ret_type).?), |
| 61 | .@"const" => return analyzeInstConst(mod, scope, old_inst.castTag(.@"const").?), | 61 | .store_to_block_ptr => return zirStoreToBlockPtr(mod, scope, old_inst.castTag(.store_to_block_ptr).?), |
| 62 | .dbg_stmt => return analyzeInstDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?), | 62 | .store_to_inferred_ptr => return zirStoreToInferredPtr(mod, scope, old_inst.castTag(.store_to_inferred_ptr).?), |
| 63 | .declref => return declRef(mod, scope, old_inst.castTag(.declref).?), | 63 | .single_const_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), |
| 64 | .declref_str => return analyzeInstDeclRefStr(mod, scope, old_inst.castTag(.declref_str).?), | 64 | .single_mut_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), |
| 65 | .declval => return declVal(mod, scope, old_inst.castTag(.declval).?), | 65 | .many_const_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), |
| 66 | .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?), | 66 | .many_mut_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), |
| 67 | .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?), | 67 | .c_const_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), |
| 68 | .indexable_ptr_len => return indexablePtrLen(mod, scope, old_inst.castTag(.indexable_ptr_len).?), | 68 | .c_mut_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), |
| 69 | .ref => return ref(mod, scope, old_inst.castTag(.ref).?), | 69 | .const_slice_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice), |
| 70 | .resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?), | 70 | .mut_slice_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), |
| 71 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), | 71 | .ptr_type => return zirPtrType(mod, scope, old_inst.castTag(.ptr_type).?), |
| 72 | .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), | 72 | .store => return zirStore(mod, scope, old_inst.castTag(.store).?), |
| 73 | .store_to_inferred_ptr => return analyzeInstStoreToInferredPtr(mod, scope, old_inst.castTag(.store_to_inferred_ptr).?), | 73 | .set_eval_branch_quota => return zirSetEvalBranchQuota(mod, scope, old_inst.castTag(.set_eval_branch_quota).?), |
| 74 | .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), | 74 | .str => return zirStr(mod, scope, old_inst.castTag(.str).?), |
| 75 | .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), | 75 | .int => return zirInt(mod, scope, old_inst.castTag(.int).?), |
| 76 | .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), | 76 | .int_type => return zirIntType(mod, scope, old_inst.castTag(.int_type).?), |
| 77 | .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), | 77 | .loop => return zirLoop(mod, scope, old_inst.castTag(.loop).?), |
| 78 | .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), | 78 | .param_type => return zirParamType(mod, scope, old_inst.castTag(.param_type).?), |
| 79 | .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), | 79 | .ptrtoint => return zirPtrtoint(mod, scope, old_inst.castTag(.ptrtoint).?), |
| 80 | .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice), | 80 | .field_ptr => return zirFieldPtr(mod, scope, old_inst.castTag(.field_ptr).?), |
| 81 | .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), | 81 | .field_val => return zirFieldVal(mod, scope, old_inst.castTag(.field_val).?), |
| 82 | .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), | 82 | .field_ptr_named => return zirFieldPtrNamed(mod, scope, old_inst.castTag(.field_ptr_named).?), |
| 83 | .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), | 83 | .field_val_named => return zirFieldValNamed(mod, scope, old_inst.castTag(.field_val_named).?), |
| 84 | .set_eval_branch_quota => return analyzeInstSetEvalBranchQuota(mod, scope, old_inst.castTag(.set_eval_branch_quota).?), | 84 | .deref => return zirDeref(mod, scope, old_inst.castTag(.deref).?), |
| 85 | .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), | 85 | .as => return zirAs(mod, scope, old_inst.castTag(.as).?), |
| 86 | .int => return analyzeInstInt(mod, scope, old_inst.castTag(.int).?), | 86 | .@"asm" => return zirAsm(mod, scope, old_inst.castTag(.@"asm").?), |
| 87 | .inttype => return analyzeInstIntType(mod, scope, old_inst.castTag(.inttype).?), | 87 | .unreachable_safe => return zirUnreachable(mod, scope, old_inst.castTag(.unreachable_safe).?, true), |
| 88 | .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?), | 88 | .unreachable_unsafe => return zirUnreachable(mod, scope, old_inst.castTag(.unreachable_unsafe).?, false), |
| 89 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), | 89 | .@"return" => return zirReturn(mod, scope, old_inst.castTag(.@"return").?), |
| 90 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), | 90 | .return_void => return zirReturnVoid(mod, scope, old_inst.castTag(.return_void).?), |
| 91 | .field_ptr => return fieldPtr(mod, scope, old_inst.castTag(.field_ptr).?), | 91 | .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?), |
| 92 | .field_val => return fieldVal(mod, scope, old_inst.castTag(.field_val).?), | 92 | .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?), |
| 93 | .field_ptr_named => return fieldPtrNamed(mod, scope, old_inst.castTag(.field_ptr_named).?), | 93 | .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?), |
| 94 | .field_val_named => return fieldValNamed(mod, scope, old_inst.castTag(.field_val_named).?), | 94 | .fntype => return zirFnType(mod, scope, old_inst.castTag(.fntype).?), |
| 95 | .deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?), | 95 | .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?), |
| 96 | .as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?), | 96 | .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?), |
| 97 | .@"asm" => return analyzeInstAsm(mod, scope, old_inst.castTag(.@"asm").?), | 97 | .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?), |
| 98 | .@"unreachable" => return analyzeInstUnreachable(mod, scope, old_inst.castTag(.@"unreachable").?, true), | 98 | .elem_ptr => return zirElemPtr(mod, scope, old_inst.castTag(.elem_ptr).?), |
| 99 | .unreach_nocheck => return analyzeInstUnreachable(mod, scope, old_inst.castTag(.unreach_nocheck).?, false), | 99 | .elem_val => return zirElemVal(mod, scope, old_inst.castTag(.elem_val).?), |
| 100 | .@"return" => return analyzeInstRet(mod, scope, old_inst.castTag(.@"return").?), | 100 | .add => return zirArithmetic(mod, scope, old_inst.castTag(.add).?), |
| 101 | .returnvoid => return analyzeInstRetVoid(mod, scope, old_inst.castTag(.returnvoid).?), | 101 | .addwrap => return zirArithmetic(mod, scope, old_inst.castTag(.addwrap).?), |
| 102 | .@"fn" => return analyzeInstFn(mod, scope, old_inst.castTag(.@"fn").?), | 102 | .sub => return zirArithmetic(mod, scope, old_inst.castTag(.sub).?), |
| 103 | .@"export" => return analyzeInstExport(mod, scope, old_inst.castTag(.@"export").?), | 103 | .subwrap => return zirArithmetic(mod, scope, old_inst.castTag(.subwrap).?), |
| 104 | .primitive => return analyzeInstPrimitive(mod, scope, old_inst.castTag(.primitive).?), | 104 | .mul => return zirArithmetic(mod, scope, old_inst.castTag(.mul).?), |
| 105 | .fntype => return analyzeInstFnType(mod, scope, old_inst.castTag(.fntype).?), | 105 | .mulwrap => return zirArithmetic(mod, scope, old_inst.castTag(.mulwrap).?), |
| 106 | .intcast => return analyzeInstIntCast(mod, scope, old_inst.castTag(.intcast).?), | 106 | .div => return zirArithmetic(mod, scope, old_inst.castTag(.div).?), |
| 107 | .bitcast => return analyzeInstBitCast(mod, scope, old_inst.castTag(.bitcast).?), | 107 | .mod_rem => return zirArithmetic(mod, scope, old_inst.castTag(.mod_rem).?), |
| 108 | .floatcast => return analyzeInstFloatCast(mod, scope, old_inst.castTag(.floatcast).?), | 108 | .array_cat => return zirArrayCat(mod, scope, old_inst.castTag(.array_cat).?), |
| 109 | .elem_ptr => return elemPtr(mod, scope, old_inst.castTag(.elem_ptr).?), | 109 | .array_mul => return zirArrayMul(mod, scope, old_inst.castTag(.array_mul).?), |
| 110 | .elem_val => return elemVal(mod, scope, old_inst.castTag(.elem_val).?), | 110 | .bit_and => return zirBitwise(mod, scope, old_inst.castTag(.bit_and).?), |
| 111 | .add => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.add).?), | 111 | .bit_not => return zirBitNot(mod, scope, old_inst.castTag(.bit_not).?), |
| 112 | .addwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.addwrap).?), | 112 | .bit_or => return zirBitwise(mod, scope, old_inst.castTag(.bit_or).?), |
| 113 | .sub => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.sub).?), | 113 | .xor => return zirBitwise(mod, scope, old_inst.castTag(.xor).?), |
| 114 | .subwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.subwrap).?), | 114 | .shl => return zirShl(mod, scope, old_inst.castTag(.shl).?), |
| 115 | .mul => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.mul).?), | 115 | .shr => return zirShr(mod, scope, old_inst.castTag(.shr).?), |
| 116 | .mulwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.mulwrap).?), | 116 | .cmp_lt => return zirCmp(mod, scope, old_inst.castTag(.cmp_lt).?, .lt), |
| 117 | .div => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.div).?), | 117 | .cmp_lte => return zirCmp(mod, scope, old_inst.castTag(.cmp_lte).?, .lte), |
| 118 | .mod_rem => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.mod_rem).?), | 118 | .cmp_eq => return zirCmp(mod, scope, old_inst.castTag(.cmp_eq).?, .eq), |
| 119 | .array_cat => return analyzeInstArrayCat(mod, scope, old_inst.castTag(.array_cat).?), | 119 | .cmp_gte => return zirCmp(mod, scope, old_inst.castTag(.cmp_gte).?, .gte), |
| 120 | .array_mul => return analyzeInstArrayMul(mod, scope, old_inst.castTag(.array_mul).?), | 120 | .cmp_gt => return zirCmp(mod, scope, old_inst.castTag(.cmp_gt).?, .gt), |
| 121 | .bitand => return analyzeInstBitwise(mod, scope, old_inst.castTag(.bitand).?), | 121 | .cmp_neq => return zirCmp(mod, scope, old_inst.castTag(.cmp_neq).?, .neq), |
| 122 | .bitnot => return analyzeInstBitNot(mod, scope, old_inst.castTag(.bitnot).?), | 122 | .condbr => return zirCondbr(mod, scope, old_inst.castTag(.condbr).?), |
| 123 | .bitor => return analyzeInstBitwise(mod, scope, old_inst.castTag(.bitor).?), | 123 | .is_null => return zirIsNull(mod, scope, old_inst.castTag(.is_null).?, false), |
| 124 | .xor => return analyzeInstBitwise(mod, scope, old_inst.castTag(.xor).?), | 124 | .is_non_null => return zirIsNull(mod, scope, old_inst.castTag(.is_non_null).?, true), |
| 125 | .shl => return analyzeInstShl(mod, scope, old_inst.castTag(.shl).?), | 125 | .is_null_ptr => return zirIsNullPtr(mod, scope, old_inst.castTag(.is_null_ptr).?, false), |
| 126 | .shr => return analyzeInstShr(mod, scope, old_inst.castTag(.shr).?), | 126 | .is_non_null_ptr => return zirIsNullPtr(mod, scope, old_inst.castTag(.is_non_null_ptr).?, true), |
| 127 | .cmp_lt => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_lt).?, .lt), | 127 | .is_err => return zirIsErr(mod, scope, old_inst.castTag(.is_err).?), |
| 128 | .cmp_lte => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_lte).?, .lte), | 128 | .is_err_ptr => return zirIsErrPtr(mod, scope, old_inst.castTag(.is_err_ptr).?), |
| 129 | .cmp_eq => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_eq).?, .eq), | 129 | .bool_not => return zirBoolNot(mod, scope, old_inst.castTag(.bool_not).?), |
| 130 | .cmp_gte => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_gte).?, .gte), | 130 | .typeof => return zirTypeof(mod, scope, old_inst.castTag(.typeof).?), |
| 131 | .cmp_gt => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_gt).?, .gt), | 131 | .typeof_peer => return zirTypeofPeer(mod, scope, old_inst.castTag(.typeof_peer).?), |
| 132 | .cmp_neq => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_neq).?, .neq), | 132 | .optional_type => return zirOptionalType(mod, scope, old_inst.castTag(.optional_type).?), |
| 133 | .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?), | 133 | .optional_payload_safe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true), |
| 134 | .is_null => return isNull(mod, scope, old_inst.castTag(.is_null).?, false), | 134 | .optional_payload_unsafe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false), |
| 135 | .is_non_null => return isNull(mod, scope, old_inst.castTag(.is_non_null).?, true), | 135 | .optional_payload_safe_ptr => return zirOptionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_safe_ptr).?, true), |
| 136 | .is_null_ptr => return isNullPtr(mod, scope, old_inst.castTag(.is_null_ptr).?, false), | 136 | .optional_payload_unsafe_ptr => return zirOptionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_unsafe_ptr).?, false), |
| 137 | .is_non_null_ptr => return isNullPtr(mod, scope, old_inst.castTag(.is_non_null_ptr).?, true), | 137 | .err_union_payload_safe => return zirErrUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_safe).?, true), |
| 138 | .is_err => return isErr(mod, scope, old_inst.castTag(.is_err).?), | 138 | .err_union_payload_unsafe => return zirErrUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_unsafe).?, false), |
| 139 | .is_err_ptr => return isErrPtr(mod, scope, old_inst.castTag(.is_err_ptr).?), | 139 | .err_union_payload_safe_ptr => return zirErrUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_safe_ptr).?, true), |
| 140 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), | 140 | .err_union_payload_unsafe_ptr => return zirErrUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_unsafe_ptr).?, false), |
| 141 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), | 141 | .err_union_code => return zirErrUnionCode(mod, scope, old_inst.castTag(.err_union_code).?), |
| 142 | .typeof_peer => return analyzeInstTypeOfPeer(mod, scope, old_inst.castTag(.typeof_peer).?), | 142 | .err_union_code_ptr => return zirErrUnionCodePtr(mod, scope, old_inst.castTag(.err_union_code_ptr).?), |
| 143 | .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?), | 143 | .ensure_err_payload_void => return zirEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), |
| 144 | .optional_payload_safe => return optionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true), | 144 | .array_type => return zirArrayType(mod, scope, old_inst.castTag(.array_type).?), |
| 145 | .optional_payload_unsafe => return optionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false), | 145 | .array_type_sentinel => return zirArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), |
| 146 | .optional_payload_safe_ptr => return optionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_safe_ptr).?, true), | 146 | .enum_literal => return zirEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?), |
| 147 | .optional_payload_unsafe_ptr => return optionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_unsafe_ptr).?, false), | 147 | .merge_error_sets => return zirMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?), |
| 148 | .err_union_payload_safe => return errorUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_safe).?, true), | 148 | .error_union_type => return zirErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?), |
| 149 | .err_union_payload_unsafe => return errorUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_unsafe).?, false), | 149 | .anyframe_type => return zirAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?), |
| 150 | .err_union_payload_safe_ptr => return errorUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_safe_ptr).?, true), | 150 | .error_set => return zirErrorSet(mod, scope, old_inst.castTag(.error_set).?), |
| 151 | .err_union_payload_unsafe_ptr => return errorUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_unsafe_ptr).?, false), | 151 | .slice => return zirSlice(mod, scope, old_inst.castTag(.slice).?), |
| 152 | .err_union_code => return errorUnionCode(mod, scope, old_inst.castTag(.err_union_code).?), | 152 | .slice_start => return zirSliceStart(mod, scope, old_inst.castTag(.slice_start).?), |
| 153 | .err_union_code_ptr => return errorUnionCodePtr(mod, scope, old_inst.castTag(.err_union_code_ptr).?), | 153 | .import => return zirImport(mod, scope, old_inst.castTag(.import).?), |
| 154 | .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), | 154 | .bool_and => return zirBoolOp(mod, scope, old_inst.castTag(.bool_and).?), |
| 155 | .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), | 155 | .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?), |
| 156 | .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), | 156 | .void_value => return mod.constVoid(scope, old_inst.src), |
| 157 | .enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?), | ||
| 158 | .merge_error_sets => return analyzeInstMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?), | ||
| 159 | .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?), | ||
| 160 | .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?), | ||
| 161 | .error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?), | ||
| 162 | .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?), | ||
| 163 | .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?), | ||
| 164 | .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?), | ||
| 165 | .switchbr => return analyzeInstSwitchBr(mod, scope, old_inst.castTag(.switchbr).?), | ||
| 166 | .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), | ||
| 167 | .booland => return analyzeInstBoolOp(mod, scope, old_inst.castTag(.booland).?), | ||
| 168 | .boolor => return analyzeInstBoolOp(mod, scope, old_inst.castTag(.boolor).?), | ||
| 169 | 157 | ||
| 170 | .container_field_named, | 158 | .container_field_named, |
| 171 | .container_field_typed, | 159 | .container_field_typed, |
| ... | @@ -258,7 +246,7 @@ pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerE | ... | @@ -258,7 +246,7 @@ pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerE |
| 258 | }; | 246 | }; |
| 259 | } | 247 | } |
| 260 | 248 | ||
| 261 | fn analyzeInstConst(mod: *Module, scope: *Scope, const_inst: *zir.Inst.Const) InnerError!*Inst { | 249 | fn zirConst(mod: *Module, scope: *Scope, const_inst: *zir.Inst.Const) InnerError!*Inst { |
| 262 | const tracy = trace(@src()); | 250 | const tracy = trace(@src()); |
| 263 | defer tracy.end(); | 251 | defer tracy.end(); |
| 264 | // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions | 252 | // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions |
| ... | @@ -275,44 +263,25 @@ fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError | ... | @@ -275,44 +263,25 @@ fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError |
| 275 | }; | 263 | }; |
| 276 | } | 264 | } |
| 277 | 265 | ||
| 278 | fn analyzeInstCoerceResultBlockPtr( | 266 | fn zirBitcastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 279 | mod: *Module, | ||
| 280 | scope: *Scope, | ||
| 281 | inst: *zir.Inst.CoerceResultBlockPtr, | ||
| 282 | ) InnerError!*Inst { | ||
| 283 | const tracy = trace(@src()); | ||
| 284 | defer tracy.end(); | ||
| 285 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{}); | ||
| 286 | } | ||
| 287 | |||
| 288 | fn bitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 289 | const tracy = trace(@src()); | 267 | const tracy = trace(@src()); |
| 290 | defer tracy.end(); | 268 | defer tracy.end(); |
| 291 | return mod.fail(scope, inst.base.src, "TODO implement zir_sema.bitCastRef", .{}); | 269 | return mod.fail(scope, inst.base.src, "TODO implement zir_sema.zirBitcastRef", .{}); |
| 292 | } | 270 | } |
| 293 | 271 | ||
| 294 | fn bitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 272 | fn zirBitcastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 295 | const tracy = trace(@src()); | 273 | const tracy = trace(@src()); |
| 296 | defer tracy.end(); | 274 | defer tracy.end(); |
| 297 | return mod.fail(scope, inst.base.src, "TODO implement zir_sema.bitCastResultPtr", .{}); | 275 | return mod.fail(scope, inst.base.src, "TODO implement zir_sema.zirBitcastResultPtr", .{}); |
| 298 | } | 276 | } |
| 299 | 277 | ||
| 300 | fn analyzeInstCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 278 | fn zirCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 301 | const tracy = trace(@src()); | 279 | const tracy = trace(@src()); |
| 302 | defer tracy.end(); | 280 | defer tracy.end(); |
| 303 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultPtr", .{}); | 281 | return mod.fail(scope, inst.base.src, "TODO implement zirCoerceResultPtr", .{}); |
| 304 | } | 282 | } |
| 305 | 283 | ||
| 306 | /// Equivalent to `as(ptr_child_type(typeof(ptr)), value)`. | 284 | fn zirRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| 307 | fn analyzeInstCoerceToPtrElem(mod: *Module, scope: *Scope, inst: *zir.Inst.CoerceToPtrElem) InnerError!*Inst { | ||
| 308 | const tracy = trace(@src()); | ||
| 309 | defer tracy.end(); | ||
| 310 | const ptr = try resolveInst(mod, scope, inst.positionals.ptr); | ||
| 311 | const operand = try resolveInst(mod, scope, inst.positionals.value); | ||
| 312 | return mod.coerce(scope, ptr.ty.elemType(), operand); | ||
| 313 | } | ||
| 314 | |||
| 315 | fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | ||
| 316 | const tracy = trace(@src()); | 285 | const tracy = trace(@src()); |
| 317 | defer tracy.end(); | 286 | defer tracy.end(); |
| 318 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | 287 | const b = try mod.requireFunctionBlock(scope, inst.base.src); |
| ... | @@ -322,7 +291,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr | ... | @@ -322,7 +291,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr |
| 322 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); | 291 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 323 | } | 292 | } |
| 324 | 293 | ||
| 325 | fn ref(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 294 | fn zirRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 326 | const tracy = trace(@src()); | 295 | const tracy = trace(@src()); |
| 327 | defer tracy.end(); | 296 | defer tracy.end(); |
| 328 | 297 | ||
| ... | @@ -330,7 +299,7 @@ fn ref(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ... | @@ -330,7 +299,7 @@ fn ref(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 330 | return mod.analyzeRef(scope, inst.base.src, operand); | 299 | return mod.analyzeRef(scope, inst.base.src, operand); |
| 331 | } | 300 | } |
| 332 | 301 | ||
| 333 | fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 302 | fn zirRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| 334 | const tracy = trace(@src()); | 303 | const tracy = trace(@src()); |
| 335 | defer tracy.end(); | 304 | defer tracy.end(); |
| 336 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | 305 | const b = try mod.requireFunctionBlock(scope, inst.base.src); |
| ... | @@ -339,7 +308,7 @@ fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr | ... | @@ -339,7 +308,7 @@ fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr |
| 339 | return mod.constType(scope, inst.base.src, ret_type); | 308 | return mod.constType(scope, inst.base.src, ret_type); |
| 340 | } | 309 | } |
| 341 | 310 | ||
| 342 | fn analyzeInstEnsureResultUsed(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 311 | fn zirEnsureResultUsed(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 343 | const tracy = trace(@src()); | 312 | const tracy = trace(@src()); |
| 344 | defer tracy.end(); | 313 | defer tracy.end(); |
| 345 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 314 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| ... | @@ -349,7 +318,7 @@ fn analyzeInstEnsureResultUsed(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp | ... | @@ -349,7 +318,7 @@ fn analyzeInstEnsureResultUsed(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp |
| 349 | } | 318 | } |
| 350 | } | 319 | } |
| 351 | 320 | ||
| 352 | fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 321 | fn zirEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 353 | const tracy = trace(@src()); | 322 | const tracy = trace(@src()); |
| 354 | defer tracy.end(); | 323 | defer tracy.end(); |
| 355 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 324 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| ... | @@ -359,7 +328,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. | ... | @@ -359,7 +328,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. |
| 359 | } | 328 | } |
| 360 | } | 329 | } |
| 361 | 330 | ||
| 362 | fn indexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 331 | fn zirIndexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 363 | const tracy = trace(@src()); | 332 | const tracy = trace(@src()); |
| 364 | defer tracy.end(); | 333 | defer tracy.end(); |
| 365 | 334 | ||
| ... | @@ -389,7 +358,7 @@ fn indexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError | ... | @@ -389,7 +358,7 @@ fn indexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError |
| 389 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | 358 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); |
| 390 | } | 359 | } |
| 391 | 360 | ||
| 392 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 361 | fn zirAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 393 | const tracy = trace(@src()); | 362 | const tracy = trace(@src()); |
| 394 | defer tracy.end(); | 363 | defer tracy.end(); |
| 395 | const var_type = try resolveType(mod, scope, inst.positionals.operand); | 364 | const var_type = try resolveType(mod, scope, inst.positionals.operand); |
| ... | @@ -398,7 +367,7 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro | ... | @@ -398,7 +367,7 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro |
| 398 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); | 367 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 399 | } | 368 | } |
| 400 | 369 | ||
| 401 | fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 370 | fn zirAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 402 | const tracy = trace(@src()); | 371 | const tracy = trace(@src()); |
| 403 | defer tracy.end(); | 372 | defer tracy.end(); |
| 404 | const var_type = try resolveType(mod, scope, inst.positionals.operand); | 373 | const var_type = try resolveType(mod, scope, inst.positionals.operand); |
| ... | @@ -408,7 +377,7 @@ fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerE | ... | @@ -408,7 +377,7 @@ fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerE |
| 408 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); | 377 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 409 | } | 378 | } |
| 410 | 379 | ||
| 411 | fn analyzeInstAllocInferred( | 380 | fn zirAllocInferred( |
| 412 | mod: *Module, | 381 | mod: *Module, |
| 413 | scope: *Scope, | 382 | scope: *Scope, |
| 414 | inst: *zir.Inst.NoOp, | 383 | inst: *zir.Inst.NoOp, |
| ... | @@ -437,7 +406,7 @@ fn analyzeInstAllocInferred( | ... | @@ -437,7 +406,7 @@ fn analyzeInstAllocInferred( |
| 437 | return result; | 406 | return result; |
| 438 | } | 407 | } |
| 439 | 408 | ||
| 440 | fn analyzeInstResolveInferredAlloc( | 409 | fn zirResolveInferredAlloc( |
| 441 | mod: *Module, | 410 | mod: *Module, |
| 442 | scope: *Scope, | 411 | scope: *Scope, |
| 443 | inst: *zir.Inst.UnOp, | 412 | inst: *zir.Inst.UnOp, |
| ... | @@ -466,28 +435,46 @@ fn analyzeInstResolveInferredAlloc( | ... | @@ -466,28 +435,46 @@ fn analyzeInstResolveInferredAlloc( |
| 466 | return mod.constVoid(scope, inst.base.src); | 435 | return mod.constVoid(scope, inst.base.src); |
| 467 | } | 436 | } |
| 468 | 437 | ||
| 469 | fn analyzeInstStoreToInferredPtr( | 438 | fn zirStoreToBlockPtr( |
| 470 | mod: *Module, | 439 | mod: *Module, |
| 471 | scope: *Scope, | 440 | scope: *Scope, |
| 472 | inst: *zir.Inst.BinOp, | 441 | inst: *zir.Inst.BinOp, |
| 473 | ) InnerError!*Inst { | 442 | ) InnerError!*Inst { |
| 474 | const tracy = trace(@src()); | 443 | const tracy = trace(@src()); |
| 475 | defer tracy.end(); | 444 | defer tracy.end(); |
| 445 | |||
| 446 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); | ||
| 447 | const value = try resolveInst(mod, scope, inst.positionals.rhs); | ||
| 448 | const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One); | ||
| 449 | // TODO detect when this store should be done at compile-time. For example, | ||
| 450 | // if expressions should force it when the condition is compile-time known. | ||
| 451 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | ||
| 452 | const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr); | ||
| 453 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); | ||
| 454 | } | ||
| 455 | |||
| 456 | fn zirStoreToInferredPtr( | ||
| 457 | mod: *Module, | ||
| 458 | scope: *Scope, | ||
| 459 | inst: *zir.Inst.BinOp, | ||
| 460 | ) InnerError!*Inst { | ||
| 461 | const tracy = trace(@src()); | ||
| 462 | defer tracy.end(); | ||
| 463 | |||
| 476 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); | 464 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); |
| 477 | const value = try resolveInst(mod, scope, inst.positionals.rhs); | 465 | const value = try resolveInst(mod, scope, inst.positionals.rhs); |
| 478 | const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?; | 466 | const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?; |
| 479 | // Add the stored instruction to the set we will use to resolve peer types | 467 | // Add the stored instruction to the set we will use to resolve peer types |
| 480 | // for the inferred allocation. | 468 | // for the inferred allocation. |
| 481 | try inferred_alloc.data.stored_inst_list.append(scope.arena(), value); | 469 | try inferred_alloc.data.stored_inst_list.append(scope.arena(), value); |
| 482 | // Create a new alloc with exactly the type the pointer wants. | 470 | // Create a runtime bitcast instruction with exactly the type the pointer wants. |
| 483 | // Later it gets cleaned up by aliasing the alloc we are supposed to be storing to. | ||
| 484 | const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One); | 471 | const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One); |
| 485 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | 472 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 486 | const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr); | 473 | const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr); |
| 487 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); | 474 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); |
| 488 | } | 475 | } |
| 489 | 476 | ||
| 490 | fn analyzeInstSetEvalBranchQuota( | 477 | fn zirSetEvalBranchQuota( |
| 491 | mod: *Module, | 478 | mod: *Module, |
| 492 | scope: *Scope, | 479 | scope: *Scope, |
| 493 | inst: *zir.Inst.UnOp, | 480 | inst: *zir.Inst.UnOp, |
| ... | @@ -499,15 +486,16 @@ fn analyzeInstSetEvalBranchQuota( | ... | @@ -499,15 +486,16 @@ fn analyzeInstSetEvalBranchQuota( |
| 499 | return mod.constVoid(scope, inst.base.src); | 486 | return mod.constVoid(scope, inst.base.src); |
| 500 | } | 487 | } |
| 501 | 488 | ||
| 502 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 489 | fn zirStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 503 | const tracy = trace(@src()); | 490 | const tracy = trace(@src()); |
| 504 | defer tracy.end(); | 491 | defer tracy.end(); |
| 492 | |||
| 505 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); | 493 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); |
| 506 | const value = try resolveInst(mod, scope, inst.positionals.rhs); | 494 | const value = try resolveInst(mod, scope, inst.positionals.rhs); |
| 507 | return mod.storePtr(scope, inst.base.src, ptr, value); | 495 | return mod.storePtr(scope, inst.base.src, ptr, value); |
| 508 | } | 496 | } |
| 509 | 497 | ||
| 510 | fn analyzeInstParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerError!*Inst { | 498 | fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerError!*Inst { |
| 511 | const tracy = trace(@src()); | 499 | const tracy = trace(@src()); |
| 512 | defer tracy.end(); | 500 | defer tracy.end(); |
| 513 | const fn_inst = try resolveInst(mod, scope, inst.positionals.func); | 501 | const fn_inst = try resolveInst(mod, scope, inst.positionals.func); |
| ... | @@ -516,7 +504,7 @@ fn analyzeInstParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) | ... | @@ -516,7 +504,7 @@ fn analyzeInstParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) |
| 516 | const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) { | 504 | const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) { |
| 517 | .Fn => fn_inst.ty, | 505 | .Fn => fn_inst.ty, |
| 518 | .BoundFn => { | 506 | .BoundFn => { |
| 519 | return mod.fail(scope, fn_inst.src, "TODO implement analyzeInstParamType for method call syntax", .{}); | 507 | return mod.fail(scope, fn_inst.src, "TODO implement zirParamType for method call syntax", .{}); |
| 520 | }, | 508 | }, |
| 521 | else => { | 509 | else => { |
| 522 | return mod.fail(scope, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty}); | 510 | return mod.fail(scope, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty}); |
| ... | @@ -538,7 +526,7 @@ fn analyzeInstParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) | ... | @@ -538,7 +526,7 @@ fn analyzeInstParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) |
| 538 | return mod.constType(scope, inst.base.src, param_type); | 526 | return mod.constType(scope, inst.base.src, param_type); |
| 539 | } | 527 | } |
| 540 | 528 | ||
| 541 | fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst { | 529 | fn zirStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst { |
| 542 | const tracy = trace(@src()); | 530 | const tracy = trace(@src()); |
| 543 | defer tracy.end(); | 531 | defer tracy.end(); |
| 544 | // The bytes references memory inside the ZIR module, which can get deallocated | 532 | // The bytes references memory inside the ZIR module, which can get deallocated |
| ... | @@ -557,14 +545,14 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr | ... | @@ -557,14 +545,14 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr |
| 557 | return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl); | 545 | return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl); |
| 558 | } | 546 | } |
| 559 | 547 | ||
| 560 | fn analyzeInstInt(mod: *Module, scope: *Scope, inst: *zir.Inst.Int) InnerError!*Inst { | 548 | fn zirInt(mod: *Module, scope: *Scope, inst: *zir.Inst.Int) InnerError!*Inst { |
| 561 | const tracy = trace(@src()); | 549 | const tracy = trace(@src()); |
| 562 | defer tracy.end(); | 550 | defer tracy.end(); |
| 563 | 551 | ||
| 564 | return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int); | 552 | return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int); |
| 565 | } | 553 | } |
| 566 | 554 | ||
| 567 | fn analyzeInstExport(mod: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst { | 555 | fn zirExport(mod: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst { |
| 568 | const tracy = trace(@src()); | 556 | const tracy = trace(@src()); |
| 569 | defer tracy.end(); | 557 | defer tracy.end(); |
| 570 | const symbol_name = try resolveConstString(mod, scope, export_inst.positionals.symbol_name); | 558 | const symbol_name = try resolveConstString(mod, scope, export_inst.positionals.symbol_name); |
| ... | @@ -574,14 +562,14 @@ fn analyzeInstExport(mod: *Module, scope: *Scope, export_inst: *zir.Inst.Export) | ... | @@ -574,14 +562,14 @@ fn analyzeInstExport(mod: *Module, scope: *Scope, export_inst: *zir.Inst.Export) |
| 574 | return mod.constVoid(scope, export_inst.base.src); | 562 | return mod.constVoid(scope, export_inst.base.src); |
| 575 | } | 563 | } |
| 576 | 564 | ||
| 577 | fn analyzeInstCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 565 | fn zirCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 578 | const tracy = trace(@src()); | 566 | const tracy = trace(@src()); |
| 579 | defer tracy.end(); | 567 | defer tracy.end(); |
| 580 | const msg = try resolveConstString(mod, scope, inst.positionals.operand); | 568 | const msg = try resolveConstString(mod, scope, inst.positionals.operand); |
| 581 | return mod.fail(scope, inst.base.src, "{s}", .{msg}); | 569 | return mod.fail(scope, inst.base.src, "{s}", .{msg}); |
| 582 | } | 570 | } |
| 583 | 571 | ||
| 584 | fn analyzeInstCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerError!*Inst { | 572 | fn zirCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerError!*Inst { |
| 585 | var managed = mod.compile_log_text.toManaged(mod.gpa); | 573 | var managed = mod.compile_log_text.toManaged(mod.gpa); |
| 586 | defer mod.compile_log_text = managed.moveToUnmanaged(); | 574 | defer mod.compile_log_text = managed.moveToUnmanaged(); |
| 587 | const writer = managed.writer(); | 575 | const writer = managed.writer(); |
| ... | @@ -608,7 +596,7 @@ fn analyzeInstCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog | ... | @@ -608,7 +596,7 @@ fn analyzeInstCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog |
| 608 | return mod.constVoid(scope, inst.base.src); | 596 | return mod.constVoid(scope, inst.base.src); |
| 609 | } | 597 | } |
| 610 | 598 | ||
| 611 | fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst { | 599 | fn zirArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst { |
| 612 | const tracy = trace(@src()); | 600 | const tracy = trace(@src()); |
| 613 | defer tracy.end(); | 601 | defer tracy.end(); |
| 614 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | 602 | const b = try mod.requireFunctionBlock(scope, inst.base.src); |
| ... | @@ -631,7 +619,7 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!* | ... | @@ -631,7 +619,7 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!* |
| 631 | return mod.addArg(b, inst.base.src, param_type, name); | 619 | return mod.addArg(b, inst.base.src, param_type, name); |
| 632 | } | 620 | } |
| 633 | 621 | ||
| 634 | fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst { | 622 | fn zirLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst { |
| 635 | const tracy = trace(@src()); | 623 | const tracy = trace(@src()); |
| 636 | defer tracy.end(); | 624 | defer tracy.end(); |
| 637 | const parent_block = scope.cast(Scope.Block).?; | 625 | const parent_block = scope.cast(Scope.Block).?; |
| ... | @@ -672,25 +660,14 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError | ... | @@ -672,25 +660,14 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 672 | return &loop_inst.base; | 660 | return &loop_inst.base; |
| 673 | } | 661 | } |
| 674 | 662 | ||
| 675 | fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | 663 | fn zirBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { |
| 676 | const tracy = trace(@src()); | 664 | const tracy = trace(@src()); |
| 677 | defer tracy.end(); | 665 | defer tracy.end(); |
| 678 | const parent_block = scope.cast(Scope.Block).?; | 666 | const parent_block = scope.cast(Scope.Block).?; |
| 679 | 667 | ||
| 680 | var child_block: Scope.Block = .{ | 668 | var child_block = parent_block.makeSubBlock(); |
| 681 | .parent = parent_block, | ||
| 682 | .inst_table = parent_block.inst_table, | ||
| 683 | .func = parent_block.func, | ||
| 684 | .owner_decl = parent_block.owner_decl, | ||
| 685 | .src_decl = parent_block.src_decl, | ||
| 686 | .instructions = .{}, | ||
| 687 | .arena = parent_block.arena, | ||
| 688 | .label = null, | ||
| 689 | .inlining = parent_block.inlining, | ||
| 690 | .is_comptime = parent_block.is_comptime or is_comptime, | ||
| 691 | .branch_quota = parent_block.branch_quota, | ||
| 692 | }; | ||
| 693 | defer child_block.instructions.deinit(mod.gpa); | 669 | defer child_block.instructions.deinit(mod.gpa); |
| 670 | child_block.is_comptime = child_block.is_comptime or is_comptime; | ||
| 694 | 671 | ||
| 695 | try analyzeBody(mod, &child_block, inst.positionals.body); | 672 | try analyzeBody(mod, &child_block, inst.positionals.body); |
| 696 | 673 | ||
| ... | @@ -704,9 +681,15 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c | ... | @@ -704,9 +681,15 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c |
| 704 | return resolveInst(mod, scope, last_zir_inst); | 681 | return resolveInst(mod, scope, last_zir_inst); |
| 705 | } | 682 | } |
| 706 | 683 | ||
| 707 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | 684 | fn zirBlock( |
| 685 | mod: *Module, | ||
| 686 | scope: *Scope, | ||
| 687 | inst: *zir.Inst.Block, | ||
| 688 | is_comptime: bool, | ||
| 689 | ) InnerError!*Inst { | ||
| 708 | const tracy = trace(@src()); | 690 | const tracy = trace(@src()); |
| 709 | defer tracy.end(); | 691 | defer tracy.end(); |
| 692 | |||
| 710 | const parent_block = scope.cast(Scope.Block).?; | 693 | const parent_block = scope.cast(Scope.Block).?; |
| 711 | 694 | ||
| 712 | // Reserve space for a Block instruction so that generated Break instructions can | 695 | // Reserve space for a Block instruction so that generated Break instructions can |
| ... | @@ -735,6 +718,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt | ... | @@ -735,6 +718,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt |
| 735 | .zir_block = inst, | 718 | .zir_block = inst, |
| 736 | .merges = .{ | 719 | .merges = .{ |
| 737 | .results = .{}, | 720 | .results = .{}, |
| 721 | .br_list = .{}, | ||
| 738 | .block_inst = block_inst, | 722 | .block_inst = block_inst, |
| 739 | }, | 723 | }, |
| 740 | }), | 724 | }), |
| ... | @@ -746,6 +730,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt | ... | @@ -746,6 +730,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt |
| 746 | 730 | ||
| 747 | defer child_block.instructions.deinit(mod.gpa); | 731 | defer child_block.instructions.deinit(mod.gpa); |
| 748 | defer merges.results.deinit(mod.gpa); | 732 | defer merges.results.deinit(mod.gpa); |
| 733 | defer merges.br_list.deinit(mod.gpa); | ||
| 749 | 734 | ||
| 750 | try analyzeBody(mod, &child_block, inst.positionals.body); | 735 | try analyzeBody(mod, &child_block, inst.positionals.body); |
| 751 | 736 | ||
| ... | @@ -779,49 +764,127 @@ fn analyzeBlockBody( | ... | @@ -779,49 +764,127 @@ fn analyzeBlockBody( |
| 779 | const last_inst = child_block.instructions.items[last_inst_index]; | 764 | const last_inst = child_block.instructions.items[last_inst_index]; |
| 780 | if (last_inst.breakBlock()) |br_block| { | 765 | if (last_inst.breakBlock()) |br_block| { |
| 781 | if (br_block == merges.block_inst) { | 766 | if (br_block == merges.block_inst) { |
| 782 | // No need for a block instruction. We can put the new instructions directly into the parent block. | 767 | // No need for a block instruction. We can put the new instructions directly |
| 783 | // Here we omit the break instruction. | 768 | // into the parent block. Here we omit the break instruction. |
| 784 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]); | 769 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]); |
| 785 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | 770 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); |
| 786 | return merges.results.items[0]; | 771 | return merges.results.items[0]; |
| 787 | } | 772 | } |
| 788 | } | 773 | } |
| 789 | } | 774 | } |
| 790 | // It should be impossible to have the number of results be > 1 in a comptime scope. | 775 | // It is impossible to have the number of results be > 1 in a comptime scope. |
| 791 | assert(!child_block.is_comptime); // We should have already got a compile error in the condbr condition. | 776 | assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition. |
| 792 | 777 | ||
| 793 | // Need to set the type and emit the Block instruction. This allows machine code generation | 778 | // Need to set the type and emit the Block instruction. This allows machine code generation |
| 794 | // to emit a jump instruction to after the block when it encounters the break. | 779 | // to emit a jump instruction to after the block when it encounters the break. |
| 795 | try parent_block.instructions.append(mod.gpa, &merges.block_inst.base); | 780 | try parent_block.instructions.append(mod.gpa, &merges.block_inst.base); |
| 796 | merges.block_inst.base.ty = try mod.resolvePeerTypes(scope, merges.results.items); | 781 | const resolved_ty = try mod.resolvePeerTypes(scope, merges.results.items); |
| 797 | merges.block_inst.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) }; | 782 | merges.block_inst.base.ty = resolved_ty; |
| 783 | merges.block_inst.body = .{ | ||
| 784 | .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items), | ||
| 785 | }; | ||
| 786 | // Now that the block has its type resolved, we need to go back into all the break | ||
| 787 | // instructions, and insert type coercion on the operands. | ||
| 788 | for (merges.br_list.items) |br| { | ||
| 789 | if (br.operand.ty.eql(resolved_ty)) { | ||
| 790 | // No type coercion needed. | ||
| 791 | continue; | ||
| 792 | } | ||
| 793 | var coerce_block = parent_block.makeSubBlock(); | ||
| 794 | defer coerce_block.instructions.deinit(mod.gpa); | ||
| 795 | const coerced_operand = try mod.coerce(&coerce_block.base, resolved_ty, br.operand); | ||
| 796 | // If no instructions were produced, such as in the case of a coercion of a | ||
| 797 | // constant value to a new type, we can simply point the br operand to it. | ||
| 798 | if (coerce_block.instructions.items.len == 0) { | ||
| 799 | br.operand = coerced_operand; | ||
| 800 | continue; | ||
| 801 | } | ||
| 802 | assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == coerced_operand); | ||
| 803 | // Here we depend on the br instruction having been over-allocated (if necessary) | ||
| 804 | // inide analyzeBreak so that it can be converted into a br_block_flat instruction. | ||
| 805 | const br_src = br.base.src; | ||
| 806 | const br_ty = br.base.ty; | ||
| 807 | const br_block_flat = @ptrCast(*Inst.BrBlockFlat, br); | ||
| 808 | br_block_flat.* = .{ | ||
| 809 | .base = .{ | ||
| 810 | .src = br_src, | ||
| 811 | .ty = br_ty, | ||
| 812 | .tag = .br_block_flat, | ||
| 813 | }, | ||
| 814 | .block = merges.block_inst, | ||
| 815 | .body = .{ | ||
| 816 | .instructions = try parent_block.arena.dupe(*Inst, coerce_block.instructions.items), | ||
| 817 | }, | ||
| 818 | }; | ||
| 819 | } | ||
| 798 | return &merges.block_inst.base; | 820 | return &merges.block_inst.base; |
| 799 | } | 821 | } |
| 800 | 822 | ||
| 801 | fn analyzeInstBreakpoint(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 823 | fn zirBreakpoint(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| 802 | const tracy = trace(@src()); | 824 | const tracy = trace(@src()); |
| 803 | defer tracy.end(); | 825 | defer tracy.end(); |
| 804 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | 826 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 805 | return mod.addNoOp(b, inst.base.src, Type.initTag(.void), .breakpoint); | 827 | return mod.addNoOp(b, inst.base.src, Type.initTag(.void), .breakpoint); |
| 806 | } | 828 | } |
| 807 | 829 | ||
| 808 | fn analyzeInstBreak(mod: *Module, scope: *Scope, inst: *zir.Inst.Break) InnerError!*Inst { | 830 | fn zirBreak(mod: *Module, scope: *Scope, inst: *zir.Inst.Break) InnerError!*Inst { |
| 809 | const tracy = trace(@src()); | 831 | const tracy = trace(@src()); |
| 810 | defer tracy.end(); | 832 | defer tracy.end(); |
| 833 | |||
| 811 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 834 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 812 | const block = inst.positionals.block; | 835 | const block = inst.positionals.block; |
| 813 | return analyzeBreak(mod, scope, inst.base.src, block, operand); | 836 | return analyzeBreak(mod, scope, inst.base.src, block, operand); |
| 814 | } | 837 | } |
| 815 | 838 | ||
| 816 | fn analyzeInstBreakVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst { | 839 | fn zirBreakVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst { |
| 817 | const tracy = trace(@src()); | 840 | const tracy = trace(@src()); |
| 818 | defer tracy.end(); | 841 | defer tracy.end(); |
| 842 | |||
| 819 | const block = inst.positionals.block; | 843 | const block = inst.positionals.block; |
| 820 | const void_inst = try mod.constVoid(scope, inst.base.src); | 844 | const void_inst = try mod.constVoid(scope, inst.base.src); |
| 821 | return analyzeBreak(mod, scope, inst.base.src, block, void_inst); | 845 | return analyzeBreak(mod, scope, inst.base.src, block, void_inst); |
| 822 | } | 846 | } |
| 823 | 847 | ||
| 824 | fn analyzeInstDbgStmt(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 848 | fn analyzeBreak( |
| 849 | mod: *Module, | ||
| 850 | scope: *Scope, | ||
| 851 | src: usize, | ||
| 852 | zir_block: *zir.Inst.Block, | ||
| 853 | operand: *Inst, | ||
| 854 | ) InnerError!*Inst { | ||
| 855 | var opt_block = scope.cast(Scope.Block); | ||
| 856 | while (opt_block) |block| { | ||
| 857 | if (block.label) |*label| { | ||
| 858 | if (label.zir_block == zir_block) { | ||
| 859 | const b = try mod.requireFunctionBlock(scope, src); | ||
| 860 | // Here we add a br instruction, but we over-allocate a little bit | ||
| 861 | // (if necessary) to make it possible to convert the instruction into | ||
| 862 | // a br_block_flat instruction later. | ||
| 863 | const br = @ptrCast(*Inst.Br, try b.arena.alignedAlloc( | ||
| 864 | u8, | ||
| 865 | Inst.convertable_br_align, | ||
| 866 | Inst.convertable_br_size, | ||
| 867 | )); | ||
| 868 | br.* = .{ | ||
| 869 | .base = .{ | ||
| 870 | .tag = .br, | ||
| 871 | .ty = Type.initTag(.noreturn), | ||
| 872 | .src = src, | ||
| 873 | }, | ||
| 874 | .operand = operand, | ||
| 875 | .block = label.merges.block_inst, | ||
| 876 | }; | ||
| 877 | try b.instructions.append(mod.gpa, &br.base); | ||
| 878 | try label.merges.results.append(mod.gpa, operand); | ||
| 879 | try label.merges.br_list.append(mod.gpa, br); | ||
| 880 | return &br.base; | ||
| 881 | } | ||
| 882 | } | ||
| 883 | opt_block = block.parent; | ||
| 884 | } else unreachable; | ||
| 885 | } | ||
| 886 | |||
| 887 | fn zirDbgStmt(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | ||
| 825 | const tracy = trace(@src()); | 888 | const tracy = trace(@src()); |
| 826 | defer tracy.end(); | 889 | defer tracy.end(); |
| 827 | if (scope.cast(Scope.Block)) |b| { | 890 | if (scope.cast(Scope.Block)) |b| { |
| ... | @@ -832,26 +895,26 @@ fn analyzeInstDbgStmt(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr | ... | @@ -832,26 +895,26 @@ fn analyzeInstDbgStmt(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr |
| 832 | return mod.constVoid(scope, inst.base.src); | 895 | return mod.constVoid(scope, inst.base.src); |
| 833 | } | 896 | } |
| 834 | 897 | ||
| 835 | fn analyzeInstDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst { | 898 | fn zirDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst { |
| 836 | const tracy = trace(@src()); | 899 | const tracy = trace(@src()); |
| 837 | defer tracy.end(); | 900 | defer tracy.end(); |
| 838 | const decl_name = try resolveConstString(mod, scope, inst.positionals.name); | 901 | const decl_name = try resolveConstString(mod, scope, inst.positionals.name); |
| 839 | return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name); | 902 | return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name); |
| 840 | } | 903 | } |
| 841 | 904 | ||
| 842 | fn declRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst { | 905 | fn zirDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst { |
| 843 | const tracy = trace(@src()); | 906 | const tracy = trace(@src()); |
| 844 | defer tracy.end(); | 907 | defer tracy.end(); |
| 845 | return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl); | 908 | return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl); |
| 846 | } | 909 | } |
| 847 | 910 | ||
| 848 | fn declVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst { | 911 | fn zirDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst { |
| 849 | const tracy = trace(@src()); | 912 | const tracy = trace(@src()); |
| 850 | defer tracy.end(); | 913 | defer tracy.end(); |
| 851 | return mod.analyzeDeclVal(scope, inst.base.src, inst.positionals.decl); | 914 | return mod.analyzeDeclVal(scope, inst.base.src, inst.positionals.decl); |
| 852 | } | 915 | } |
| 853 | 916 | ||
| 854 | fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | 917 | fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 855 | const tracy = trace(@src()); | 918 | const tracy = trace(@src()); |
| 856 | defer tracy.end(); | 919 | defer tracy.end(); |
| 857 | 920 | ||
| ... | @@ -965,6 +1028,7 @@ fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | ... | @@ -965,6 +1028,7 @@ fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 965 | .casted_args = casted_args, | 1028 | .casted_args = casted_args, |
| 966 | .merges = .{ | 1029 | .merges = .{ |
| 967 | .results = .{}, | 1030 | .results = .{}, |
| 1031 | .br_list = .{}, | ||
| 968 | .block_inst = block_inst, | 1032 | .block_inst = block_inst, |
| 969 | }, | 1033 | }, |
| 970 | }; | 1034 | }; |
| ... | @@ -989,6 +1053,7 @@ fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | ... | @@ -989,6 +1053,7 @@ fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 989 | 1053 | ||
| 990 | defer child_block.instructions.deinit(mod.gpa); | 1054 | defer child_block.instructions.deinit(mod.gpa); |
| 991 | defer merges.results.deinit(mod.gpa); | 1055 | defer merges.results.deinit(mod.gpa); |
| 1056 | defer merges.br_list.deinit(mod.gpa); | ||
| 992 | 1057 | ||
| 993 | try mod.emitBackwardBranch(&child_block, inst.base.src); | 1058 | try mod.emitBackwardBranch(&child_block, inst.base.src); |
| 994 | 1059 | ||
| ... | @@ -1002,7 +1067,7 @@ fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { | ... | @@ -1002,7 +1067,7 @@ fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 1002 | return mod.addCall(b, inst.base.src, ret_type, func, casted_args); | 1067 | return mod.addCall(b, inst.base.src, ret_type, func, casted_args); |
| 1003 | } | 1068 | } |
| 1004 | 1069 | ||
| 1005 | fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { | 1070 | fn zirFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { |
| 1006 | const tracy = trace(@src()); | 1071 | const tracy = trace(@src()); |
| 1007 | defer tracy.end(); | 1072 | defer tracy.end(); |
| 1008 | const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type); | 1073 | const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type); |
| ... | @@ -1019,13 +1084,13 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! | ... | @@ -1019,13 +1084,13 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! |
| 1019 | }); | 1084 | }); |
| 1020 | } | 1085 | } |
| 1021 | 1086 | ||
| 1022 | fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) InnerError!*Inst { | 1087 | fn zirIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) InnerError!*Inst { |
| 1023 | const tracy = trace(@src()); | 1088 | const tracy = trace(@src()); |
| 1024 | defer tracy.end(); | 1089 | defer tracy.end(); |
| 1025 | return mod.fail(scope, inttype.base.src, "TODO implement inttype", .{}); | 1090 | return mod.fail(scope, inttype.base.src, "TODO implement inttype", .{}); |
| 1026 | } | 1091 | } |
| 1027 | 1092 | ||
| 1028 | fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst { | 1093 | fn zirOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst { |
| 1029 | const tracy = trace(@src()); | 1094 | const tracy = trace(@src()); |
| 1030 | defer tracy.end(); | 1095 | defer tracy.end(); |
| 1031 | const child_type = try resolveType(mod, scope, optional.positionals.operand); | 1096 | const child_type = try resolveType(mod, scope, optional.positionals.operand); |
| ... | @@ -1033,7 +1098,7 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp | ... | @@ -1033,7 +1098,7 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp |
| 1033 | return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type)); | 1098 | return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type)); |
| 1034 | } | 1099 | } |
| 1035 | 1100 | ||
| 1036 | fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst { | 1101 | fn zirArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst { |
| 1037 | const tracy = trace(@src()); | 1102 | const tracy = trace(@src()); |
| 1038 | defer tracy.end(); | 1103 | defer tracy.end(); |
| 1039 | // TODO these should be lazily evaluated | 1104 | // TODO these should be lazily evaluated |
| ... | @@ -1043,7 +1108,7 @@ fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) Inn | ... | @@ -1043,7 +1108,7 @@ fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) Inn |
| 1043 | return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type)); | 1108 | return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type)); |
| 1044 | } | 1109 | } |
| 1045 | 1110 | ||
| 1046 | fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst { | 1111 | fn zirArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst { |
| 1047 | const tracy = trace(@src()); | 1112 | const tracy = trace(@src()); |
| 1048 | defer tracy.end(); | 1113 | defer tracy.end(); |
| 1049 | // TODO these should be lazily evaluated | 1114 | // TODO these should be lazily evaluated |
| ... | @@ -1054,7 +1119,7 @@ fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.Ar | ... | @@ -1054,7 +1119,7 @@ fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.Ar |
| 1054 | return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type)); | 1119 | return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type)); |
| 1055 | } | 1120 | } |
| 1056 | 1121 | ||
| 1057 | fn analyzeInstErrorUnionType(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1122 | fn zirErrorUnionType(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1058 | const tracy = trace(@src()); | 1123 | const tracy = trace(@src()); |
| 1059 | defer tracy.end(); | 1124 | defer tracy.end(); |
| 1060 | const error_union = try resolveType(mod, scope, inst.positionals.lhs); | 1125 | const error_union = try resolveType(mod, scope, inst.positionals.lhs); |
| ... | @@ -1067,7 +1132,7 @@ fn analyzeInstErrorUnionType(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) | ... | @@ -1067,7 +1132,7 @@ fn analyzeInstErrorUnionType(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) |
| 1067 | return mod.constType(scope, inst.base.src, try mod.errorUnionType(scope, error_union, payload)); | 1132 | return mod.constType(scope, inst.base.src, try mod.errorUnionType(scope, error_union, payload)); |
| 1068 | } | 1133 | } |
| 1069 | 1134 | ||
| 1070 | fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1135 | fn zirAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 1071 | const tracy = trace(@src()); | 1136 | const tracy = trace(@src()); |
| 1072 | defer tracy.end(); | 1137 | defer tracy.end(); |
| 1073 | const return_type = try resolveType(mod, scope, inst.positionals.operand); | 1138 | const return_type = try resolveType(mod, scope, inst.positionals.operand); |
| ... | @@ -1075,7 +1140,7 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In | ... | @@ -1075,7 +1140,7 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In |
| 1075 | return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type)); | 1140 | return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type)); |
| 1076 | } | 1141 | } |
| 1077 | 1142 | ||
| 1078 | fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst { | 1143 | fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst { |
| 1079 | const tracy = trace(@src()); | 1144 | const tracy = trace(@src()); |
| 1080 | defer tracy.end(); | 1145 | defer tracy.end(); |
| 1081 | // The declarations arena will store the hashmap. | 1146 | // The declarations arena will store the hashmap. |
| ... | @@ -1107,13 +1172,13 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In | ... | @@ -1107,13 +1172,13 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In |
| 1107 | return mod.analyzeDeclVal(scope, inst.base.src, new_decl); | 1172 | return mod.analyzeDeclVal(scope, inst.base.src, new_decl); |
| 1108 | } | 1173 | } |
| 1109 | 1174 | ||
| 1110 | fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1175 | fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1111 | const tracy = trace(@src()); | 1176 | const tracy = trace(@src()); |
| 1112 | defer tracy.end(); | 1177 | defer tracy.end(); |
| 1113 | return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{}); | 1178 | return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{}); |
| 1114 | } | 1179 | } |
| 1115 | 1180 | ||
| 1116 | fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst { | 1181 | fn zirEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst { |
| 1117 | const tracy = trace(@src()); | 1182 | const tracy = trace(@src()); |
| 1118 | defer tracy.end(); | 1183 | defer tracy.end(); |
| 1119 | const duped_name = try scope.arena().dupe(u8, inst.positionals.name); | 1184 | const duped_name = try scope.arena().dupe(u8, inst.positionals.name); |
| ... | @@ -1124,7 +1189,7 @@ fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiter | ... | @@ -1124,7 +1189,7 @@ fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiter |
| 1124 | } | 1189 | } |
| 1125 | 1190 | ||
| 1126 | /// Pointer in, pointer out. | 1191 | /// Pointer in, pointer out. |
| 1127 | fn optionalPayloadPtr( | 1192 | fn zirOptionalPayloadPtr( |
| 1128 | mod: *Module, | 1193 | mod: *Module, |
| 1129 | scope: *Scope, | 1194 | scope: *Scope, |
| 1130 | unwrap: *zir.Inst.UnOp, | 1195 | unwrap: *zir.Inst.UnOp, |
| ... | @@ -1165,7 +1230,7 @@ fn optionalPayloadPtr( | ... | @@ -1165,7 +1230,7 @@ fn optionalPayloadPtr( |
| 1165 | } | 1230 | } |
| 1166 | 1231 | ||
| 1167 | /// Value in, value out. | 1232 | /// Value in, value out. |
| 1168 | fn optionalPayload( | 1233 | fn zirOptionalPayload( |
| 1169 | mod: *Module, | 1234 | mod: *Module, |
| 1170 | scope: *Scope, | 1235 | scope: *Scope, |
| 1171 | unwrap: *zir.Inst.UnOp, | 1236 | unwrap: *zir.Inst.UnOp, |
| ... | @@ -1201,40 +1266,40 @@ fn optionalPayload( | ... | @@ -1201,40 +1266,40 @@ fn optionalPayload( |
| 1201 | } | 1266 | } |
| 1202 | 1267 | ||
| 1203 | /// Value in, value out | 1268 | /// Value in, value out |
| 1204 | fn errorUnionPayload(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | 1269 | fn zirErrUnionPayload(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { |
| 1205 | const tracy = trace(@src()); | 1270 | const tracy = trace(@src()); |
| 1206 | defer tracy.end(); | 1271 | defer tracy.end(); |
| 1207 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionPayload", .{}); | 1272 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionPayload", .{}); |
| 1208 | } | 1273 | } |
| 1209 | 1274 | ||
| 1210 | /// Pointer in, pointer out | 1275 | /// Pointer in, pointer out |
| 1211 | fn errorUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | 1276 | fn zirErrUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { |
| 1212 | const tracy = trace(@src()); | 1277 | const tracy = trace(@src()); |
| 1213 | defer tracy.end(); | 1278 | defer tracy.end(); |
| 1214 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionPayloadPtr", .{}); | 1279 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionPayloadPtr", .{}); |
| 1215 | } | 1280 | } |
| 1216 | 1281 | ||
| 1217 | /// Value in, value out | 1282 | /// Value in, value out |
| 1218 | fn errorUnionCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1283 | fn zirErrUnionCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 1219 | const tracy = trace(@src()); | 1284 | const tracy = trace(@src()); |
| 1220 | defer tracy.end(); | 1285 | defer tracy.end(); |
| 1221 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionCode", .{}); | 1286 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionCode", .{}); |
| 1222 | } | 1287 | } |
| 1223 | 1288 | ||
| 1224 | /// Pointer in, value out | 1289 | /// Pointer in, value out |
| 1225 | fn errorUnionCodePtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1290 | fn zirErrUnionCodePtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 1226 | const tracy = trace(@src()); | 1291 | const tracy = trace(@src()); |
| 1227 | defer tracy.end(); | 1292 | defer tracy.end(); |
| 1228 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionCodePtr", .{}); | 1293 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionCodePtr", .{}); |
| 1229 | } | 1294 | } |
| 1230 | 1295 | ||
| 1231 | fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1296 | fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 1232 | const tracy = trace(@src()); | 1297 | const tracy = trace(@src()); |
| 1233 | defer tracy.end(); | 1298 | defer tracy.end(); |
| 1234 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{}); | 1299 | return mod.fail(scope, unwrap.base.src, "TODO implement zirEnsureErrPayloadVoid", .{}); |
| 1235 | } | 1300 | } |
| 1236 | 1301 | ||
| 1237 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { | 1302 | fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| 1238 | const tracy = trace(@src()); | 1303 | const tracy = trace(@src()); |
| 1239 | defer tracy.end(); | 1304 | defer tracy.end(); |
| 1240 | const return_type = try resolveType(mod, scope, fntype.positionals.return_type); | 1305 | const return_type = try resolveType(mod, scope, fntype.positionals.return_type); |
| ... | @@ -1277,13 +1342,13 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne | ... | @@ -1277,13 +1342,13 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne |
| 1277 | return mod.constType(scope, fntype.base.src, fn_ty); | 1342 | return mod.constType(scope, fntype.base.src, fn_ty); |
| 1278 | } | 1343 | } |
| 1279 | 1344 | ||
| 1280 | fn analyzeInstPrimitive(mod: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst { | 1345 | fn zirPrimitive(mod: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst { |
| 1281 | const tracy = trace(@src()); | 1346 | const tracy = trace(@src()); |
| 1282 | defer tracy.end(); | 1347 | defer tracy.end(); |
| 1283 | return mod.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue()); | 1348 | return mod.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue()); |
| 1284 | } | 1349 | } |
| 1285 | 1350 | ||
| 1286 | fn analyzeInstAs(mod: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*Inst { | 1351 | fn zirAs(mod: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*Inst { |
| 1287 | const tracy = trace(@src()); | 1352 | const tracy = trace(@src()); |
| 1288 | defer tracy.end(); | 1353 | defer tracy.end(); |
| 1289 | const dest_type = try resolveType(mod, scope, as.positionals.lhs); | 1354 | const dest_type = try resolveType(mod, scope, as.positionals.lhs); |
| ... | @@ -1291,7 +1356,7 @@ fn analyzeInstAs(mod: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*I | ... | @@ -1291,7 +1356,7 @@ fn analyzeInstAs(mod: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*I |
| 1291 | return mod.coerce(scope, dest_type, new_inst); | 1356 | return mod.coerce(scope, dest_type, new_inst); |
| 1292 | } | 1357 | } |
| 1293 | 1358 | ||
| 1294 | fn analyzeInstPtrToInt(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) InnerError!*Inst { | 1359 | fn zirPtrtoint(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) InnerError!*Inst { |
| 1295 | const tracy = trace(@src()); | 1360 | const tracy = trace(@src()); |
| 1296 | defer tracy.end(); | 1361 | defer tracy.end(); |
| 1297 | const ptr = try resolveInst(mod, scope, ptrtoint.positionals.operand); | 1362 | const ptr = try resolveInst(mod, scope, ptrtoint.positionals.operand); |
| ... | @@ -1304,7 +1369,7 @@ fn analyzeInstPtrToInt(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) In | ... | @@ -1304,7 +1369,7 @@ fn analyzeInstPtrToInt(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) In |
| 1304 | return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr); | 1369 | return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr); |
| 1305 | } | 1370 | } |
| 1306 | 1371 | ||
| 1307 | fn fieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { | 1372 | fn zirFieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { |
| 1308 | const tracy = trace(@src()); | 1373 | const tracy = trace(@src()); |
| 1309 | defer tracy.end(); | 1374 | defer tracy.end(); |
| 1310 | 1375 | ||
| ... | @@ -1315,7 +1380,7 @@ fn fieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst | ... | @@ -1315,7 +1380,7 @@ fn fieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst |
| 1315 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | 1380 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); |
| 1316 | } | 1381 | } |
| 1317 | 1382 | ||
| 1318 | fn fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { | 1383 | fn zirFieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst { |
| 1319 | const tracy = trace(@src()); | 1384 | const tracy = trace(@src()); |
| 1320 | defer tracy.end(); | 1385 | defer tracy.end(); |
| 1321 | 1386 | ||
| ... | @@ -1324,7 +1389,7 @@ fn fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst | ... | @@ -1324,7 +1389,7 @@ fn fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst |
| 1324 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src); | 1389 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src); |
| 1325 | } | 1390 | } |
| 1326 | 1391 | ||
| 1327 | fn fieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { | 1392 | fn zirFieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { |
| 1328 | const tracy = trace(@src()); | 1393 | const tracy = trace(@src()); |
| 1329 | defer tracy.end(); | 1394 | defer tracy.end(); |
| 1330 | 1395 | ||
| ... | @@ -1336,7 +1401,7 @@ fn fieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerE | ... | @@ -1336,7 +1401,7 @@ fn fieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerE |
| 1336 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | 1401 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); |
| 1337 | } | 1402 | } |
| 1338 | 1403 | ||
| 1339 | fn fieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { | 1404 | fn zirFieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst { |
| 1340 | const tracy = trace(@src()); | 1405 | const tracy = trace(@src()); |
| 1341 | defer tracy.end(); | 1406 | defer tracy.end(); |
| 1342 | 1407 | ||
| ... | @@ -1346,7 +1411,7 @@ fn fieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerE | ... | @@ -1346,7 +1411,7 @@ fn fieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerE |
| 1346 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc); | 1411 | return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc); |
| 1347 | } | 1412 | } |
| 1348 | 1413 | ||
| 1349 | fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1414 | fn zirIntcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1350 | const tracy = trace(@src()); | 1415 | const tracy = trace(@src()); |
| 1351 | defer tracy.end(); | 1416 | defer tracy.end(); |
| 1352 | const dest_type = try resolveType(mod, scope, inst.positionals.lhs); | 1417 | const dest_type = try resolveType(mod, scope, inst.positionals.lhs); |
| ... | @@ -1384,7 +1449,7 @@ fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE | ... | @@ -1384,7 +1449,7 @@ fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE |
| 1384 | return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{}); | 1449 | return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{}); |
| 1385 | } | 1450 | } |
| 1386 | 1451 | ||
| 1387 | fn analyzeInstBitCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1452 | fn zirBitcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1388 | const tracy = trace(@src()); | 1453 | const tracy = trace(@src()); |
| 1389 | defer tracy.end(); | 1454 | defer tracy.end(); |
| 1390 | const dest_type = try resolveType(mod, scope, inst.positionals.lhs); | 1455 | const dest_type = try resolveType(mod, scope, inst.positionals.lhs); |
| ... | @@ -1392,7 +1457,7 @@ fn analyzeInstBitCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE | ... | @@ -1392,7 +1457,7 @@ fn analyzeInstBitCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE |
| 1392 | return mod.bitcast(scope, dest_type, operand); | 1457 | return mod.bitcast(scope, dest_type, operand); |
| 1393 | } | 1458 | } |
| 1394 | 1459 | ||
| 1395 | fn analyzeInstFloatCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1460 | fn zirFloatcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1396 | const tracy = trace(@src()); | 1461 | const tracy = trace(@src()); |
| 1397 | defer tracy.end(); | 1462 | defer tracy.end(); |
| 1398 | const dest_type = try resolveType(mod, scope, inst.positionals.lhs); | 1463 | const dest_type = try resolveType(mod, scope, inst.positionals.lhs); |
| ... | @@ -1430,7 +1495,7 @@ fn analyzeInstFloatCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inne | ... | @@ -1430,7 +1495,7 @@ fn analyzeInstFloatCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inne |
| 1430 | return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{}); | 1495 | return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{}); |
| 1431 | } | 1496 | } |
| 1432 | 1497 | ||
| 1433 | fn elemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { | 1498 | fn zirElemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { |
| 1434 | const tracy = trace(@src()); | 1499 | const tracy = trace(@src()); |
| 1435 | defer tracy.end(); | 1500 | defer tracy.end(); |
| 1436 | 1501 | ||
| ... | @@ -1441,7 +1506,7 @@ fn elemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { | ... | @@ -1441,7 +1506,7 @@ fn elemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { |
| 1441 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); | 1506 | return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src); |
| 1442 | } | 1507 | } |
| 1443 | 1508 | ||
| 1444 | fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { | 1509 | fn zirElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { |
| 1445 | const tracy = trace(@src()); | 1510 | const tracy = trace(@src()); |
| 1446 | defer tracy.end(); | 1511 | defer tracy.end(); |
| 1447 | 1512 | ||
| ... | @@ -1450,7 +1515,7 @@ fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { | ... | @@ -1450,7 +1515,7 @@ fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst { |
| 1450 | return mod.elemPtr(scope, inst.base.src, array_ptr, elem_index); | 1515 | return mod.elemPtr(scope, inst.base.src, array_ptr, elem_index); |
| 1451 | } | 1516 | } |
| 1452 | 1517 | ||
| 1453 | fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst { | 1518 | fn zirSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst { |
| 1454 | const tracy = trace(@src()); | 1519 | const tracy = trace(@src()); |
| 1455 | defer tracy.end(); | 1520 | defer tracy.end(); |
| 1456 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); | 1521 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); |
| ... | @@ -1461,7 +1526,7 @@ fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerErr | ... | @@ -1461,7 +1526,7 @@ fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerErr |
| 1461 | return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, end, sentinel); | 1526 | return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, end, sentinel); |
| 1462 | } | 1527 | } |
| 1463 | 1528 | ||
| 1464 | fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1529 | fn zirSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1465 | const tracy = trace(@src()); | 1530 | const tracy = trace(@src()); |
| 1466 | defer tracy.end(); | 1531 | defer tracy.end(); |
| 1467 | const array_ptr = try resolveInst(mod, scope, inst.positionals.lhs); | 1532 | const array_ptr = try resolveInst(mod, scope, inst.positionals.lhs); |
| ... | @@ -1470,235 +1535,7 @@ fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn | ... | @@ -1470,235 +1535,7 @@ fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn |
| 1470 | return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null); | 1535 | return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null); |
| 1471 | } | 1536 | } |
| 1472 | 1537 | ||
| 1473 | fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1538 | fn zirImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 1474 | const tracy = trace(@src()); | ||
| 1475 | defer tracy.end(); | ||
| 1476 | const start = try resolveInst(mod, scope, inst.positionals.lhs); | ||
| 1477 | const end = try resolveInst(mod, scope, inst.positionals.rhs); | ||
| 1478 | |||
| 1479 | switch (start.ty.zigTypeTag()) { | ||
| 1480 | .Int, .ComptimeInt => {}, | ||
| 1481 | else => return mod.constVoid(scope, inst.base.src), | ||
| 1482 | } | ||
| 1483 | switch (end.ty.zigTypeTag()) { | ||
| 1484 | .Int, .ComptimeInt => {}, | ||
| 1485 | else => return mod.constVoid(scope, inst.base.src), | ||
| 1486 | } | ||
| 1487 | if (start.value()) |start_val| { | ||
| 1488 | if (end.value()) |end_val| { | ||
| 1489 | if (start_val.compare(.gte, end_val)) { | ||
| 1490 | return mod.fail(scope, inst.base.src, "range start value must be smaller than the end value", .{}); | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | } | ||
| 1494 | return mod.constVoid(scope, inst.base.src); | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) InnerError!*Inst { | ||
| 1498 | const tracy = trace(@src()); | ||
| 1499 | defer tracy.end(); | ||
| 1500 | const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr); | ||
| 1501 | const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src); | ||
| 1502 | try validateSwitch(mod, scope, target, inst); | ||
| 1503 | |||
| 1504 | if (try mod.resolveDefinedValue(scope, target)) |target_val| { | ||
| 1505 | for (inst.positionals.cases) |case| { | ||
| 1506 | const resolved = try resolveInst(mod, scope, case.item); | ||
| 1507 | const casted = try mod.coerce(scope, target.ty, resolved); | ||
| 1508 | const item = try mod.resolveConstValue(scope, casted); | ||
| 1509 | |||
| 1510 | if (target_val.eql(item)) { | ||
| 1511 | try analyzeBody(mod, scope.cast(Scope.Block).?, case.body); | ||
| 1512 | return mod.constNoReturn(scope, inst.base.src); | ||
| 1513 | } | ||
| 1514 | } | ||
| 1515 | try analyzeBody(mod, scope.cast(Scope.Block).?, inst.positionals.else_body); | ||
| 1516 | return mod.constNoReturn(scope, inst.base.src); | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | if (inst.positionals.cases.len == 0) { | ||
| 1520 | // no cases just analyze else_branch | ||
| 1521 | try analyzeBody(mod, scope.cast(Scope.Block).?, inst.positionals.else_body); | ||
| 1522 | return mod.constNoReturn(scope, inst.base.src); | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); | ||
| 1526 | const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len); | ||
| 1527 | |||
| 1528 | var case_block: Scope.Block = .{ | ||
| 1529 | .parent = parent_block, | ||
| 1530 | .inst_table = parent_block.inst_table, | ||
| 1531 | .func = parent_block.func, | ||
| 1532 | .owner_decl = parent_block.owner_decl, | ||
| 1533 | .src_decl = parent_block.src_decl, | ||
| 1534 | .instructions = .{}, | ||
| 1535 | .arena = parent_block.arena, | ||
| 1536 | .inlining = parent_block.inlining, | ||
| 1537 | .is_comptime = parent_block.is_comptime, | ||
| 1538 | .branch_quota = parent_block.branch_quota, | ||
| 1539 | }; | ||
| 1540 | defer case_block.instructions.deinit(mod.gpa); | ||
| 1541 | |||
| 1542 | for (inst.positionals.cases) |case, i| { | ||
| 1543 | // Reset without freeing. | ||
| 1544 | case_block.instructions.items.len = 0; | ||
| 1545 | |||
| 1546 | const resolved = try resolveInst(mod, scope, case.item); | ||
| 1547 | const casted = try mod.coerce(scope, target.ty, resolved); | ||
| 1548 | const item = try mod.resolveConstValue(scope, casted); | ||
| 1549 | |||
| 1550 | try analyzeBody(mod, &case_block, case.body); | ||
| 1551 | |||
| 1552 | cases[i] = .{ | ||
| 1553 | .item = item, | ||
| 1554 | .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) }, | ||
| 1555 | }; | ||
| 1556 | } | ||
| 1557 | |||
| 1558 | case_block.instructions.items.len = 0; | ||
| 1559 | try analyzeBody(mod, &case_block, inst.positionals.else_body); | ||
| 1560 | |||
| 1561 | const else_body: ir.Body = .{ | ||
| 1562 | .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items), | ||
| 1563 | }; | ||
| 1564 | |||
| 1565 | return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body); | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void { | ||
| 1569 | // validate usage of '_' prongs | ||
| 1570 | if (inst.kw_args.special_prong == .underscore and target.ty.zigTypeTag() != .Enum) { | ||
| 1571 | return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{}); | ||
| 1572 | // TODO notes "'_' prong here" inst.positionals.cases[last].src | ||
| 1573 | } | ||
| 1574 | |||
| 1575 | // check that target type supports ranges | ||
| 1576 | if (inst.kw_args.range) |range_inst| { | ||
| 1577 | switch (target.ty.zigTypeTag()) { | ||
| 1578 | .Int, .ComptimeInt => {}, | ||
| 1579 | else => { | ||
| 1580 | return mod.fail(scope, target.src, "ranges not allowed when switching on type {}", .{target.ty}); | ||
| 1581 | // TODO notes "range used here" range_inst.src | ||
| 1582 | }, | ||
| 1583 | } | ||
| 1584 | } | ||
| 1585 | |||
| 1586 | // validate for duplicate items/missing else prong | ||
| 1587 | switch (target.ty.zigTypeTag()) { | ||
| 1588 | .Enum => return mod.fail(scope, inst.base.src, "TODO validateSwitch .Enum", .{}), | ||
| 1589 | .ErrorSet => return mod.fail(scope, inst.base.src, "TODO validateSwitch .ErrorSet", .{}), | ||
| 1590 | .Union => return mod.fail(scope, inst.base.src, "TODO validateSwitch .Union", .{}), | ||
| 1591 | .Int, .ComptimeInt => { | ||
| 1592 | var range_set = @import("RangeSet.zig").init(mod.gpa); | ||
| 1593 | defer range_set.deinit(); | ||
| 1594 | |||
| 1595 | for (inst.positionals.items) |item| { | ||
| 1596 | const maybe_src = if (item.castTag(.switch_range)) |range| blk: { | ||
| 1597 | const start_resolved = try resolveInst(mod, scope, range.positionals.lhs); | ||
| 1598 | const start_casted = try mod.coerce(scope, target.ty, start_resolved); | ||
| 1599 | const end_resolved = try resolveInst(mod, scope, range.positionals.rhs); | ||
| 1600 | const end_casted = try mod.coerce(scope, target.ty, end_resolved); | ||
| 1601 | |||
| 1602 | break :blk try range_set.add( | ||
| 1603 | try mod.resolveConstValue(scope, start_casted), | ||
| 1604 | try mod.resolveConstValue(scope, end_casted), | ||
| 1605 | item.src, | ||
| 1606 | ); | ||
| 1607 | } else blk: { | ||
| 1608 | const resolved = try resolveInst(mod, scope, item); | ||
| 1609 | const casted = try mod.coerce(scope, target.ty, resolved); | ||
| 1610 | const value = try mod.resolveConstValue(scope, casted); | ||
| 1611 | break :blk try range_set.add(value, value, item.src); | ||
| 1612 | }; | ||
| 1613 | |||
| 1614 | if (maybe_src) |previous_src| { | ||
| 1615 | return mod.fail(scope, item.src, "duplicate switch value", .{}); | ||
| 1616 | // TODO notes "previous value is here" previous_src | ||
| 1617 | } | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | if (target.ty.zigTypeTag() == .Int) { | ||
| 1621 | var arena = std.heap.ArenaAllocator.init(mod.gpa); | ||
| 1622 | defer arena.deinit(); | ||
| 1623 | |||
| 1624 | const start = try target.ty.minInt(&arena, mod.getTarget()); | ||
| 1625 | const end = try target.ty.maxInt(&arena, mod.getTarget()); | ||
| 1626 | if (try range_set.spans(start, end)) { | ||
| 1627 | if (inst.kw_args.special_prong == .@"else") { | ||
| 1628 | return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{}); | ||
| 1629 | } | ||
| 1630 | return; | ||
| 1631 | } | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | if (inst.kw_args.special_prong != .@"else") { | ||
| 1635 | return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{}); | ||
| 1636 | } | ||
| 1637 | }, | ||
| 1638 | .Bool => { | ||
| 1639 | var true_count: u8 = 0; | ||
| 1640 | var false_count: u8 = 0; | ||
| 1641 | for (inst.positionals.items) |item| { | ||
| 1642 | const resolved = try resolveInst(mod, scope, item); | ||
| 1643 | const casted = try mod.coerce(scope, Type.initTag(.bool), resolved); | ||
| 1644 | if ((try mod.resolveConstValue(scope, casted)).toBool()) { | ||
| 1645 | true_count += 1; | ||
| 1646 | } else { | ||
| 1647 | false_count += 1; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | if (true_count + false_count > 2) { | ||
| 1651 | return mod.fail(scope, item.src, "duplicate switch value", .{}); | ||
| 1652 | } | ||
| 1653 | } | ||
| 1654 | if ((true_count + false_count < 2) and inst.kw_args.special_prong != .@"else") { | ||
| 1655 | return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{}); | ||
| 1656 | } | ||
| 1657 | if ((true_count + false_count == 2) and inst.kw_args.special_prong == .@"else") { | ||
| 1658 | return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{}); | ||
| 1659 | } | ||
| 1660 | }, | ||
| 1661 | .EnumLiteral, .Void, .Fn, .Pointer, .Type => { | ||
| 1662 | if (inst.kw_args.special_prong != .@"else") { | ||
| 1663 | return mod.fail(scope, inst.base.src, "else prong required when switching on type '{}'", .{target.ty}); | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa); | ||
| 1667 | defer seen_values.deinit(); | ||
| 1668 | |||
| 1669 | for (inst.positionals.items) |item| { | ||
| 1670 | const resolved = try resolveInst(mod, scope, item); | ||
| 1671 | const casted = try mod.coerce(scope, target.ty, resolved); | ||
| 1672 | const val = try mod.resolveConstValue(scope, casted); | ||
| 1673 | |||
| 1674 | if (try seen_values.fetchPut(val, item.src)) |prev| { | ||
| 1675 | return mod.fail(scope, item.src, "duplicate switch value", .{}); | ||
| 1676 | // TODO notes "previous value here" prev.value | ||
| 1677 | } | ||
| 1678 | } | ||
| 1679 | }, | ||
| 1680 | |||
| 1681 | .ErrorUnion, | ||
| 1682 | .NoReturn, | ||
| 1683 | .Array, | ||
| 1684 | .Struct, | ||
| 1685 | .Undefined, | ||
| 1686 | .Null, | ||
| 1687 | .Optional, | ||
| 1688 | .BoundFn, | ||
| 1689 | .Opaque, | ||
| 1690 | .Vector, | ||
| 1691 | .Frame, | ||
| 1692 | .AnyFrame, | ||
| 1693 | .ComptimeFloat, | ||
| 1694 | .Float, | ||
| 1695 | => { | ||
| 1696 | return mod.fail(scope, target.src, "invalid switch target type '{}'", .{target.ty}); | ||
| 1697 | }, | ||
| 1698 | } | ||
| 1699 | } | ||
| 1700 | |||
| 1701 | fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 1702 | const tracy = trace(@src()); | 1539 | const tracy = trace(@src()); |
| 1703 | defer tracy.end(); | 1540 | defer tracy.end(); |
| 1704 | const operand = try resolveConstString(mod, scope, inst.positionals.operand); | 1541 | const operand = try resolveConstString(mod, scope, inst.positionals.operand); |
| ... | @@ -1718,19 +1555,19 @@ fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErr | ... | @@ -1718,19 +1555,19 @@ fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErr |
| 1718 | return mod.constType(scope, inst.base.src, file_scope.root_container.ty); | 1555 | return mod.constType(scope, inst.base.src, file_scope.root_container.ty); |
| 1719 | } | 1556 | } |
| 1720 | 1557 | ||
| 1721 | fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1558 | fn zirShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1722 | const tracy = trace(@src()); | 1559 | const tracy = trace(@src()); |
| 1723 | defer tracy.end(); | 1560 | defer tracy.end(); |
| 1724 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{}); | 1561 | return mod.fail(scope, inst.base.src, "TODO implement zirShl", .{}); |
| 1725 | } | 1562 | } |
| 1726 | 1563 | ||
| 1727 | fn analyzeInstShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1564 | fn zirShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1728 | const tracy = trace(@src()); | 1565 | const tracy = trace(@src()); |
| 1729 | defer tracy.end(); | 1566 | defer tracy.end(); |
| 1730 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShr", .{}); | 1567 | return mod.fail(scope, inst.base.src, "TODO implement zirShr", .{}); |
| 1731 | } | 1568 | } |
| 1732 | 1569 | ||
| 1733 | fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1570 | fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1734 | const tracy = trace(@src()); | 1571 | const tracy = trace(@src()); |
| 1735 | defer tracy.end(); | 1572 | defer tracy.end(); |
| 1736 | 1573 | ||
| ... | @@ -1784,8 +1621,8 @@ fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE | ... | @@ -1784,8 +1621,8 @@ fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE |
| 1784 | 1621 | ||
| 1785 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | 1622 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 1786 | const ir_tag = switch (inst.base.tag) { | 1623 | const ir_tag = switch (inst.base.tag) { |
| 1787 | .bitand => Inst.Tag.bitand, | 1624 | .bit_and => Inst.Tag.bit_and, |
| 1788 | .bitor => Inst.Tag.bitor, | 1625 | .bit_or => Inst.Tag.bit_or, |
| 1789 | .xor => Inst.Tag.xor, | 1626 | .xor => Inst.Tag.xor, |
| 1790 | else => unreachable, | 1627 | else => unreachable, |
| 1791 | }; | 1628 | }; |
| ... | @@ -1793,25 +1630,25 @@ fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE | ... | @@ -1793,25 +1630,25 @@ fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE |
| 1793 | return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs); | 1630 | return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs); |
| 1794 | } | 1631 | } |
| 1795 | 1632 | ||
| 1796 | fn analyzeInstBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1633 | fn zirBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 1797 | const tracy = trace(@src()); | 1634 | const tracy = trace(@src()); |
| 1798 | defer tracy.end(); | 1635 | defer tracy.end(); |
| 1799 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitNot", .{}); | 1636 | return mod.fail(scope, inst.base.src, "TODO implement zirBitNot", .{}); |
| 1800 | } | 1637 | } |
| 1801 | 1638 | ||
| 1802 | fn analyzeInstArrayCat(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1639 | fn zirArrayCat(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1803 | const tracy = trace(@src()); | 1640 | const tracy = trace(@src()); |
| 1804 | defer tracy.end(); | 1641 | defer tracy.end(); |
| 1805 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstArrayCat", .{}); | 1642 | return mod.fail(scope, inst.base.src, "TODO implement zirArrayCat", .{}); |
| 1806 | } | 1643 | } |
| 1807 | 1644 | ||
| 1808 | fn analyzeInstArrayMul(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1645 | fn zirArrayMul(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1809 | const tracy = trace(@src()); | 1646 | const tracy = trace(@src()); |
| 1810 | defer tracy.end(); | 1647 | defer tracy.end(); |
| 1811 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstArrayMul", .{}); | 1648 | return mod.fail(scope, inst.base.src, "TODO implement zirArrayMul", .{}); |
| 1812 | } | 1649 | } |
| 1813 | 1650 | ||
| 1814 | fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1651 | fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1815 | const tracy = trace(@src()); | 1652 | const tracy = trace(@src()); |
| 1816 | defer tracy.end(); | 1653 | defer tracy.end(); |
| 1817 | 1654 | ||
| ... | @@ -1912,14 +1749,14 @@ fn analyzeInstComptimeOp(mod: *Module, scope: *Scope, res_type: Type, inst: *zir | ... | @@ -1912,14 +1749,14 @@ fn analyzeInstComptimeOp(mod: *Module, scope: *Scope, res_type: Type, inst: *zir |
| 1912 | }); | 1749 | }); |
| 1913 | } | 1750 | } |
| 1914 | 1751 | ||
| 1915 | fn analyzeInstDeref(mod: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst { | 1752 | fn zirDeref(mod: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst { |
| 1916 | const tracy = trace(@src()); | 1753 | const tracy = trace(@src()); |
| 1917 | defer tracy.end(); | 1754 | defer tracy.end(); |
| 1918 | const ptr = try resolveInst(mod, scope, deref.positionals.operand); | 1755 | const ptr = try resolveInst(mod, scope, deref.positionals.operand); |
| 1919 | return mod.analyzeDeref(scope, deref.base.src, ptr, deref.positionals.operand.src); | 1756 | return mod.analyzeDeref(scope, deref.base.src, ptr, deref.positionals.operand.src); |
| 1920 | } | 1757 | } |
| 1921 | 1758 | ||
| 1922 | fn analyzeInstAsm(mod: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerError!*Inst { | 1759 | fn zirAsm(mod: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerError!*Inst { |
| 1923 | const tracy = trace(@src()); | 1760 | const tracy = trace(@src()); |
| 1924 | defer tracy.end(); | 1761 | defer tracy.end(); |
| 1925 | const return_type = try resolveType(mod, scope, assembly.positionals.return_type); | 1762 | const return_type = try resolveType(mod, scope, assembly.positionals.return_type); |
| ... | @@ -1960,7 +1797,7 @@ fn analyzeInstAsm(mod: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerErr | ... | @@ -1960,7 +1797,7 @@ fn analyzeInstAsm(mod: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerErr |
| 1960 | return &inst.base; | 1797 | return &inst.base; |
| 1961 | } | 1798 | } |
| 1962 | 1799 | ||
| 1963 | fn analyzeInstCmp( | 1800 | fn zirCmp( |
| 1964 | mod: *Module, | 1801 | mod: *Module, |
| 1965 | scope: *Scope, | 1802 | scope: *Scope, |
| 1966 | inst: *zir.Inst.BinOp, | 1803 | inst: *zir.Inst.BinOp, |
| ... | @@ -2018,14 +1855,14 @@ fn analyzeInstCmp( | ... | @@ -2018,14 +1855,14 @@ fn analyzeInstCmp( |
| 2018 | return mod.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{}); | 1855 | return mod.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{}); |
| 2019 | } | 1856 | } |
| 2020 | 1857 | ||
| 2021 | fn analyzeInstTypeOf(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1858 | fn zirTypeof(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 2022 | const tracy = trace(@src()); | 1859 | const tracy = trace(@src()); |
| 2023 | defer tracy.end(); | 1860 | defer tracy.end(); |
| 2024 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 1861 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 2025 | return mod.constType(scope, inst.base.src, operand.ty); | 1862 | return mod.constType(scope, inst.base.src, operand.ty); |
| 2026 | } | 1863 | } |
| 2027 | 1864 | ||
| 2028 | fn analyzeInstTypeOfPeer(mod: *Module, scope: *Scope, inst: *zir.Inst.TypeOfPeer) InnerError!*Inst { | 1865 | fn zirTypeofPeer(mod: *Module, scope: *Scope, inst: *zir.Inst.TypeOfPeer) InnerError!*Inst { |
| 2029 | const tracy = trace(@src()); | 1866 | const tracy = trace(@src()); |
| 2030 | defer tracy.end(); | 1867 | defer tracy.end(); |
| 2031 | var insts_to_res = try mod.gpa.alloc(*ir.Inst, inst.positionals.items.len); | 1868 | var insts_to_res = try mod.gpa.alloc(*ir.Inst, inst.positionals.items.len); |
| ... | @@ -2037,7 +1874,7 @@ fn analyzeInstTypeOfPeer(mod: *Module, scope: *Scope, inst: *zir.Inst.TypeOfPeer | ... | @@ -2037,7 +1874,7 @@ fn analyzeInstTypeOfPeer(mod: *Module, scope: *Scope, inst: *zir.Inst.TypeOfPeer |
| 2037 | return mod.constType(scope, inst.base.src, pt_res); | 1874 | return mod.constType(scope, inst.base.src, pt_res); |
| 2038 | } | 1875 | } |
| 2039 | 1876 | ||
| 2040 | fn analyzeInstBoolNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1877 | fn zirBoolNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 2041 | const tracy = trace(@src()); | 1878 | const tracy = trace(@src()); |
| 2042 | defer tracy.end(); | 1879 | defer tracy.end(); |
| 2043 | const uncasted_operand = try resolveInst(mod, scope, inst.positionals.operand); | 1880 | const uncasted_operand = try resolveInst(mod, scope, inst.positionals.operand); |
| ... | @@ -2050,7 +1887,7 @@ fn analyzeInstBoolNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerEr | ... | @@ -2050,7 +1887,7 @@ fn analyzeInstBoolNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerEr |
| 2050 | return mod.addUnOp(b, inst.base.src, bool_type, .not, operand); | 1887 | return mod.addUnOp(b, inst.base.src, bool_type, .not, operand); |
| 2051 | } | 1888 | } |
| 2052 | 1889 | ||
| 2053 | fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 1890 | fn zirBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 2054 | const tracy = trace(@src()); | 1891 | const tracy = trace(@src()); |
| 2055 | defer tracy.end(); | 1892 | defer tracy.end(); |
| 2056 | const bool_type = Type.initTag(.bool); | 1893 | const bool_type = Type.initTag(.bool); |
| ... | @@ -2059,7 +1896,7 @@ fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr | ... | @@ -2059,7 +1896,7 @@ fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr |
| 2059 | const uncasted_rhs = try resolveInst(mod, scope, inst.positionals.rhs); | 1896 | const uncasted_rhs = try resolveInst(mod, scope, inst.positionals.rhs); |
| 2060 | const rhs = try mod.coerce(scope, bool_type, uncasted_rhs); | 1897 | const rhs = try mod.coerce(scope, bool_type, uncasted_rhs); |
| 2061 | 1898 | ||
| 2062 | const is_bool_or = inst.base.tag == .boolor; | 1899 | const is_bool_or = inst.base.tag == .bool_or; |
| 2063 | 1900 | ||
| 2064 | if (lhs.value()) |lhs_val| { | 1901 | if (lhs.value()) |lhs_val| { |
| 2065 | if (rhs.value()) |rhs_val| { | 1902 | if (rhs.value()) |rhs_val| { |
| ... | @@ -2071,17 +1908,17 @@ fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr | ... | @@ -2071,17 +1908,17 @@ fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr |
| 2071 | } | 1908 | } |
| 2072 | } | 1909 | } |
| 2073 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | 1910 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 2074 | return mod.addBinOp(b, inst.base.src, bool_type, if (is_bool_or) .boolor else .booland, lhs, rhs); | 1911 | return mod.addBinOp(b, inst.base.src, bool_type, if (is_bool_or) .bool_or else .bool_and, lhs, rhs); |
| 2075 | } | 1912 | } |
| 2076 | 1913 | ||
| 2077 | fn isNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { | 1914 | fn zirIsNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { |
| 2078 | const tracy = trace(@src()); | 1915 | const tracy = trace(@src()); |
| 2079 | defer tracy.end(); | 1916 | defer tracy.end(); |
| 2080 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 1917 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 2081 | return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic); | 1918 | return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic); |
| 2082 | } | 1919 | } |
| 2083 | 1920 | ||
| 2084 | fn isNullPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { | 1921 | fn zirIsNullPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { |
| 2085 | const tracy = trace(@src()); | 1922 | const tracy = trace(@src()); |
| 2086 | defer tracy.end(); | 1923 | defer tracy.end(); |
| 2087 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); | 1924 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); |
| ... | @@ -2089,14 +1926,14 @@ fn isNullPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bo | ... | @@ -2089,14 +1926,14 @@ fn isNullPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bo |
| 2089 | return mod.analyzeIsNull(scope, inst.base.src, loaded, invert_logic); | 1926 | return mod.analyzeIsNull(scope, inst.base.src, loaded, invert_logic); |
| 2090 | } | 1927 | } |
| 2091 | 1928 | ||
| 2092 | fn isErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1929 | fn zirIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 2093 | const tracy = trace(@src()); | 1930 | const tracy = trace(@src()); |
| 2094 | defer tracy.end(); | 1931 | defer tracy.end(); |
| 2095 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 1932 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 2096 | return mod.analyzeIsErr(scope, inst.base.src, operand); | 1933 | return mod.analyzeIsErr(scope, inst.base.src, operand); |
| 2097 | } | 1934 | } |
| 2098 | 1935 | ||
| 2099 | fn isErrPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1936 | fn zirIsErrPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 2100 | const tracy = trace(@src()); | 1937 | const tracy = trace(@src()); |
| 2101 | defer tracy.end(); | 1938 | defer tracy.end(); |
| 2102 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); | 1939 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); |
| ... | @@ -2104,7 +1941,7 @@ fn isErrPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst | ... | @@ -2104,7 +1941,7 @@ fn isErrPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst |
| 2104 | return mod.analyzeIsErr(scope, inst.base.src, loaded); | 1941 | return mod.analyzeIsErr(scope, inst.base.src, loaded); |
| 2105 | } | 1942 | } |
| 2106 | 1943 | ||
| 2107 | fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst { | 1944 | fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst { |
| 2108 | const tracy = trace(@src()); | 1945 | const tracy = trace(@src()); |
| 2109 | defer tracy.end(); | 1946 | defer tracy.end(); |
| 2110 | const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition); | 1947 | const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition); |
| ... | @@ -2153,7 +1990,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -2153,7 +1990,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 2153 | return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body); | 1990 | return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body); |
| 2154 | } | 1991 | } |
| 2155 | 1992 | ||
| 2156 | fn analyzeInstUnreachable( | 1993 | fn zirUnreachable( |
| 2157 | mod: *Module, | 1994 | mod: *Module, |
| 2158 | scope: *Scope, | 1995 | scope: *Scope, |
| 2159 | unreach: *zir.Inst.NoOp, | 1996 | unreach: *zir.Inst.NoOp, |
| ... | @@ -2170,7 +2007,7 @@ fn analyzeInstUnreachable( | ... | @@ -2170,7 +2007,7 @@ fn analyzeInstUnreachable( |
| 2170 | } | 2007 | } |
| 2171 | } | 2008 | } |
| 2172 | 2009 | ||
| 2173 | fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 2010 | fn zirReturn(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 2174 | const tracy = trace(@src()); | 2011 | const tracy = trace(@src()); |
| 2175 | defer tracy.end(); | 2012 | defer tracy.end(); |
| 2176 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 2013 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| ... | @@ -2179,13 +2016,14 @@ fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! | ... | @@ -2179,13 +2016,14 @@ fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! |
| 2179 | if (b.inlining) |inlining| { | 2016 | if (b.inlining) |inlining| { |
| 2180 | // We are inlining a function call; rewrite the `ret` as a `break`. | 2017 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 2181 | try inlining.merges.results.append(mod.gpa, operand); | 2018 | try inlining.merges.results.append(mod.gpa, operand); |
| 2182 | return mod.addBr(b, inst.base.src, inlining.merges.block_inst, operand); | 2019 | const br = try mod.addBr(b, inst.base.src, inlining.merges.block_inst, operand); |
| 2020 | return &br.base; | ||
| 2183 | } | 2021 | } |
| 2184 | 2022 | ||
| 2185 | return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, operand); | 2023 | return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, operand); |
| 2186 | } | 2024 | } |
| 2187 | 2025 | ||
| 2188 | fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 2026 | fn zirReturnVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| 2189 | const tracy = trace(@src()); | 2027 | const tracy = trace(@src()); |
| 2190 | defer tracy.end(); | 2028 | defer tracy.end(); |
| 2191 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | 2029 | const b = try mod.requireFunctionBlock(scope, inst.base.src); |
| ... | @@ -2193,7 +2031,8 @@ fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr | ... | @@ -2193,7 +2031,8 @@ fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr |
| 2193 | // We are inlining a function call; rewrite the `retvoid` as a `breakvoid`. | 2031 | // We are inlining a function call; rewrite the `retvoid` as a `breakvoid`. |
| 2194 | const void_inst = try mod.constVoid(scope, inst.base.src); | 2032 | const void_inst = try mod.constVoid(scope, inst.base.src); |
| 2195 | try inlining.merges.results.append(mod.gpa, void_inst); | 2033 | try inlining.merges.results.append(mod.gpa, void_inst); |
| 2196 | return mod.addBr(b, inst.base.src, inlining.merges.block_inst, void_inst); | 2034 | const br = try mod.addBr(b, inst.base.src, inlining.merges.block_inst, void_inst); |
| 2035 | return &br.base; | ||
| 2197 | } | 2036 | } |
| 2198 | 2037 | ||
| 2199 | if (b.func) |func| { | 2038 | if (b.func) |func| { |
| ... | @@ -2216,27 +2055,7 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool { | ... | @@ -2216,27 +2055,7 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool { |
| 2216 | }; | 2055 | }; |
| 2217 | } | 2056 | } |
| 2218 | 2057 | ||
| 2219 | fn analyzeBreak( | 2058 | fn zirSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { |
| 2220 | mod: *Module, | ||
| 2221 | scope: *Scope, | ||
| 2222 | src: usize, | ||
| 2223 | zir_block: *zir.Inst.Block, | ||
| 2224 | operand: *Inst, | ||
| 2225 | ) InnerError!*Inst { | ||
| 2226 | var opt_block = scope.cast(Scope.Block); | ||
| 2227 | while (opt_block) |block| { | ||
| 2228 | if (block.label) |*label| { | ||
| 2229 | if (label.zir_block == zir_block) { | ||
| 2230 | try label.merges.results.append(mod.gpa, operand); | ||
| 2231 | const b = try mod.requireFunctionBlock(scope, src); | ||
| 2232 | return mod.addBr(b, src, label.merges.block_inst, operand); | ||
| 2233 | } | ||
| 2234 | } | ||
| 2235 | opt_block = block.parent; | ||
| 2236 | } else unreachable; | ||
| 2237 | } | ||
| 2238 | |||
| 2239 | fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { | ||
| 2240 | const tracy = trace(@src()); | 2059 | const tracy = trace(@src()); |
| 2241 | defer tracy.end(); | 2060 | defer tracy.end(); |
| 2242 | const elem_type = try resolveType(mod, scope, inst.positionals.operand); | 2061 | const elem_type = try resolveType(mod, scope, inst.positionals.operand); |
| ... | @@ -2244,7 +2063,7 @@ fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, m | ... | @@ -2244,7 +2063,7 @@ fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, m |
| 2244 | return mod.constType(scope, inst.base.src, ty); | 2063 | return mod.constType(scope, inst.base.src, ty); |
| 2245 | } | 2064 | } |
| 2246 | 2065 | ||
| 2247 | fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { | 2066 | fn zirPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { |
| 2248 | const tracy = trace(@src()); | 2067 | const tracy = trace(@src()); |
| 2249 | defer tracy.end(); | 2068 | defer tracy.end(); |
| 2250 | // TODO lazy values | 2069 | // TODO lazy values |
test/stage2/test.zig-37| ... | @@ -962,43 +962,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -962,43 +962,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 962 | , | 962 | , |
| 963 | "hello\nhello\nhello\nhello\nhello\n", | 963 | "hello\nhello\nhello\nhello\nhello\n", |
| 964 | ); | 964 | ); |
| 965 | |||
| 966 | // comptime switch | ||
| 967 | |||
| 968 | // Basic for loop | ||
| 969 | case.addCompareOutput( | ||
| 970 | \\pub export fn _start() noreturn { | ||
| 971 | \\ assert(foo() == 1); | ||
| 972 | \\ exit(); | ||
| 973 | \\} | ||
| 974 | \\ | ||
| 975 | \\fn foo() u32 { | ||
| 976 | \\ const a: comptime_int = 1; | ||
| 977 | \\ var b: u32 = 0; | ||
| 978 | \\ switch (a) { | ||
| 979 | \\ 1 => b = 1, | ||
| 980 | \\ 2 => b = 2, | ||
| 981 | \\ else => unreachable, | ||
| 982 | \\ } | ||
| 983 | \\ return b; | ||
| 984 | \\} | ||
| 985 | \\ | ||
| 986 | \\pub fn assert(ok: bool) void { | ||
| 987 | \\ if (!ok) unreachable; // assertion failure | ||
| 988 | \\} | ||
| 989 | \\ | ||
| 990 | \\fn exit() noreturn { | ||
| 991 | \\ asm volatile ("syscall" | ||
| 992 | \\ : | ||
| 993 | \\ : [number] "{rax}" (231), | ||
| 994 | \\ [arg1] "{rdi}" (0) | ||
| 995 | \\ : "rcx", "r11", "memory" | ||
| 996 | \\ ); | ||
| 997 | \\ unreachable; | ||
| 998 | \\} | ||
| 999 | , | ||
| 1000 | "", | ||
| 1001 | ); | ||
| 1002 | } | 965 | } |
| 1003 | 966 | ||
| 1004 | { | 967 | { |