authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-22 21:56:38+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-23 21:40:32+01:00
loga9a629f89a1d72130103bd59800e1257af84c97c
tree967ff5eac7b0a8cf355a1c4b525ffbbdc32b1626
parent49051c065120781b6ff78172c447b6307bd01e39
signature Commit is signed but in an unrecognized format.

wasm: Fix switching on errors

Error sets contain the entire global error set. Users are often switching on specific errors only present within that operand. This means that cases are almost always sparse and not contiguous. For this reason, we will instead emit the default case for error values not present in that specific operand error set. This is fine as those cases will never be hit, as prevented by the type system. By still allowing jump tables for those cases, rather than if-else chains, we save runtime cost as well as binary size.

1 files changed, 5 insertions(+), 1 deletions(-)

src/arch/wasm/CodeGen.zig+5-1
......@@ -2452,7 +2452,11 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24522452 if (case_value.integer == value) break :blk @intCast(u32, idx);
24532453 }
24542454 }
2455 break :blk if (has_else_body) case_i else unreachable;
2455 // error sets are almost always sparse so we use the default case
2456 // for errors that are not present in any branch. This is fine as this default
2457 // case will never be hit for those cases but we do save runtime cost and size
2458 // by using a jump table for this instead of if-else chains.
2459 break :blk if (has_else_body or target_ty.zigTypeTag() == .ErrorSet) case_i else unreachable;
24562460 };
24572461 self.mir_extra.appendAssumeCapacity(idx);
24582462 } else if (has_else_body) {