diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-07-23 20:42:25 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-23 20:42:25 -0700 |
| commit | fa95c89a717f283215e9fd3ea0b8ebcd1599a69b (patch) | |
| tree | 8f2a312f2dddb0ddd91b1abd4419f51deb4da0bd /src | |
| parent | 399f4fe7d69723eb94db7e13d2e8ffdc0ce4345b (diff) | |
| parent | ba8522e6c79b5c93cfbd8bdfbecabf8255848624 (diff) | |
| download | zig-fa95c89a717f283215e9fd3ea0b8ebcd1599a69b.tar.gz zig-fa95c89a717f283215e9fd3ea0b8ebcd1599a69b.zip | |
Merge pull request #20758 from pavelverigo/stage2-wasm-compiler-rt-test-pass
stage2-wasm: pass compiler_rt test suite
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 122 |
1 files changed, 116 insertions, 6 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index e1b362ef2e..68b7f72938 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1837,6 +1837,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .sub_sat => func.airSatBinOp(inst, .sub), .sub_wrap => func.airWrapBinOp(inst, .sub), .mul => func.airBinOp(inst, .mul), + .mul_sat => func.airSatMul(inst), .mul_wrap => func.airWrapBinOp(inst, .mul), .div_float, .div_exact => func.airDiv(inst), .div_trunc => func.airDivTrunc(inst), @@ -2002,7 +2003,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .error_set_has_value => func.airErrorSetHasValue(inst), .frame_addr => func.airFrameAddress(inst), - .mul_sat, .assembly, .is_err_ptr, .is_non_err_ptr, @@ -2666,8 +2666,8 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner switch (op) { .mul => return func.callIntrinsic("__multi3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), .div => switch (int_info.signedness) { - .signed => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), - .unsigned => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), + .signed => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), + .unsigned => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), }, .rem => switch (int_info.signedness) { .signed => return func.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), @@ -4378,7 +4378,7 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { else try func.intcast(operand, operand_ty, ty); - return func.finishAir(inst, result, &.{}); + return func.finishAir(inst, result, &.{ty_op.operand}); } /// Upcasts or downcasts an integer based on the given and wanted types, @@ -4677,10 +4677,20 @@ fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try func.resolveInst(ty_op.operand); - const wanted_ty = ty_op.ty.toType(); + const wanted_ty: Type = ty_op.ty.toType(); const op_ty = func.typeOf(ty_op.operand); + const pt = func.pt; + const mod = pt.zcu; + + if (wanted_ty.zigTypeTag(mod) == .Vector or op_ty.zigTypeTag(mod) == .Vector) { + return func.fail("TODO: trunc for vectors", .{}); + } + + const result = if (op_ty.bitSize(pt) == wanted_ty.bitSize(pt)) + func.reuseOperand(ty_op.operand, operand) + else + try func.trunc(operand, wanted_ty, op_ty); - const result = try func.trunc(operand, wanted_ty, op_ty); return func.finishAir(inst, result, &.{ty_op.operand}); } @@ -6783,6 +6793,106 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs }); } +fn airSatMul(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { + const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; + + const pt = func.pt; + const mod = pt.zcu; + const ty = func.typeOfIndex(inst); + const int_info = ty.intInfo(mod); + const is_signed = int_info.signedness == .signed; + + const lhs = try func.resolveInst(bin_op.lhs); + const rhs = try func.resolveInst(bin_op.rhs); + const wasm_bits = toWasmBits(int_info.bits) orelse { + return func.fail("TODO: mul_sat for {}", .{ty.fmt(pt)}); + }; + + switch (wasm_bits) { + 32 => { + const upcast_ty: Type = if (is_signed) Type.i64 else Type.u64; + const lhs_up = try func.intcast(lhs, ty, upcast_ty); + const rhs_up = try func.intcast(rhs, ty, upcast_ty); + var mul_res = try (try func.binOp(lhs_up, rhs_up, upcast_ty, .mul)).toLocal(func, upcast_ty); + defer mul_res.free(func); + if (is_signed) { + const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - (int_info.bits - 1)) }; + try func.emitWValue(mul_res); + try func.emitWValue(imm_max); + _ = try func.cmp(mul_res, imm_max, upcast_ty, .lt); + try func.addTag(.select); + + var tmp = try func.allocLocal(upcast_ty); + defer tmp.free(func); + try func.addLabel(.local_set, tmp.local.value); + + const imm_min: WValue = .{ .imm64 = ~@as(u64, 0) << @intCast(int_info.bits - 1) }; + try func.emitWValue(tmp); + try func.emitWValue(imm_min); + _ = try func.cmp(tmp, imm_min, upcast_ty, .gt); + try func.addTag(.select); + } else { + const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - int_info.bits) }; + try func.emitWValue(mul_res); + try func.emitWValue(imm_max); + _ = try func.cmp(mul_res, imm_max, upcast_ty, .lt); + try func.addTag(.select); + } + try func.addTag(.i32_wrap_i64); + }, + 64 => { + if (!(int_info.bits == 64 and int_info.signedness == .signed)) { + return func.fail("TODO: mul_sat for {}", .{ty.fmt(pt)}); + } + const overflow_ret = try func.allocStack(Type.i32); + _ = try func.callIntrinsic( + "__mulodi4", + &[_]InternPool.Index{ .i64_type, .i64_type, .usize_type }, + Type.i64, + &.{ lhs, rhs, overflow_ret }, + ); + const xor = try func.binOp(lhs, rhs, Type.i64, .xor); + const sign_v = try func.binOp(xor, .{ .imm64 = 63 }, Type.i64, .shr); + _ = try func.binOp(sign_v, .{ .imm64 = ~@as(u63, 0) }, Type.i64, .xor); + _ = try func.load(overflow_ret, Type.i32, 0); + try func.addTag(.i32_eqz); + try func.addTag(.select); + }, + 128 => { + if (!(int_info.bits == 128 and int_info.signedness == .signed)) { + return func.fail("TODO: mul_sat for {}", .{ty.fmt(pt)}); + } + const overflow_ret = try func.allocStack(Type.i32); + const ret = try func.callIntrinsic( + "__muloti4", + &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type }, + Type.i128, + &.{ lhs, rhs, overflow_ret }, + ); + try func.lowerToStack(ret); + const xor = try func.binOp(lhs, rhs, Type.i128, .xor); + const sign_v = try func.binOp(xor, .{ .imm32 = 127 }, Type.i128, .shr); + + // xor ~@as(u127, 0) + try func.emitWValue(sign_v); + const lsb = try func.load(sign_v, Type.u64, 0); + _ = try func.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); + try func.store(.stack, .stack, Type.u64, sign_v.offset()); + try func.emitWValue(sign_v); + const msb = try func.load(sign_v, Type.u64, 8); + _ = try func.binOp(msb, .{ .imm64 = ~@as(u63, 0) }, Type.u64, .xor); + try func.store(.stack, .stack, Type.u64, sign_v.offset() + 8); + + try func.lowerToStack(sign_v); + _ = try func.load(overflow_ret, Type.i32, 0); + try func.addTag(.i32_eqz); + try func.addTag(.select); + }, + else => unreachable, + } + return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs }); +} + fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { assert(op == .add or op == .sub); const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
