| ... | @@ -3602,11 +3602,6 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO | ... | @@ -3602,11 +3602,6 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3602 | return func.cmpBigInt(lhs, rhs, ty, op); | 3602 | return func.cmpBigInt(lhs, rhs, ty, op); |
| 3603 | } | 3603 | } |
| 3604 | | 3604 | |
| 3605 | // ensure that when we compare pointers, we emit | | |
| 3606 | // the true pointer of a stack value, rather than the stack pointer. | | |
| 3607 | try func.lowerToStack(lhs); | | |
| 3608 | try func.lowerToStack(rhs); | | |
| 3609 | | | |
| 3610 | const signedness: std.builtin.Signedness = blk: { | 3605 | const signedness: std.builtin.Signedness = blk: { |
| 3611 | // by default we tell the operand type is unsigned (i.e. bools and enum values) | 3606 | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 3612 | if (ty.zigTypeTag(mod) != .Int) break :blk .unsigned; | 3607 | if (ty.zigTypeTag(mod) != .Int) break :blk .unsigned; |
| ... | @@ -3614,6 +3609,30 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO | ... | @@ -3614,6 +3609,30 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3614 | // incase of an actual integer, we emit the correct signedness | 3609 | // incase of an actual integer, we emit the correct signedness |
| 3615 | break :blk ty.intInfo(mod).signedness; | 3610 | break :blk ty.intInfo(mod).signedness; |
| 3616 | }; | 3611 | }; |
| | 3612 | const extend_sign = blk: { |
| | 3613 | // do we need to extend the sign bit? |
| | 3614 | if (signedness != .signed) break :blk false; |
| | 3615 | if (op == .eq or op == .neq) break :blk false; |
| | 3616 | const int_bits = ty.intInfo(mod).bits; |
| | 3617 | const wasm_bits = toWasmBits(int_bits) orelse unreachable; |
| | 3618 | break :blk (wasm_bits != int_bits); |
| | 3619 | }; |
| | 3620 | |
| | 3621 | const lhs_wasm = if (extend_sign) |
| | 3622 | try func.signExtendInt(lhs, ty) |
| | 3623 | else |
| | 3624 | lhs; |
| | 3625 | |
| | 3626 | const rhs_wasm = if (extend_sign) |
| | 3627 | try func.signExtendInt(rhs, ty) |
| | 3628 | else |
| | 3629 | rhs; |
| | 3630 | |
| | 3631 | // ensure that when we compare pointers, we emit |
| | 3632 | // the true pointer of a stack value, rather than the stack pointer. |
| | 3633 | try func.lowerToStack(lhs_wasm); |
| | 3634 | try func.lowerToStack(rhs_wasm); |
| | 3635 | |
| 3617 | const opcode: wasm.Opcode = buildOpcode(.{ | 3636 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 3618 | .valtype1 = typeToValtype(ty, mod), | 3637 | .valtype1 = typeToValtype(ty, mod), |
| 3619 | .op = switch (op) { | 3638 | .op = switch (op) { |
| ... | @@ -6920,12 +6939,13 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, | ... | @@ -6920,12 +6939,13 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, |
| 6920 | const int_info = ty.intInfo(mod); | 6939 | const int_info = ty.intInfo(mod); |
| 6921 | const wasm_bits = toWasmBits(int_info.bits).?; | 6940 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 6922 | const is_wasm_bits = wasm_bits == int_info.bits; | 6941 | const is_wasm_bits = wasm_bits == int_info.bits; |
| | 6942 | const ext_ty = if (!is_wasm_bits) try mod.intType(int_info.signedness, wasm_bits) else ty; |
| 6923 | | 6943 | |
| 6924 | var lhs = if (!is_wasm_bits) lhs: { | 6944 | var lhs = if (!is_wasm_bits) lhs: { |
| 6925 | break :lhs try (try func.signExtendInt(lhs_operand, ty)).toLocal(func, ty); | 6945 | break :lhs try (try func.signExtendInt(lhs_operand, ty)).toLocal(func, ext_ty); |
| 6926 | } else lhs_operand; | 6946 | } else lhs_operand; |
| 6927 | var rhs = if (!is_wasm_bits) rhs: { | 6947 | var rhs = if (!is_wasm_bits) rhs: { |
| 6928 | break :rhs try (try func.signExtendInt(rhs_operand, ty)).toLocal(func, ty); | 6948 | break :rhs try (try func.signExtendInt(rhs_operand, ty)).toLocal(func, ext_ty); |
| 6929 | } else rhs_operand; | 6949 | } else rhs_operand; |
| 6930 | | 6950 | |
| 6931 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); | 6951 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); |
| ... | @@ -6941,20 +6961,20 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, | ... | @@ -6941,20 +6961,20 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, |
| 6941 | else => unreachable, | 6961 | else => unreachable, |
| 6942 | }; | 6962 | }; |
| 6943 | | 6963 | |
| 6944 | var bin_result = try (try func.binOp(lhs, rhs, ty, op)).toLocal(func, ty); | 6964 | var bin_result = try (try func.binOp(lhs, rhs, ext_ty, op)).toLocal(func, ext_ty); |
| 6945 | if (!is_wasm_bits) { | 6965 | if (!is_wasm_bits) { |
| 6946 | defer bin_result.free(func); // not returned in this branch | 6966 | defer bin_result.free(func); // not returned in this branch |
| 6947 | defer lhs.free(func); // uses temporary local for absvalue | 6967 | defer lhs.free(func); // uses temporary local for absvalue |
| 6948 | defer rhs.free(func); // uses temporary local for absvalue | 6968 | defer rhs.free(func); // uses temporary local for absvalue |
| 6949 | try func.emitWValue(bin_result); | 6969 | try func.emitWValue(bin_result); |
| 6950 | try func.emitWValue(max_wvalue); | 6970 | try func.emitWValue(max_wvalue); |
| 6951 | _ = try func.cmp(bin_result, max_wvalue, ty, .lt); | 6971 | _ = try func.cmp(bin_result, max_wvalue, ext_ty, .lt); |
| 6952 | try func.addTag(.select); | 6972 | try func.addTag(.select); |
| 6953 | try func.addLabel(.local_set, bin_result.local.value); // re-use local | 6973 | try func.addLabel(.local_set, bin_result.local.value); // re-use local |
| 6954 | | 6974 | |
| 6955 | try func.emitWValue(bin_result); | 6975 | try func.emitWValue(bin_result); |
| 6956 | try func.emitWValue(min_wvalue); | 6976 | try func.emitWValue(min_wvalue); |
| 6957 | _ = try func.cmp(bin_result, min_wvalue, ty, .gt); | 6977 | _ = try func.cmp(bin_result, min_wvalue, ext_ty, .gt); |
| 6958 | try func.addTag(.select); | 6978 | try func.addTag(.select); |
| 6959 | try func.addLabel(.local_set, bin_result.local.value); // re-use local | 6979 | try func.addLabel(.local_set, bin_result.local.value); // re-use local |
| 6960 | return (try func.wrapOperand(bin_result, ty)).toLocal(func, ty); | 6980 | return (try func.wrapOperand(bin_result, ty)).toLocal(func, ty); |
| ... | @@ -7036,12 +7056,13 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7036,12 +7056,13 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7036 | 64 => WValue{ .imm64 = shift_size }, | 7056 | 64 => WValue{ .imm64 = shift_size }, |
| 7037 | else => unreachable, | 7057 | else => unreachable, |
| 7038 | }; | 7058 | }; |
| | 7059 | const ext_ty = try mod.intType(int_info.signedness, wasm_bits); |
| 7039 | | 7060 | |
| 7040 | var shl_res = try (try func.binOp(lhs, shift_value, ty, .shl)).toLocal(func, ty); | 7061 | var shl_res = try (try func.binOp(lhs, shift_value, ext_ty, .shl)).toLocal(func, ext_ty); |
| 7041 | defer shl_res.free(func); | 7062 | defer shl_res.free(func); |
| 7042 | var shl = try (try func.binOp(shl_res, rhs, ty, .shl)).toLocal(func, ty); | 7063 | var shl = try (try func.binOp(shl_res, rhs, ext_ty, .shl)).toLocal(func, ext_ty); |
| 7043 | defer shl.free(func); | 7064 | defer shl.free(func); |
| 7044 | var shr = try (try func.binOp(shl, rhs, ty, .shr)).toLocal(func, ty); | 7065 | var shr = try (try func.binOp(shl, rhs, ext_ty, .shr)).toLocal(func, ext_ty); |
| 7045 | defer shr.free(func); | 7066 | defer shr.free(func); |
| 7046 | | 7067 | |
| 7047 | switch (wasm_bits) { | 7068 | switch (wasm_bits) { |
| ... | @@ -7053,7 +7074,7 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7053,7 +7074,7 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7053 | | 7074 | |
| 7054 | try func.addImm32(std.math.minInt(i32)); | 7075 | try func.addImm32(std.math.minInt(i32)); |
| 7055 | try func.addImm32(std.math.maxInt(i32)); | 7076 | try func.addImm32(std.math.maxInt(i32)); |
| 7056 | _ = try func.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt); | 7077 | _ = try func.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt); |
| 7057 | try func.addTag(.select); | 7078 | try func.addTag(.select); |
| 7058 | }, | 7079 | }, |
| 7059 | 64 => blk: { | 7080 | 64 => blk: { |
| ... | @@ -7064,16 +7085,16 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7064,16 +7085,16 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7064 | | 7085 | |
| 7065 | try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.minInt(i64))))); | 7086 | try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.minInt(i64))))); |
| 7066 | try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.maxInt(i64))))); | 7087 | try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.maxInt(i64))))); |
| 7067 | _ = try func.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt); | 7088 | _ = try func.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt); |
| 7068 | try func.addTag(.select); | 7089 | try func.addTag(.select); |
| 7069 | }, | 7090 | }, |
| 7070 | else => unreachable, | 7091 | else => unreachable, |
| 7071 | } | 7092 | } |
| 7072 | try func.emitWValue(shl); | 7093 | try func.emitWValue(shl); |
| 7073 | _ = try func.cmp(shl_res, shr, ty, .neq); | 7094 | _ = try func.cmp(shl_res, shr, ext_ty, .neq); |
| 7074 | try func.addTag(.select); | 7095 | try func.addTag(.select); |
| 7075 | try func.addLabel(.local_set, result.local.value); | 7096 | try func.addLabel(.local_set, result.local.value); |
| 7076 | var shift_result = try func.binOp(result, shift_value, ty, .shr); | 7097 | var shift_result = try func.binOp(result, shift_value, ext_ty, .shr); |
| 7077 | if (is_signed) { | 7098 | if (is_signed) { |
| 7078 | shift_result = try func.wrapOperand(shift_result, ty); | 7099 | shift_result = try func.wrapOperand(shift_result, ty); |
| 7079 | } | 7100 | } |