authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-02 19:49:34-07:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-05 10:37:08+02:00
logf4ac37f55da7258c25194e66e1cfe3270ca9d419
tree950151f6d2db1620463fe2a3a44faa02b1dfe685
parent6d3586e0edf3278862a3a969debaa842014f8110

Sema: extract out zirTryPtr from zirTry

This function took is_ptr: bool and then branched on it three times. Now, instead, each implementation does no branching and the logic is easier to follow, both for maintainers and compilers. I also fixed a bug with TryPtr not ensuring enough capacity in the extra array.

1 files changed, 63 insertions(+), 46 deletions(-)

src/Sema.zig+63-46
...@@ -1323,7 +1323,7 @@ fn analyzeBodyInner(...@@ -1323,7 +1323,7 @@ fn analyzeBodyInner(
1323 }1323 }
1324 },1324 },
1325 .@"try" => blk: {1325 .@"try" => blk: {
1326 if (!block.is_comptime) break :blk try sema.zirTry(block, inst, false);1326 if (!block.is_comptime) break :blk try sema.zirTry(block, inst);
1327 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1327 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1328 const src = inst_data.src();1328 const src = inst_data.src();
1329 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };1329 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
...@@ -1376,7 +1376,7 @@ fn analyzeBodyInner(...@@ -1376,7 +1376,7 @@ fn analyzeBodyInner(
1376 // }1376 // }
1377 //},1377 //},
1378 .try_ptr => blk: {1378 .try_ptr => blk: {
1379 if (!block.is_comptime) break :blk try sema.zirTry(block, inst, true);1379 if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst);
1380 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1380 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1381 const src = inst_data.src();1381 const src = inst_data.src();
1382 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };1382 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
...@@ -13065,22 +13065,13 @@ fn zirCondbr(...@@ -13065,22 +13065,13 @@ fn zirCondbr(
13065 return always_noreturn;13065 return always_noreturn;
13066}13066}
1306713067
13068fn zirTry(13068fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
13069 sema: *Sema,
13070 parent_block: *Block,
13071 inst: Zir.Inst.Index,
13072 is_ptr: bool,
13073) CompileError!Zir.Inst.Ref {
13074 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;13069 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13075 const src = inst_data.src();13070 const src = inst_data.src();
13076 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };13071 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
13077 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);13072 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
13078 const body = sema.code.extra[extra.end..][0..extra.data.body_len];13073 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
13079 const operand = try sema.resolveInst(extra.data.operand);13074 const err_union = try sema.resolveInst(extra.data.operand);
13080 const err_union = if (is_ptr)
13081 try sema.analyzeLoad(parent_block, src, operand, operand_src)
13082 else
13083 operand;
13084 const err_union_ty = sema.typeOf(err_union);13075 const err_union_ty = sema.typeOf(err_union);
13085 if (err_union_ty.zigTypeTag() != .ErrorUnion) {13076 if (err_union_ty.zigTypeTag() != .ErrorUnion) {
13086 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{13077 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
...@@ -13091,11 +13082,7 @@ fn zirTry(...@@ -13091,11 +13082,7 @@ fn zirTry(
1309113082
13092 if (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)) |is_non_err_val| {13083 if (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)) |is_non_err_val| {
13093 if (is_non_err_val.toBool()) {13084 if (is_non_err_val.toBool()) {
13094 if (is_ptr) {13085 return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false);
13095 return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false);
13096 } else {
13097 return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, operand, operand_src, false);
13098 }
13099 }13086 }
13100 // We can analyze the body directly in the parent block because we know there are13087 // We can analyze the body directly in the parent block because we know there are
13101 // no breaks from the body possible, and that the body is noreturn.13088 // no breaks from the body possible, and that the body is noreturn.
...@@ -13108,39 +13095,12 @@ fn zirTry(...@@ -13108,39 +13095,12 @@ fn zirTry(
13108 // This body is guaranteed to end with noreturn and has no breaks.13095 // This body is guaranteed to end with noreturn and has no breaks.
13109 _ = try sema.analyzeBodyInner(&sub_block, body);13096 _ = try sema.analyzeBodyInner(&sub_block, body);
1311013097
13111 if (is_ptr) {
13112 const operand_ty = sema.typeOf(operand);
13113 const ptr_info = operand_ty.ptrInfo().data;
13114 const res_ty = try Type.ptr(sema.arena, sema.mod, .{
13115 .pointee_type = err_union_ty.errorUnionPayload(),
13116 .@"addrspace" = ptr_info.@"addrspace",
13117 .mutable = ptr_info.mutable,
13118 .@"allowzero" = ptr_info.@"allowzero",
13119 .@"volatile" = ptr_info.@"volatile",
13120 });
13121 const res_ty_ref = try sema.addType(res_ty);
13122 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +
13123 sub_block.instructions.items.len);
13124 const try_inst = try parent_block.addInst(.{
13125 .tag = .try_ptr,
13126 .data = .{ .ty_pl = .{
13127 .ty = res_ty_ref,
13128 .payload = sema.addExtraAssumeCapacity(Air.TryPtr{
13129 .ptr = operand,
13130 .body_len = @intCast(u32, sub_block.instructions.items.len),
13131 }),
13132 } },
13133 });
13134 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
13135 return try_inst;
13136 }
13137
13138 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +13098 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +
13139 sub_block.instructions.items.len);13099 sub_block.instructions.items.len);
13140 const try_inst = try parent_block.addInst(.{13100 const try_inst = try parent_block.addInst(.{
13141 .tag = .@"try",13101 .tag = .@"try",
13142 .data = .{ .pl_op = .{13102 .data = .{ .pl_op = .{
13143 .operand = operand,13103 .operand = err_union,
13144 .payload = sema.addExtraAssumeCapacity(Air.Try{13104 .payload = sema.addExtraAssumeCapacity(Air.Try{
13145 .body_len = @intCast(u32, sub_block.instructions.items.len),13105 .body_len = @intCast(u32, sub_block.instructions.items.len),
13146 }),13106 }),
...@@ -13150,6 +13110,63 @@ fn zirTry(...@@ -13150,6 +13110,63 @@ fn zirTry(
13150 return try_inst;13110 return try_inst;
13151}13111}
1315213112
13113fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
13114 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13115 const src = inst_data.src();
13116 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
13117 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
13118 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
13119 const operand = try sema.resolveInst(extra.data.operand);
13120 const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src);
13121 const err_union_ty = sema.typeOf(err_union);
13122 if (err_union_ty.zigTypeTag() != .ErrorUnion) {
13123 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
13124 err_union_ty.fmt(sema.mod),
13125 });
13126 }
13127 const is_non_err = try sema.analyzeIsNonErr(parent_block, operand_src, err_union);
13128
13129 if (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)) |is_non_err_val| {
13130 if (is_non_err_val.toBool()) {
13131 return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false);
13132 }
13133 // We can analyze the body directly in the parent block because we know there are
13134 // no breaks from the body possible, and that the body is noreturn.
13135 return sema.resolveBody(parent_block, body, inst);
13136 }
13137
13138 var sub_block = parent_block.makeSubBlock();
13139 defer sub_block.instructions.deinit(sema.gpa);
13140
13141 // This body is guaranteed to end with noreturn and has no breaks.
13142 _ = try sema.analyzeBodyInner(&sub_block, body);
13143
13144 const operand_ty = sema.typeOf(operand);
13145 const ptr_info = operand_ty.ptrInfo().data;
13146 const res_ty = try Type.ptr(sema.arena, sema.mod, .{
13147 .pointee_type = err_union_ty.errorUnionPayload(),
13148 .@"addrspace" = ptr_info.@"addrspace",
13149 .mutable = ptr_info.mutable,
13150 .@"allowzero" = ptr_info.@"allowzero",
13151 .@"volatile" = ptr_info.@"volatile",
13152 });
13153 const res_ty_ref = try sema.addType(res_ty);
13154 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).Struct.fields.len +
13155 sub_block.instructions.items.len);
13156 const try_inst = try parent_block.addInst(.{
13157 .tag = .try_ptr,
13158 .data = .{ .ty_pl = .{
13159 .ty = res_ty_ref,
13160 .payload = sema.addExtraAssumeCapacity(Air.TryPtr{
13161 .ptr = operand,
13162 .body_len = @intCast(u32, sub_block.instructions.items.len),
13163 }),
13164 } },
13165 });
13166 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
13167 return try_inst;
13168}
13169
13153// A `break` statement is inside a runtime condition, but trying to13170// A `break` statement is inside a runtime condition, but trying to
13154// break from an inline loop. In such case we must convert it to13171// break from an inline loop. In such case we must convert it to
13155// a runtime break.13172// a runtime break.