authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-07 21:10:31+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 13:53:10-07:00
log557f396f613a416e81116f85c080af8b976fe8cf
tree8d3c5564d6bbefde4cd04f2dc670bc726ec0ef95
parentb936fe0a5855872814c9f70f958363f64896217b

wasm: Improve switch implementation

- Implement switching over booleans and pointers. - Fix sparse-detection where the lowest value was never truly set as it started at a non-zero number and the case was > 50. - Fix indexing the jump table by ensuring it starts indexing from 0.

1 files changed, 18 insertions(+), 8 deletions(-)

src/arch/wasm/CodeGen.zig+18-8
......@@ -1886,6 +1886,8 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 {
18861886 const kv = self.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
18871887 return @bitCast(i32, kv.value);
18881888 },
1889 .Bool => return @intCast(i32, val.toSignedInt()),
1890 .Pointer => return @intCast(i32, val.toSignedInt()),
18891891 else => unreachable, // Programmer called this function for an illegal type
18901892 }
18911893}
......@@ -2164,8 +2166,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
21642166 self.gpa.free(case.values);
21652167 } else case_list.deinit();
21662168
2167 var lowest: i32 = 0;
2168 var highest: i32 = 0;
2169 var lowest_maybe: ?i32 = null;
2170 var highest_maybe: ?i32 = null;
21692171 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
21702172 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
21712173 const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
......@@ -2177,11 +2179,11 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
21772179 for (items) |ref, i| {
21782180 const item_val = self.air.value(ref).?;
21792181 const int_val = self.valueAsI32(item_val, target_ty);
2180 if (int_val < lowest) {
2181 lowest = int_val;
2182 if (lowest_maybe == null or int_val < lowest_maybe.?) {
2183 lowest_maybe = int_val;
21822184 }
2183 if (int_val > highest) {
2184 highest = int_val;
2185 if (highest_maybe == null or int_val > highest_maybe.?) {
2186 highest_maybe = int_val;
21852187 }
21862188 values[i] = .{ .integer = int_val, .value = item_val };
21872189 }
......@@ -2190,6 +2192,9 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
21902192 try self.startBlock(.block, blocktype);
21912193 }
21922194
2195 // When highest and lowest are null, we have no cases and can use a jump table
2196 const lowest = lowest_maybe orelse 0;
2197 const highest = highest_maybe orelse 0;
21932198 // When the highest and lowest values are seperated by '50',
21942199 // we define it as sparse and use an if/else-chain, rather than a jump table.
21952200 // When the target is an integer size larger than u32, we have no way to use the value
......@@ -2215,6 +2220,10 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22152220 // we put inside, are atleast 0.
22162221 try self.addImm32(lowest * -1);
22172222 try self.addTag(.i32_add);
2223 } else if (lowest > 0) {
2224 // make the index start from 0 by substracting the lowest value
2225 try self.addImm32(lowest);
2226 try self.addTag(.i32_sub);
22182227 }
22192228
22202229 // Account for default branch so always add '1'
......@@ -2223,12 +2232,13 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22232232 const table_extra_index = try self.addExtra(jump_table);
22242233 try self.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
22252234 try self.mir_extra.ensureUnusedCapacity(self.gpa, depth);
2226 while (lowest <= highest) : (lowest += 1) {
2235 var value = lowest;
2236 while (value <= highest) : (value += 1) {
22272237 // idx represents the branch we jump to
22282238 const idx = blk: {
22292239 for (case_list.items) |case, idx| {
22302240 for (case.values) |case_value| {
2231 if (case_value.integer == lowest) break :blk @intCast(u32, idx);
2241 if (case_value.integer == value) break :blk @intCast(u32, idx);
22322242 }
22332243 }
22342244 break :blk if (has_else_body) case_i else unreachable;