@@ -303,14 +303,14 @@ pub const Scope = struct {
303303 switch (self .tag ) {
304304 .block = > return self .cast (Block ).? .arena ,
305305 .decl = > return & self .cast (DeclAnalysis ).? .arena .allocator ,
306- .gen_zir = > return & self .cast (GenZIR ).? .arena . allocator ,
306+ .gen_zir = > return self .cast (GenZIR ).? .arena ,
307307 .zir_module = > return & self .cast (ZIRModule ).? .contents .module .arena .allocator ,
308308 .file = > unreachable ,
309309 }
310310 }
311311
312- /// Asserts the scope has a parent which is a DeclAnalysis and
313- /// returns the Decl.
312+ /// If the scope has a parent which is a ` DeclAnalysis`,
313+ /// returns the ` Decl`, otherwise returns `null` .
314314 pub fn decl (self : * Scope ) ? * Decl {
315315 return switch (self .tag ) {
316316 .block = > self .cast (Block ).? .decl ,
@@ -653,7 +653,7 @@ pub const Scope = struct {
653653 label : ? Label = null ,
654654
655655 pub const Label = struct {
656- name : [] const u8 ,
656+ zir_block : * zir.Inst.Block ,
657657 results : ArrayListUnmanaged (* Inst ),
658658 block_inst : * Inst.Block ,
659659 };
@@ -674,8 +674,8 @@ pub const Scope = struct {
674674 pub const base_tag : Tag = .gen_zir ;
675675 base : Scope = Scope { .tag = base_tag },
676676 decl : * Decl ,
677- arena : std.heap.ArenaAllocator ,
678- instructions : std .ArrayList (* zir .Inst ),
677+ arena : * Allocator ,
678+ instructions : std .ArrayListUnmanaged (* zir .Inst ) = .{} ,
679679 };
680680};
681681
@@ -1115,19 +1115,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11151115 // This arena allocator's memory is discarded at the end of this function. It is used
11161116 // to determine the type of the function, and hence the type of the decl, which is needed
11171117 // to complete the Decl analysis.
1118+ var fn_type_scope_arena = std .heap .ArenaAllocator .init (self .gpa );
1119+ defer fn_type_scope_arena .deinit ();
11181120 var fn_type_scope : Scope.GenZIR = .{
11191121 .decl = decl ,
1120- .arena = std .heap .ArenaAllocator .init (self .gpa ),
1121- .instructions = std .ArrayList (* zir .Inst ).init (self .gpa ),
1122+ .arena = & fn_type_scope_arena .allocator ,
11221123 };
1123- defer fn_type_scope .arena .deinit ();
1124- defer fn_type_scope .instructions .deinit ();
1124+ defer fn_type_scope .instructions .deinit (self .gpa );
11251125
11261126 const body_node = fn_proto .body_node orelse
11271127 return self .failTok (& fn_type_scope .base , fn_proto .fn_token , "TODO implement extern functions" , .{});
11281128
11291129 const param_decls = fn_proto .params ();
1130- const param_types = try fn_type_scope .arena .allocator . alloc (* zir .Inst , param_decls .len );
1130+ const param_types = try fn_type_scope .arena .alloc (* zir .Inst , param_decls .len );
11311131 for (param_decls ) | param_decl , i | {
11321132 const param_type_node = switch (param_decl .param_type ) {
11331133 .var_type = > | node | return self .failNode (& fn_type_scope .base , node , "TODO implement anytype parameter" , .{}),
@@ -1190,24 +1190,24 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11901190 const fn_zir = blk : {
11911191 // This scope's arena memory is discarded after the ZIR generation
11921192 // pass completes, and semantic analysis of it completes.
1193+ var gen_scope_arena = std .heap .ArenaAllocator .init (self .gpa );
1194+ errdefer gen_scope_arena .deinit ();
11931195 var gen_scope : Scope.GenZIR = .{
11941196 .decl = decl ,
1195- .arena = std .heap .ArenaAllocator .init (self .gpa ),
1196- .instructions = std .ArrayList (* zir .Inst ).init (self .gpa ),
1197+ .arena = & gen_scope_arena .allocator ,
11971198 };
1198- errdefer gen_scope .arena .deinit ();
1199- defer gen_scope .instructions .deinit ();
1199+ defer gen_scope .instructions .deinit (self .gpa );
12001200
12011201 const body_block = body_node .cast (ast .Node .Block ).? ;
12021202
12031203 try self .astGenBlock (& gen_scope .base , body_block );
12041204
1205- const fn_zir = try gen_scope . arena .allocator .create (Fn .ZIR );
1205+ const fn_zir = try gen_scope_arena .allocator .create (Fn .ZIR );
12061206 fn_zir .* = .{
12071207 .body = .{
1208- .instructions = try gen_scope .arena .allocator . dupe (* zir .Inst , gen_scope .instructions .items ),
1208+ .instructions = try gen_scope .arena .dupe (* zir .Inst , gen_scope .instructions .items ),
12091209 },
1210- .arena = gen_scope . arena .state ,
1210+ .arena = gen_scope_arena .state ,
12111211 };
12121212 break :blk fn_zir ;
12131213 };
@@ -1351,9 +1351,70 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir
13511351 return self .failNode (scope , payload , "TODO implement astGenIf for error unions" , .{});
13521352 }
13531353 }
1354- const cond = try self .astGenExpr (scope , if_node .condition );
1355- const body = try self .astGenExpr (scope , if_node .condition );
1356- return self .failNode (scope , if_node .condition , "TODO implement astGenIf" , .{});
1354+ var block_scope : Scope.GenZIR = .{
1355+ .decl = scope .decl ().? ,
1356+ .arena = scope .arena (),
1357+ .instructions = .{},
1358+ };
1359+ defer block_scope .instructions .deinit (self .gpa );
1360+
1361+ const cond = try self .astGenExpr (& block_scope .base , if_node .condition );
1362+
1363+ const tree = scope .tree ();
1364+ const if_src = tree .token_locs [if_node .if_token ].start ;
1365+ const condbr = try self .addZIRInstSpecial (& block_scope .base , if_src , zir .Inst .CondBr , .{
1366+ .condition = cond ,
1367+ .true_body = undefined , // populated below
1368+ .false_body = undefined , // populated below
1369+ }, .{});
1370+
1371+ const block = try self .addZIRInstBlock (scope , if_src , .{
1372+ .instructions = try block_scope .arena .dupe (* zir .Inst , block_scope .instructions .items ),
1373+ });
1374+ var then_scope : Scope.GenZIR = .{
1375+ .decl = block_scope .decl ,
1376+ .arena = block_scope .arena ,
1377+ .instructions = .{},
1378+ };
1379+ defer then_scope .instructions .deinit (self .gpa );
1380+
1381+ const then_result = try self .astGenExpr (& then_scope .base , if_node .body );
1382+ const then_src = tree .token_locs [if_node .body .lastToken ()].start ;
1383+ _ = try self .addZIRInst (& then_scope .base , then_src , zir .Inst .Break , .{
1384+ .block = block ,
1385+ .operand = then_result ,
1386+ }, .{});
1387+ condbr .positionals .true_body = .{
1388+ .instructions = try then_scope .arena .dupe (* zir .Inst , then_scope .instructions .items ),
1389+ };
1390+
1391+ var else_scope : Scope.GenZIR = .{
1392+ .decl = block_scope .decl ,
1393+ .arena = block_scope .arena ,
1394+ .instructions = .{},
1395+ };
1396+ defer else_scope .instructions .deinit (self .gpa );
1397+
1398+ if (if_node .@"else" ) | else_node | {
1399+ const else_result = try self .astGenExpr (& else_scope .base , else_node .body );
1400+ const else_src = tree .token_locs [else_node .body .lastToken ()].start ;
1401+ _ = try self .addZIRInst (& else_scope .base , else_src , zir .Inst .Break , .{
1402+ .block = block ,
1403+ .operand = else_result ,
1404+ }, .{});
1405+ } else {
1406+ // TODO Optimization opportunity: we can avoid an allocation and a memcpy here
1407+ // by directly allocating the body for this one instruction.
1408+ const else_src = tree .token_locs [if_node .lastToken ()].start ;
1409+ _ = try self .addZIRInst (& else_scope .base , else_src , zir .Inst .BreakVoid , .{
1410+ .block = block ,
1411+ }, .{});
1412+ }
1413+ condbr .positionals .false_body = .{
1414+ .instructions = try else_scope .arena .dupe (* zir .Inst , else_scope .instructions .items ),
1415+ };
1416+
1417+ return & block .base ;
13571418}
13581419
13591420fn astGenControlFlowExpression (
@@ -1379,12 +1440,12 @@ fn astGenControlFlowExpression(
13791440fn astGenIdent (self : * Module , scope : * Scope , ident : * ast.Node.Identifier ) InnerError ! * zir.Inst {
13801441 const tree = scope .tree ();
13811442 const ident_name = tree .tokenSlice (ident .token );
1443+ const src = tree .token_locs [ident .token ].start ;
13821444 if (mem .eql (u8 , ident_name , "_" )) {
13831445 return self .failNode (scope , & ident .base , "TODO implement '_' identifier" , .{});
13841446 }
13851447
13861448 if (getSimplePrimitiveValue (ident_name )) | typed_value | {
1387- const src = tree .token_locs [ident .token ].start ;
13881449 return self .addZIRInstConst (scope , src , typed_value );
13891450 }
13901451
@@ -1408,7 +1469,6 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
14081469 64 = > if (is_signed ) Value .initTag (.i64_type ) else Value .initTag (.u64_type ),
14091470 else = > return self .failNode (scope , & ident .base , "TODO implement arbitrary integer bitwidth types" , .{}),
14101471 };
1411- const src = tree .token_locs [ident .token ].start ;
14121472 return self .addZIRInstConst (scope , src , .{
14131473 .ty = Type .initTag (.type ),
14141474 .val = val ,
@@ -1417,10 +1477,21 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
14171477 }
14181478
14191479 if (self .lookupDeclName (scope , ident_name )) | decl | {
1420- const src = tree .token_locs [ident .token ].start ;
14211480 return try self .addZIRInst (scope , src , zir .Inst .DeclValInModule , .{ .decl = decl }, .{});
14221481 }
14231482
1483+ // Function parameter
1484+ if (scope .decl ()) | decl | {
1485+ if (tree .root_node .decls ()[decl .src_index ].cast (ast .Node .FnProto )) | fn_proto | {
1486+ for (fn_proto .params ()) | param , i | {
1487+ const param_name = tree .tokenSlice (param .name_token .? );
1488+ if (mem .eql (u8 , param_name , ident_name )) {
1489+ return try self .addZIRInst (scope , src , zir .Inst .Arg , .{ .index = i }, .{});
1490+ }
1491+ }
1492+ }
1493+ }
1494+
14241495 return self .failNode (scope , & ident .base , "TODO implement local variable identifier lookup" , .{});
14251496}
14261497
@@ -1563,7 +1634,7 @@ fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zi
15631634 const lhs = try self .astGenExpr (scope , call .lhs );
15641635
15651636 const param_nodes = call .params ();
1566- const args = try scope .cast (Scope .GenZIR ).? .arena .allocator . alloc (* zir .Inst , param_nodes .len );
1637+ const args = try scope .cast (Scope .GenZIR ).? .arena .alloc (* zir .Inst , param_nodes .len );
15671638 for (param_nodes ) | param_node , i | {
15681639 args [i ] = try self .astGenExpr (scope , param_node );
15691640 }
@@ -2239,7 +2310,7 @@ fn newZIRInst(
22392310 comptime T : type ,
22402311 positionals : std .meta .fieldInfo (T , "positionals" ).field_type ,
22412312 kw_args : std .meta .fieldInfo (T , "kw_args" ).field_type ,
2242- ) ! * zir.Inst {
2313+ ) ! * T {
22432314 const inst = try gpa .create (T );
22442315 inst .* = .{
22452316 .base = .{
@@ -2249,30 +2320,48 @@ fn newZIRInst(
22492320 .positionals = positionals ,
22502321 .kw_args = kw_args ,
22512322 };
2252- return & inst . base ;
2323+ return inst ;
22532324}
22542325
2255- fn addZIRInst (
2326+ fn addZIRInstSpecial (
22562327 self : * Module ,
22572328 scope : * Scope ,
22582329 src : usize ,
22592330 comptime T : type ,
22602331 positionals : std .meta .fieldInfo (T , "positionals" ).field_type ,
22612332 kw_args : std .meta .fieldInfo (T , "kw_args" ).field_type ,
2262- ) ! * zir.Inst {
2333+ ) ! * T {
22632334 const gen_zir = scope .cast (Scope .GenZIR ).? ;
2264- try gen_zir .instructions .ensureCapacity (gen_zir .instructions .items .len + 1 );
2265- const inst = try newZIRInst (& gen_zir .arena . allocator , src , T , positionals , kw_args );
2266- gen_zir .instructions .appendAssumeCapacity (inst );
2335+ try gen_zir .instructions .ensureCapacity (self . gpa , gen_zir .instructions .items .len + 1 );
2336+ const inst = try newZIRInst (gen_zir .arena , src , T , positionals , kw_args );
2337+ gen_zir .instructions .appendAssumeCapacity (& inst . base );
22672338 return inst ;
22682339}
22692340
2341+ fn addZIRInst (
2342+ self : * Module ,
2343+ scope : * Scope ,
2344+ src : usize ,
2345+ comptime T : type ,
2346+ positionals : std .meta .fieldInfo (T , "positionals" ).field_type ,
2347+ kw_args : std .meta .fieldInfo (T , "kw_args" ).field_type ,
2348+ ) ! * zir.Inst {
2349+ const inst_special = try self .addZIRInstSpecial (scope , src , T , positionals , kw_args );
2350+ return & inst_special .base ;
2351+ }
2352+
22702353/// TODO The existence of this function is a workaround for a bug in stage1.
22712354fn addZIRInstConst (self : * Module , scope : * Scope , src : usize , typed_value : TypedValue ) ! * zir.Inst {
22722355 const P = std .meta .fieldInfo (zir .Inst .Const , "positionals" ).field_type ;
22732356 return self .addZIRInst (scope , src , zir .Inst .Const , P { .typed_value = typed_value }, .{});
22742357}
22752358
2359+ /// TODO The existence of this function is a workaround for a bug in stage1.
2360+ fn addZIRInstBlock (self : * Module , scope : * Scope , src : usize , body : zir.Module.Body ) ! * zir.Inst.Block {
2361+ const P = std .meta .fieldInfo (zir .Inst .Block , "positionals" ).field_type ;
2362+ return self .addZIRInstSpecial (scope , src , zir .Inst .Block , P { .body = body }, .{});
2363+ }
2364+
22762365fn addNewInst (self : * Module , block : * Scope.Block , src : usize , ty : Type , comptime T : type ) ! * T {
22772366 const inst = try block .arena .create (T );
22782367 inst .* = .{
@@ -2403,6 +2492,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
24032492 switch (old_inst .tag ) {
24042493 .arg = > return self .analyzeInstArg (scope , old_inst .cast (zir .Inst .Arg ).? ),
24052494 .block = > return self .analyzeInstBlock (scope , old_inst .cast (zir .Inst .Block ).? ),
2495+ .@"break" = > return self .analyzeInstBreak (scope , old_inst .cast (zir .Inst .Break ).? ),
24062496 .breakpoint = > return self .analyzeInstBreakpoint (scope , old_inst .cast (zir .Inst .Breakpoint ).? ),
24072497 .breakvoid = > return self .analyzeInstBreakVoid (scope , old_inst .cast (zir .Inst .BreakVoid ).? ),
24082498 .call = > return self .analyzeInstCall (scope , old_inst .cast (zir .Inst .Call ).? ),
@@ -2559,7 +2649,7 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr
25592649 .arena = parent_block .arena ,
25602650 // TODO @as here is working around a miscompilation compiler bug :(
25612651 .label = @as (? Scope .Block .Label , Scope.Block.Label {
2562- .name = inst . positionals . label ,
2652+ .zir_block = inst ,
25632653 .results = .{},
25642654 .block_inst = block_inst ,
25652655 }),
@@ -2588,25 +2678,39 @@ fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoin
25882678 return self .addNewInstArgs (b , inst .base .src , Type .initTag (.void ), Inst .Breakpoint , {});
25892679}
25902680
2681+ fn analyzeInstBreak (self : * Module , scope : * Scope , inst : * zir.Inst.Break ) InnerError ! * Inst {
2682+ const operand = try self .resolveInst (scope , inst .positionals .operand );
2683+ const block = inst .positionals .block ;
2684+ return self .analyzeBreak (scope , inst .base .src , block , operand );
2685+ }
2686+
25912687fn analyzeInstBreakVoid (self : * Module , scope : * Scope , inst : * zir.Inst.BreakVoid ) InnerError ! * Inst {
2592- const label_name = inst .positionals .label ;
2688+ const block = inst .positionals .block ;
25932689 const void_inst = try self .constVoid (scope , inst .base .src );
2690+ return self .analyzeBreak (scope , inst .base .src , block , void_inst );
2691+ }
25942692
2693+ fn analyzeBreak (
2694+ self : * Module ,
2695+ scope : * Scope ,
2696+ src : usize ,
2697+ zir_block : * zir.Inst.Block ,
2698+ operand : * Inst ,
2699+ ) InnerError ! * Inst {
25952700 var opt_block = scope .cast (Scope .Block );
25962701 while (opt_block ) | block | {
25972702 if (block .label ) | * label | {
2598- if (mem . eql ( u8 , label .name , label_name ) ) {
2599- try label .results .append (self .gpa , void_inst );
2600- const b = try self .requireRuntimeBlock (scope , inst . base . src );
2601- return self .addNewInstArgs (b , inst . base . src , Type .initTag (.noreturn ), Inst .BreakVoid , .{
2703+ if (label .zir_block == zir_block ) {
2704+ try label .results .append (self .gpa , operand );
2705+ const b = try self .requireRuntimeBlock (scope , src );
2706+ return self .addNewInstArgs (b , src , Type .initTag (.noreturn ), Inst .Br , .{
26022707 .block = label .block_inst ,
2708+ .operand = operand ,
26032709 });
26042710 }
26052711 }
26062712 opt_block = block .parent ;
2607- } else {
2608- return self .fail (scope , inst .base .src , "use of undeclared label '{}'" , .{label_name });
2609- }
2713+ } else unreachable ;
26102714}
26112715
26122716fn analyzeInstDeclRefStr (self : * Module , scope : * Scope , inst : * zir.Inst.DeclRefStr ) InnerError ! * Inst {
0 commit comments