Skip to content

Commit

Permalink
wasm: correctly intcast signed integers
Browse files Browse the repository at this point in the history
When a signed integer's bitsize is not 32 or 64, but the given
bitsize and wanted bitsize are either both represented by Wasm's i32
or i64, we must either sign extend or wrap the integer.
  • Loading branch information
Luukdegram committed Jul 22, 2023
1 parent 8924f81 commit 619140c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/arch/wasm/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4160,7 +4160,7 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {

const op_bits = toWasmBits(@as(u16, @intCast(operand_ty.bitSize(mod)))).?;
const wanted_bits = toWasmBits(@as(u16, @intCast(ty.bitSize(mod)))).?;
const result = if (op_bits == wanted_bits)
const result = if (op_bits == wanted_bits and !ty.isSignedInt(mod))
func.reuseOperand(ty_op.operand, operand)
else
try (try func.intcast(operand, operand_ty, ty)).toLocal(func, ty);
Expand All @@ -4181,7 +4181,19 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro

const op_bits = toWasmBits(given_bitsize).?;
const wanted_bits = toWasmBits(wanted_bitsize).?;
if (op_bits == wanted_bits) return operand;
if (op_bits == wanted_bits) {
if (given.isSignedInt(mod)) {
if (given_bitsize < wanted_bitsize) {
// signed integers are stored as two's complement,
// when we upcast from a smaller integer to larger
// integers, we must get its absolute value similar to
// i64_extend_i32_s instruction.
return func.signAbsValue(operand, given);
}
return func.wrapOperand(operand, wanted);
}
return operand;
}

if (op_bits > 32 and op_bits <= 64 and wanted_bits == 32) {
try func.emitWValue(operand);
Expand Down
15 changes: 15 additions & 0 deletions test/behavior/cast_int.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,18 @@ test "@intCast i32 to u7" {
var z = x >> @as(u7, @intCast(y));
try expect(z == 0xff);
}

test "coerce i8 to i32 and @intCast back" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

var x: i8 = -5;
var y: i32 = -5;
try expect(y == x);

var x2: i32 = -5;
var y2: i8 = -5;
try expect(y2 == @as(i8, @intCast(x2)));
}

0 comments on commit 619140c

Please sign in to comment.