Re-enable switch test cases and fix regressions

This commit is contained in:
Luuk de Gram 2021-07-24 19:48:55 +02:00
parent 5d98abd570
commit 30376a82b2
No known key found for this signature in database
GPG Key ID: A8CFE58E4DC7D664
2 changed files with 94 additions and 68 deletions

View File

@ -1084,6 +1084,42 @@ pub const Context = struct {
}
}
/// Returns a `Value` as a signed 32 bit value.
/// It's illegale to provide a value with a type that cannot be represented
/// as an integer value.
fn valueAsI32(self: Context, val: Value, ty: Type) i32 {
switch (ty.zigTypeTag()) {
.Enum => {
if (val.castTag(.enum_field_index)) |field_index| {
switch (ty.tag()) {
.enum_simple => return @bitCast(i32, field_index.data),
.enum_full, .enum_nonexhaustive => {
const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
if (enum_full.values.count() != 0) {
const tag_val = enum_full.values.keys()[field_index.data];
return self.valueAsI32(tag_val, enum_full.tag_ty);
} else return @bitCast(i32, field_index.data);
},
else => unreachable,
}
} else {
var int_tag_buffer: Type.Payload.Bits = undefined;
const int_tag_ty = ty.intTagType(&int_tag_buffer);
return self.valueAsI32(val, int_tag_ty);
}
},
.Int => switch (ty.intInfo(self.target).signedness) {
.signed => return @truncate(i32, val.toSignedInt()),
.unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())),
},
.ErrorSet => {
const error_index = self.global_error_set.get(val.getError().?).?;
return @bitCast(i32, error_index);
},
else => unreachable, // Programmer called this function for an illegal type
}
}
fn airBlock(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const block_ty = try self.genBlockType(self.air.getRefType(ty_pl.ty));
@ -1307,15 +1343,7 @@ pub const Context = struct {
for (items) |ref, i| {
const item_val = self.air.value(ref).?;
const int_val: i32 = blk: {
if (target_ty.intInfo(self.target).signedness == .signed) {
// safe to truncate the values as we only use them when
// the target's bits is 32 or lower.
break :blk @truncate(i32, item_val.toSignedInt());
}
break :blk @bitCast(i32, @truncate(u32, item_val.toUnsignedInt()));
};
const int_val = self.valueAsI32(item_val, target_ty);
if (int_val < lowest) {
lowest = int_val;
}
@ -1334,7 +1362,7 @@ pub const Context = struct {
// When the target is an integer size larger than u32, we have no way to use the value
// as an index, therefore we also use an if/else-chain for those cases.
// TODO: Benchmark this to find a proper value, LLVM seems to draw the line at '40~45'.
const is_sparse = target_ty.intInfo(self.target).bits > 32 or highest - lowest > 50;
const is_sparse = highest - lowest > 50 or target_ty.bitSize(self.target) > 32;
const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
const has_else_body = else_body.len != 0;

View File

@ -479,68 +479,66 @@ pub fn addCases(ctx: *TestContext) !void {
, "30\n");
}
// This test case is disabled until the codegen for switch is reworked
// to take advantage of br_table rather than a series of br_if opcodes.
//{
// var case = ctx.exe("wasm switch", wasi);
{
var case = ctx.exe("wasm switch", wasi);
// case.addCompareOutput(
// \\pub export fn _start() u32 {
// \\ var val: u32 = 1;
// \\ var a: u32 = switch (val) {
// \\ 0, 1 => 2,
// \\ 2 => 3,
// \\ 3 => 4,
// \\ else => 5,
// \\ };
// \\
// \\ return a;
// \\}
// , "2\n");
case.addCompareOutput(
\\pub export fn _start() u32 {
\\ var val: u32 = 1;
\\ var a: u32 = switch (val) {
\\ 0, 1 => 2,
\\ 2 => 3,
\\ 3 => 4,
\\ else => 5,
\\ };
\\
\\ return a;
\\}
, "2\n");
// case.addCompareOutput(
// \\pub export fn _start() u32 {
// \\ var val: u32 = 2;
// \\ var a: u32 = switch (val) {
// \\ 0, 1 => 2,
// \\ 2 => 3,
// \\ 3 => 4,
// \\ else => 5,
// \\ };
// \\
// \\ return a;
// \\}
// , "3\n");
case.addCompareOutput(
\\pub export fn _start() u32 {
\\ var val: u32 = 2;
\\ var a: u32 = switch (val) {
\\ 0, 1 => 2,
\\ 2 => 3,
\\ 3 => 4,
\\ else => 5,
\\ };
\\
\\ return a;
\\}
, "3\n");
// case.addCompareOutput(
// \\pub export fn _start() u32 {
// \\ var val: u32 = 10;
// \\ var a: u32 = switch (val) {
// \\ 0, 1 => 2,
// \\ 2 => 3,
// \\ 3 => 4,
// \\ else => 5,
// \\ };
// \\
// \\ return a;
// \\}
// , "5\n");
case.addCompareOutput(
\\pub export fn _start() u32 {
\\ var val: u32 = 10;
\\ var a: u32 = switch (val) {
\\ 0, 1 => 2,
\\ 2 => 3,
\\ 3 => 4,
\\ else => 5,
\\ };
\\
\\ return a;
\\}
, "5\n");
// case.addCompareOutput(
// \\const MyEnum = enum { One, Two, Three };
// \\
// \\pub export fn _start() u32 {
// \\ var val: MyEnum = .Two;
// \\ var a: u32 = switch (val) {
// \\ .One => 1,
// \\ .Two => 2,
// \\ .Three => 3,
// \\ };
// \\
// \\ return a;
// \\}
// , "2\n");
//}
case.addCompareOutput(
\\const MyEnum = enum { One, Two, Three };
\\
\\pub export fn _start() u32 {
\\ var val: MyEnum = .Two;
\\ var a: u32 = switch (val) {
\\ .One => 1,
\\ .Two => 2,
\\ .Three => 3,
\\ };
\\
\\ return a;
\\}
, "2\n");
}
{
var case = ctx.exe("wasm error unions", wasi);