authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-07-24 17:50:26+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-07-24 19:49:25+02:00
log5d98abd5703607884844e8b8165dcc2238389c57
tree49ace4ff6fe1196dbff7e174b62b151f1ceff4bb
parent72149ae7e4a826d1657d82c367596e06ff771734
signature Commit is signed but in an unrecognized format.

Support multi-value prongs


1 files changed, 64 insertions(+), 27 deletions(-)

src/codegen/wasm.zig+64-27
...@@ -979,10 +979,15 @@ pub const Context = struct {...@@ -979,10 +979,15 @@ pub const Context = struct {
979 .valtype1 = try self.typeToValtype(ty),979 .valtype1 = try self.typeToValtype(ty),
980 });980 });
981 try writer.writeByte(wasm.opcode(opcode));981 try writer.writeByte(wasm.opcode(opcode));
982 const int_info = ty.intInfo(self.target);
982 // write constant983 // write constant
983 switch (ty.intInfo(self.target).signedness) {984 switch (int_info.signedness) {
984 .signed => try leb.writeILEB128(writer, value.toSignedInt()),985 .signed => try leb.writeILEB128(writer, value.toSignedInt()),
985 .unsigned => try leb.writeILEB128(writer, value.toUnsignedInt()),986 .unsigned => switch (int_info.bits) {
987 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, value.toUnsignedInt()))),
988 33...64 => try leb.writeILEB128(writer, @bitCast(i64, value.toUnsignedInt())),
989 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),
990 },
986 }991 }
987 },992 },
988 .Bool => {993 .Bool => {
...@@ -1280,13 +1285,15 @@ pub const Context = struct {...@@ -1280,13 +1285,15 @@ pub const Context = struct {
1280 var extra_index: usize = switch_br.end;1285 var extra_index: usize = switch_br.end;
1281 var case_i: u32 = 0;1286 var case_i: u32 = 0;
12821287
1283 // a map that maps each value with its index and body1288 // a list that maps each value with its value and body based on the order inside the list.
1284 var map = std.AutoArrayHashMap(i32, struct {1289 const CaseValue = struct { integer: i32, value: Value };
1285 index: u32,1290 var case_list = try std.ArrayList(struct {
1291 values: []const CaseValue,
1286 body: []const Air.Inst.Index,1292 body: []const Air.Inst.Index,
1287 value: Value,1293 }).initCapacity(self.gpa, switch_br.data.cases_len);
1288 }).init(self.gpa);1294 defer for (case_list.items) |case| {
1289 defer map.deinit();1295 self.gpa.free(case.values);
1296 } else case_list.deinit();
12901297
1291 var lowest: i32 = 0;1298 var lowest: i32 = 0;
1292 var highest: i32 = 0;1299 var highest: i32 = 0;
...@@ -1295,8 +1302,10 @@ pub const Context = struct {...@@ -1295,8 +1302,10 @@ pub const Context = struct {
1295 const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);1302 const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
1296 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];1303 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
1297 extra_index = case.end + items.len + case_body.len;1304 extra_index = case.end + items.len + case_body.len;
1305 const values = try self.gpa.alloc(CaseValue, items.len);
1306 errdefer self.gpa.free(values);
12981307
1299 for (items) |ref| {1308 for (items) |ref, i| {
1300 const item_val = self.air.value(ref).?;1309 const item_val = self.air.value(ref).?;
1301 const int_val: i32 = blk: {1310 const int_val: i32 = blk: {
1302 if (target_ty.intInfo(self.target).signedness == .signed) {1311 if (target_ty.intInfo(self.target).signedness == .signed) {
...@@ -1305,7 +1314,7 @@ pub const Context = struct {...@@ -1305,7 +1314,7 @@ pub const Context = struct {
1305 break :blk @truncate(i32, item_val.toSignedInt());1314 break :blk @truncate(i32, item_val.toSignedInt());
1306 }1315 }
13071316
1308 break :blk @intCast(i32, @truncate(u31, item_val.toUnsignedInt()) - 1);1317 break :blk @bitCast(i32, @truncate(u32, item_val.toUnsignedInt()));
1309 };1318 };
1310 if (int_val < lowest) {1319 if (int_val < lowest) {
1311 lowest = int_val;1320 lowest = int_val;
...@@ -1313,9 +1322,10 @@ pub const Context = struct {...@@ -1313,9 +1322,10 @@ pub const Context = struct {
1313 if (int_val > highest) {1322 if (int_val > highest) {
1314 highest = int_val;1323 highest = int_val;
1315 }1324 }
1316 try map.put(int_val, .{ .index = case_i, .body = case_body, .value = item_val });1325 values[i] = .{ .integer = int_val, .value = item_val };
1317 }1326 }
13181327
1328 case_list.appendAssumeCapacity(.{ .values = values, .body = case_body });
1319 try self.startBlock(.block, blocktype, null);1329 try self.startBlock(.block, blocktype, null);
1320 }1330 }
13211331
...@@ -1350,9 +1360,15 @@ pub const Context = struct {...@@ -1350,9 +1360,15 @@ pub const Context = struct {
1350 const depth = highest - lowest + @boolToInt(has_else_body);1360 const depth = highest - lowest + @boolToInt(has_else_body);
1351 try leb.writeILEB128(self.code.writer(), depth);1361 try leb.writeILEB128(self.code.writer(), depth);
1352 while (lowest <= highest) : (lowest += 1) {1362 while (lowest <= highest) : (lowest += 1) {
1353 const idx = if (map.get(lowest)) |value| blk: {1363 // idx represents the branch we jump to
1354 break :blk value.index;1364 const idx = blk: {
1355 } else if (has_else_body) case_i else unreachable;1365 for (case_list.items) |case, idx| {
1366 for (case.values) |case_value| {
1367 if (case_value.integer == lowest) break :blk @intCast(u32, idx);
1368 }
1369 }
1370 break :blk if (has_else_body) case_i else unreachable;
1371 };
1356 try leb.writeULEB128(self.code.writer(), idx);1372 try leb.writeULEB128(self.code.writer(), idx);
1357 } else if (has_else_body) {1373 } else if (has_else_body) {
1358 try leb.writeULEB128(self.code.writer(), @as(u32, case_i)); // default branch1374 try leb.writeULEB128(self.code.writer(), @as(u32, case_i)); // default branch
...@@ -1368,21 +1384,43 @@ pub const Context = struct {...@@ -1368,21 +1384,43 @@ pub const Context = struct {
1368 break :blk target_ty.intInfo(self.target).signedness;1384 break :blk target_ty.intInfo(self.target).signedness;
1369 };1385 };
13701386
1371 for (map.values()) |val| {1387 for (case_list.items) |case| {
1372 // when sparse, we use if/else-chain, so emit conditional checks1388 // when sparse, we use if/else-chain, so emit conditional checks
1373 if (is_sparse) {1389 if (is_sparse) {
1374 try self.emitWValue(target);1390 // for single value prong we can emit a simple if
1375 try self.emitConstant(val.value, target_ty);1391 if (case.values.len == 1) {
1376 const opcode = buildOpcode(.{1392 try self.emitWValue(target);
1377 .valtype1 = try self.typeToValtype(target_ty),1393 try self.emitConstant(case.values[0].value, target_ty);
1378 .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition.1394 const opcode = buildOpcode(.{
1379 .signedness = signedness,1395 .valtype1 = try self.typeToValtype(target_ty),
1380 });1396 .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition.
1381 try self.code.append(wasm.opcode(opcode));1397 .signedness = signedness,
1382 try self.code.append(wasm.opcode(.br_if));1398 });
1383 try leb.writeULEB128(self.code.writer(), @as(u32, 0));1399 try self.code.append(wasm.opcode(opcode));
1400 try self.code.append(wasm.opcode(.br_if));
1401 try leb.writeULEB128(self.code.writer(), @as(u32, 0));
1402 } else {
1403 // in multi-value prongs we must check if any prongs match the target value.
1404 try self.startBlock(.block, blocktype, null);
1405 for (case.values) |value| {
1406 try self.emitWValue(target);
1407 try self.emitConstant(value.value, target_ty);
1408 const opcode = buildOpcode(.{
1409 .valtype1 = try self.typeToValtype(target_ty),
1410 .op = .eq,
1411 .signedness = signedness,
1412 });
1413 try self.code.append(wasm.opcode(opcode));
1414 try self.code.append(wasm.opcode(.br_if));
1415 try leb.writeULEB128(self.code.writer(), @as(u32, 0));
1416 }
1417 // value did not match any of the prong values
1418 try self.code.append(wasm.opcode(.br));
1419 try leb.writeULEB128(self.code.writer(), @as(u32, 1));
1420 try self.endBlock();
1421 }
1384 }1422 }
1385 try self.genBody(val.body);1423 try self.genBody(case.body);
1386 try self.endBlock();1424 try self.endBlock();
1387 }1425 }
13881426
...@@ -1390,7 +1428,6 @@ pub const Context = struct {...@@ -1390,7 +1428,6 @@ pub const Context = struct {
1390 try self.genBody(else_body);1428 try self.genBody(else_body);
1391 try self.endBlock();1429 try self.endBlock();
1392 }1430 }
1393
1394 return .none;1431 return .none;
1395 }1432 }
13961433