From 9d6b6bddb60e5a970b1c849c2a0b7a66451f8bc3 Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Fri, 8 Sep 2023 01:19:38 +0200 Subject: [PATCH] wasm: implement common conversions between integers/floats with bitsize larger than 64 bits --- src/arch/wasm/CodeGen.zig | 56 +++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 15eecde5fe..b03d8cf14c 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -4857,11 +4857,31 @@ fn airIntFromFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_op = func.air.instructions.items(.data)[inst].ty_op; const operand = try func.resolveInst(ty_op.operand); - const dest_ty = func.typeOfIndex(inst); const op_ty = func.typeOf(ty_op.operand); + const op_bits = op_ty.floatBits(func.target); - if (op_ty.abiSize(mod) > 8) { - return func.fail("TODO: intFromFloat for integers/floats with bitsize larger than 64 bits", .{}); + const dest_ty = func.typeOfIndex(inst); + const dest_info = dest_ty.intInfo(mod); + + if (dest_info.bits > 128) { + return func.fail("TODO: intFromFloat for integers/floats with bitsize {}", .{dest_info.bits}); + } + + if ((op_bits != 32 and op_bits != 64) or dest_info.bits > 64) { + const dest_bitsize = if (dest_info.bits <= 16) 16 else std.math.ceilPowerOfTwoAssert(u16, dest_info.bits); + + var fn_name_buf: [16]u8 = undefined; + const fn_name = std.fmt.bufPrint(&fn_name_buf, "__fix{s}{s}f{s}i", .{ + switch (dest_info.signedness) { + .signed => "", + .unsigned => "uns", + }, + target_util.compilerRtFloatAbbrev(op_bits), + target_util.compilerRtIntAbbrev(dest_bitsize), + }) catch unreachable; + + const result = try (try func.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand})).toLocal(func, dest_ty); + return func.finishAir(inst, result, &.{ty_op.operand}); } try func.emitWValue(operand); @@ -4869,7 +4889,7 @@ fn airIntFromFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .op = .trunc, .valtype1 = typeToValtype(dest_ty, mod), .valtype2 = typeToValtype(op_ty, mod), - .signedness = if (dest_ty.isSignedInt(mod)) .signed else .unsigned, + .signedness = dest_info.signedness, }); try func.addTag(Mir.Inst.Tag.fromOpcode(op)); const wrapped = try func.wrapOperand(.{ .stack = {} }, dest_ty); @@ -4882,11 +4902,31 @@ fn airFloatFromInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_op = func.air.instructions.items(.data)[inst].ty_op; const operand = try func.resolveInst(ty_op.operand); - const dest_ty = func.typeOfIndex(inst); const op_ty = func.typeOf(ty_op.operand); + const op_info = op_ty.intInfo(mod); - if (op_ty.abiSize(mod) > 8) { - return func.fail("TODO: floatFromInt for integers/floats with bitsize larger than 64 bits", .{}); + const dest_ty = func.typeOfIndex(inst); + const dest_bits = dest_ty.floatBits(func.target); + + if (op_info.bits > 128) { + return func.fail("TODO: floatFromInt for integers/floats with bitsize {d} bits", .{op_info.bits}); + } + + if (op_info.bits > 64 or (dest_bits > 64 or dest_bits < 32)) { + const op_bitsize = if (op_info.bits <= 16) 16 else std.math.ceilPowerOfTwoAssert(u16, op_info.bits); + + var fn_name_buf: [16]u8 = undefined; + const fn_name = std.fmt.bufPrint(&fn_name_buf, "__float{s}{s}i{s}f", .{ + switch (op_info.signedness) { + .signed => "", + .unsigned => "un", + }, + target_util.compilerRtIntAbbrev(op_bitsize), + target_util.compilerRtFloatAbbrev(dest_bits), + }) catch unreachable; + + const result = try (try func.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand})).toLocal(func, dest_ty); + return func.finishAir(inst, result, &.{ty_op.operand}); } try func.emitWValue(operand); @@ -4894,7 +4934,7 @@ fn airFloatFromInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .op = .convert, .valtype1 = typeToValtype(dest_ty, mod), .valtype2 = typeToValtype(op_ty, mod), - .signedness = if (op_ty.isSignedInt(mod)) .signed else .unsigned, + .signedness = op_info.signedness, }); try func.addTag(Mir.Inst.Tag.fromOpcode(op));