diff options
| -rw-r--r-- | src/astgen.zig | 118 | ||||
| -rw-r--r-- | src/zir.zig | 19 | ||||
| -rw-r--r-- | src/zir_sema.zig | 11 |
3 files changed, 86 insertions, 62 deletions
diff --git a/src/astgen.zig b/src/astgen.zig index 617937aa82..ee4591ef7c 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -663,11 +663,27 @@ fn varDecl( switch (tree.token_ids[node.mut_token]) { .Keyword_const => { - var resolve_inferred_alloc: ?*zir.Inst = null; // Depending on the type of AST the initialization expression is, we may need an lvalue // or an rvalue as a result location. If it is an rvalue, we can use the instruction as // the variable, no memory location needed. - const result_loc = if (nodeMayNeedMemoryLocation(init_node, scope)) r: { + if (!nodeMayNeedMemoryLocation(init_node, scope)) { + const result_loc: ResultLoc = if (node.getTypeNode()) |type_node| + .{ .ty = try typeExpr(mod, scope, type_node) } + else + .none; + const init_inst = try expr(mod, scope, result_loc, init_node); + const sub_scope = try block_arena.create(Scope.LocalVal); + sub_scope.* = .{ + .parent = scope, + .gen_zir = scope.getGenZIR(), + .name = ident_name, + .inst = init_inst, + }; + return &sub_scope.base; + } + + var resolve_inferred_alloc: ?*zir.Inst = null; + const result_loc = r: { if (node.getTypeNode()) |type_node| { const type_inst = try typeExpr(mod, scope, type_node); const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); @@ -677,11 +693,6 @@ fn varDecl( resolve_inferred_alloc = &alloc.base; break :r ResultLoc{ .inferred_ptr = alloc }; } - } else r: { - if (node.getTypeNode()) |type_node| - break :r ResultLoc{ .ty = try typeExpr(mod, scope, type_node) } - else - break :r .none; }; const init_inst = try expr(mod, scope, result_loc, init_node); if (resolve_inferred_alloc) |inst| { @@ -1718,14 +1729,20 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn switch (strategy) { .break_void => { if (!then_result.tag.isNoReturn()) { - _ = try addZIRNoOp(mod, then_sub_scope, then_src, .break_void); + _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ + .block = block, + }); } if (else_result) |inst| { if (!inst.tag.isNoReturn()) { - _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); + _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ + .block = block, + }); } } else { - _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); + _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ + .block = block, + }); } assert(!elide_store_to_block_ptr_instructions); try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); @@ -1747,7 +1764,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn }); } } else { - _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); + _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ + .block = block, + }); } if (elide_store_to_block_ptr_instructions) { try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); @@ -2728,31 +2747,30 @@ fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError return addZIRUnOp(mod, scope, src, .ptrtoint, operand); } -fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn as( + mod: *Module, + scope: *Scope, + rl: ResultLoc, + call: *ast.Node.BuiltinCall, +) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 2); const tree = scope.tree(); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const dest_type = try typeExpr(mod, scope, params[0]); switch (rl) { - .none => return try expr(mod, scope, .{ .ty = dest_type }, params[1]), - .discard => { + .none, .discard, .ref, .ty => { const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); - _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); - return result; - }, - .ref => { - const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); - return addZIRUnOp(mod, scope, result.src, .ref, result); - }, - .ty => |result_ty| { - const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); - return addZIRBinOp(mod, scope, src, .as, result_ty, result); + return rvalue(mod, scope, rl, result); }, + .ptr => |result_ptr| { - const casted_result_ptr = try addZIRBinOp(mod, scope, src, .coerce_result_ptr, dest_type, result_ptr); - return expr(mod, scope, .{ .ptr = casted_result_ptr }, params[1]); + return asRlPtr(mod, scope, rl, src, result_ptr, params[1], dest_type); }, + .block_ptr => |block_scope| { + return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, params[1], dest_type); + }, + .bitcasted_ptr => |bitcasted_ptr| { // TODO here we should be able to resolve the inference; we now have a type for the result. return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); @@ -2761,13 +2779,47 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I // TODO here we should be able to resolve the inference; we now have a type for the result. return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); }, - .block_ptr => |block_scope| { - const casted_block_ptr = try addZirInstTag(mod, scope, src, .coerce_result_block_ptr, .{ - .dest_type = dest_type, - .block_ptr = block_scope.rl_ptr.?, - }); - return expr(mod, scope, .{ .ptr = casted_block_ptr }, params[1]); - }, + } +} + +fn asRlPtr( + mod: *Module, + scope: *Scope, + rl: ResultLoc, + src: usize, + result_ptr: *zir.Inst, + operand_node: *ast.Node, + dest_type: *zir.Inst, +) InnerError!*zir.Inst { + // Detect whether this expr() call goes into rvalue() to store the result into the + // result location. If it does, elide the coerce_result_ptr instruction + // as well as the store instruction, instead passing the result as an rvalue. + var as_scope: Scope.GenZIR = .{ + .parent = scope, + .decl = scope.ownerDecl().?, + .arena = scope.arena(), + .instructions = .{}, + }; + defer as_scope.instructions.deinit(mod.gpa); + + as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr); + const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); + const parent_zir = &scope.getGenZIR().instructions; + if (as_scope.rvalue_rl_count == 1) { + // Busted! This expression didn't actually need a pointer. + const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; + try parent_zir.ensureCapacity(mod.gpa, expected_len); + for (as_scope.instructions.items) |src_inst| { + switch (src_inst.tag) { + .store_to_block_ptr, .coerce_result_ptr => continue, + else => parent_zir.appendAssumeCapacity(src_inst), + } + } + assert(parent_zir.items.len == expected_len); + return rvalue(mod, scope, rl, result); + } else { + try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); + return result; } } diff --git a/src/zir.zig b/src/zir.zig index 07fc64b65a..651e5ee3dc 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -112,10 +112,6 @@ pub const Inst = struct { /// as type coercion from the new element type to the old element type. /// LHS is destination element type, RHS is result pointer. coerce_result_ptr, - /// This instruction does a `coerce_result_ptr` operation on a `Block`'s - /// result location pointer, whose type is inferred by peer type resolution on the - /// `Block`'s corresponding `break` instructions. - coerce_result_block_ptr, /// Emit an error message and fail compilation. compile_error, /// Log compile time variables and emit an error message. @@ -460,7 +456,6 @@ pub const Inst = struct { .decl_ref => DeclRef, .decl_ref_str => DeclRefStr, .decl_val => DeclVal, - .coerce_result_block_ptr => CoerceResultBlockPtr, .compile_log => CompileLog, .loop => Loop, .@"const" => Const, @@ -531,7 +526,6 @@ pub const Inst = struct { .cmp_gt, .cmp_neq, .coerce_result_ptr, - .coerce_result_block_ptr, .@"const", .dbg_stmt, .decl_ref, @@ -771,17 +765,6 @@ pub const Inst = struct { kw_args: struct {}, }; - pub const CoerceResultBlockPtr = struct { - pub const base_tag = Tag.coerce_result_block_ptr; - base: Inst, - - positionals: struct { - dest_type: *Inst, - block_ptr: *Inst, - }, - kw_args: struct {}, - }; - pub const CompileLog = struct { pub const base_tag = Tag.compile_log; base: Inst, @@ -1464,7 +1447,7 @@ const Writer = struct { TypedValue => return stream.print("TypedValue{{ .ty = {}, .val = {}}}", .{ param.ty, param.val }), *IrModule.Decl => return stream.print("Decl({s})", .{param.name}), *Inst.Block => { - const name = self.block_table.get(param).?; + const name = self.block_table.get(param) orelse "!BADREF!"; return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)}); }, *Inst.Loop => { diff --git a/src/zir_sema.zig b/src/zir_sema.zig index ca8255df94..40ea563bb6 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -43,7 +43,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .breakpoint => return zirBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), .break_void => return zirBreakVoid(mod, scope, old_inst.castTag(.break_void).?), .call => return zirCall(mod, scope, old_inst.castTag(.call).?), - .coerce_result_block_ptr => return zirCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?), .coerce_result_ptr => return zirCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?), .compile_error => return zirCompileError(mod, scope, old_inst.castTag(.compile_error).?), .compile_log => return zirCompileLog(mod, scope, old_inst.castTag(.compile_log).?), @@ -265,16 +264,6 @@ fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError }; } -fn zirCoerceResultBlockPtr( - mod: *Module, - scope: *Scope, - inst: *zir.Inst.CoerceResultBlockPtr, -) InnerError!*Inst { - const tracy = trace(@src()); - defer tracy.end(); - return mod.fail(scope, inst.base.src, "TODO implement zirCoerceResultBlockPtr", .{}); -} - fn zirBitcastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const tracy = trace(@src()); defer tracy.end(); |
