| ... | @@ -2325,14 +2325,19 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void | ... | @@ -2325,14 +2325,19 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 2325 | WValue{ .imm32 = @as(u32, @truncate(mask)) } | 2325 | WValue{ .imm32 = @as(u32, @truncate(mask)) } |
| 2326 | else | 2326 | else |
| 2327 | WValue{ .imm64 = mask }; | 2327 | WValue{ .imm64 = mask }; |
| | 2328 | const wrap_mask_val = if (ptr_info.packed_offset.host_size <= 4) |
| | 2329 | WValue{ .imm32 = @truncate(~@as(u64, 0) >> @intCast(64 - ty.bitSize(mod))) } |
| | 2330 | else |
| | 2331 | WValue{ .imm64 = ~@as(u64, 0) >> @intCast(64 - ty.bitSize(mod)) }; |
| 2328 | | 2332 | |
| 2329 | try func.emitWValue(lhs); | 2333 | try func.emitWValue(lhs); |
| 2330 | const loaded = try func.load(lhs, int_elem_ty, 0); | 2334 | const loaded = try func.load(lhs, int_elem_ty, 0); |
| 2331 | const anded = try func.binOp(loaded, mask_val, int_elem_ty, .@"and"); | 2335 | const anded = try func.binOp(loaded, mask_val, int_elem_ty, .@"and"); |
| 2332 | const extended_value = try func.intcast(rhs, ty, int_elem_ty); | 2336 | const extended_value = try func.intcast(rhs, ty, int_elem_ty); |
| | 2337 | const masked_value = try func.binOp(extended_value, wrap_mask_val, int_elem_ty, .@"and"); |
| 2333 | const shifted_value = if (ptr_info.packed_offset.bit_offset > 0) shifted: { | 2338 | const shifted_value = if (ptr_info.packed_offset.bit_offset > 0) shifted: { |
| 2334 | break :shifted try func.binOp(extended_value, shift_val, int_elem_ty, .shl); | 2339 | break :shifted try func.binOp(masked_value, shift_val, int_elem_ty, .shl); |
| 2335 | } else extended_value; | 2340 | } else masked_value; |
| 2336 | const result = try func.binOp(anded, shifted_value, int_elem_ty, .@"or"); | 2341 | const result = try func.binOp(anded, shifted_value, int_elem_ty, .@"or"); |
| 2337 | // lhs is still on the stack | 2342 | // lhs is still on the stack |
| 2338 | try func.store(.stack, result, int_elem_ty, lhs.offset()); | 2343 | try func.store(.stack, result, int_elem_ty, lhs.offset()); |
| ... | @@ -2515,7 +2520,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu | ... | @@ -2515,7 +2520,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2515 | .valtype1 = typeToValtype(ty, mod), | 2520 | .valtype1 = typeToValtype(ty, mod), |
| 2516 | .width = abi_size * 8, | 2521 | .width = abi_size * 8, |
| 2517 | .op = .load, | 2522 | .op = .load, |
| 2518 | .signedness = .unsigned, | 2523 | .signedness = if (ty.isSignedInt(mod)) .signed else .unsigned, |
| 2519 | }); | 2524 | }); |
| 2520 | | 2525 | |
| 2521 | try func.addMemArg( | 2526 | try func.addMemArg( |
| ... | @@ -2800,10 +2805,7 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2800,10 +2805,7 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2800 | switch (wasm_bits) { | 2805 | switch (wasm_bits) { |
| 2801 | 32 => { | 2806 | 32 => { |
| 2802 | try func.emitWValue(operand); | 2807 | try func.emitWValue(operand); |
| 2803 | if (wasm_bits != int_bits) { | 2808 | |
| 2804 | try func.addImm32(wasm_bits - int_bits); | | |
| 2805 | try func.addTag(.i32_shl); | | |
| 2806 | } | | |
| 2807 | try func.addImm32(31); | 2809 | try func.addImm32(31); |
| 2808 | try func.addTag(.i32_shr_s); | 2810 | try func.addTag(.i32_shr_s); |
| 2809 | | 2811 | |
| ... | @@ -2815,15 +2817,10 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2815,15 +2817,10 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2815 | try func.addTag(.i32_xor); | 2817 | try func.addTag(.i32_xor); |
| 2816 | try func.emitWValue(tmp); | 2818 | try func.emitWValue(tmp); |
| 2817 | try func.addTag(.i32_sub); | 2819 | try func.addTag(.i32_sub); |
| 2818 | | | |
| 2819 | _ = try func.wrapOperand(.stack, ty); | | |
| 2820 | }, | 2820 | }, |
| 2821 | 64 => { | 2821 | 64 => { |
| 2822 | try func.emitWValue(operand); | 2822 | try func.emitWValue(operand); |
| 2823 | if (wasm_bits != int_bits) { | 2823 | |
| 2824 | try func.addImm64(wasm_bits - int_bits); | | |
| 2825 | try func.addTag(.i64_shl); | | |
| 2826 | } | | |
| 2827 | try func.addImm64(63); | 2824 | try func.addImm64(63); |
| 2828 | try func.addTag(.i64_shr_s); | 2825 | try func.addTag(.i64_shr_s); |
| 2829 | | 2826 | |
| ... | @@ -2835,8 +2832,6 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2835,8 +2832,6 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2835 | try func.addTag(.i64_xor); | 2832 | try func.addTag(.i64_xor); |
| 2836 | try func.emitWValue(tmp); | 2833 | try func.emitWValue(tmp); |
| 2837 | try func.addTag(.i64_sub); | 2834 | try func.addTag(.i64_sub); |
| 2838 | | | |
| 2839 | _ = try func.wrapOperand(.stack, ty); | | |
| 2840 | }, | 2835 | }, |
| 2841 | 128 => { | 2836 | 128 => { |
| 2842 | const mask = try func.allocStack(Type.u128); | 2837 | const mask = try func.allocStack(Type.u128); |
| ... | @@ -2844,10 +2839,6 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2844,10 +2839,6 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2844 | try func.emitWValue(mask); | 2839 | try func.emitWValue(mask); |
| 2845 | | 2840 | |
| 2846 | _ = try func.load(operand, Type.u64, 8); | 2841 | _ = try func.load(operand, Type.u64, 8); |
| 2847 | if (int_bits != 128) { | | |
| 2848 | try func.addImm64(128 - int_bits); | | |
| 2849 | try func.addTag(.i64_shl); | | |
| 2850 | } | | |
| 2851 | try func.addImm64(63); | 2842 | try func.addImm64(63); |
| 2852 | try func.addTag(.i64_shr_s); | 2843 | try func.addTag(.i64_shr_s); |
| 2853 | | 2844 | |
| ... | @@ -2860,9 +2851,8 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2860,9 +2851,8 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2860 | | 2851 | |
| 2861 | const a = try func.binOpBigInt(operand, mask, Type.u128, .xor); | 2852 | const a = try func.binOpBigInt(operand, mask, Type.u128, .xor); |
| 2862 | const b = try func.binOpBigInt(a, mask, Type.u128, .sub); | 2853 | const b = try func.binOpBigInt(a, mask, Type.u128, .sub); |
| 2863 | const result = try func.wrapOperand(b, ty); | | |
| 2864 | | 2854 | |
| 2865 | func.finishAir(inst, result, &.{ty_op.operand}); | 2855 | func.finishAir(inst, b, &.{ty_op.operand}); |
| 2866 | return; | 2856 | return; |
| 2867 | }, | 2857 | }, |
| 2868 | else => unreachable, | 2858 | else => unreachable, |
| ... | @@ -3058,14 +3048,28 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -3058,14 +3048,28 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 3058 | switch (wasm_bits) { | 3048 | switch (wasm_bits) { |
| 3059 | 32 => { | 3049 | 32 => { |
| 3060 | try func.emitWValue(operand); | 3050 | try func.emitWValue(operand); |
| 3061 | try func.addImm32((@as(u32, 1) << @intCast(int_bits)) - 1); | 3051 | if (ty.isSignedInt(mod)) { |
| 3062 | try func.addTag(.i32_and); | 3052 | try func.addImm32(32 - int_bits); |
| | 3053 | try func.addTag(.i32_shl); |
| | 3054 | try func.addImm32(32 - int_bits); |
| | 3055 | try func.addTag(.i32_shr_s); |
| | 3056 | } else { |
| | 3057 | try func.addImm32(~@as(u32, 0) >> @intCast(32 - int_bits)); |
| | 3058 | try func.addTag(.i32_and); |
| | 3059 | } |
| 3063 | return .stack; | 3060 | return .stack; |
| 3064 | }, | 3061 | }, |
| 3065 | 64 => { | 3062 | 64 => { |
| 3066 | try func.emitWValue(operand); | 3063 | try func.emitWValue(operand); |
| 3067 | try func.addImm64((@as(u64, 1) << @intCast(int_bits)) - 1); | 3064 | if (ty.isSignedInt(mod)) { |
| 3068 | try func.addTag(.i64_and); | 3065 | try func.addImm64(64 - int_bits); |
| | 3066 | try func.addTag(.i64_shl); |
| | 3067 | try func.addImm64(64 - int_bits); |
| | 3068 | try func.addTag(.i64_shr_s); |
| | 3069 | } else { |
| | 3070 | try func.addImm64(~@as(u64, 0) >> @intCast(64 - int_bits)); |
| | 3071 | try func.addTag(.i64_and); |
| | 3072 | } |
| 3069 | return .stack; | 3073 | return .stack; |
| 3070 | }, | 3074 | }, |
| 3071 | 128 => { | 3075 | 128 => { |
| ... | @@ -3078,8 +3082,15 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -3078,8 +3082,15 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 3078 | | 3082 | |
| 3079 | try func.emitWValue(result); | 3083 | try func.emitWValue(result); |
| 3080 | _ = try func.load(operand, Type.u64, 8); | 3084 | _ = try func.load(operand, Type.u64, 8); |
| 3081 | try func.addImm64((@as(u64, 1) << @intCast(int_bits - 64)) - 1); | 3085 | if (ty.isSignedInt(mod)) { |
| 3082 | try func.addTag(.i64_and); | 3086 | try func.addImm64(128 - int_bits); |
| | 3087 | try func.addTag(.i64_shl); |
| | 3088 | try func.addImm64(128 - int_bits); |
| | 3089 | try func.addTag(.i64_shr_s); |
| | 3090 | } else { |
| | 3091 | try func.addImm64(~@as(u64, 0) >> @intCast(128 - int_bits)); |
| | 3092 | try func.addTag(.i64_and); |
| | 3093 | } |
| 3083 | try func.store(.stack, .stack, Type.u64, result.offset() + 8); | 3094 | try func.store(.stack, .stack, Type.u64, result.offset() + 8); |
| 3084 | | 3095 | |
| 3085 | return result; | 3096 | return result; |
| ... | @@ -3201,22 +3212,6 @@ fn lowerDeclRefValue(func: *CodeGen, decl_index: InternPool.DeclIndex, offset: u | ... | @@ -3201,22 +3212,6 @@ fn lowerDeclRefValue(func: *CodeGen, decl_index: InternPool.DeclIndex, offset: u |
| 3201 | } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } }; | 3212 | } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } }; |
| 3202 | } | 3213 | } |
| 3203 | | 3214 | |
| 3204 | /// Converts a signed integer to its 2's complement form and returns | | |
| 3205 | /// an unsigned integer instead. | | |
| 3206 | /// Asserts bitsize <= 64 | | |
| 3207 | fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(@TypeOf(value)).Int.bits) { | | |
| 3208 | const T = @TypeOf(value); | | |
| 3209 | comptime assert(@typeInfo(T) == .Int); | | |
| 3210 | comptime assert(@typeInfo(T).Int.signedness == .signed); | | |
| 3211 | assert(bits <= 64); | | |
| 3212 | const WantedT = std.meta.Int(.unsigned, @typeInfo(T).Int.bits); | | |
| 3213 | if (value >= 0) return @as(WantedT, @bitCast(value)); | | |
| 3214 | const max_value = @as(u64, @intCast((@as(u65, 1) << bits) - 1)); | | |
| 3215 | const flipped = @as(T, @intCast((~-@as(i65, value)) + 1)); | | |
| 3216 | const result = @as(WantedT, @bitCast(flipped)) & max_value; | | |
| 3217 | return @as(WantedT, @intCast(result)); | | |
| 3218 | } | | |
| 3219 | | | |
| 3220 | /// Asserts that `isByRef` returns `false` for `ty`. | 3215 | /// Asserts that `isByRef` returns `false` for `ty`. |
| 3221 | fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { | 3216 | fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3222 | const mod = func.bin_file.base.comp.module.?; | 3217 | const mod = func.bin_file.base.comp.module.?; |
| ... | @@ -3268,18 +3263,12 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { | ... | @@ -3268,18 +3263,12 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3268 | const int_info = ty.intInfo(mod); | 3263 | const int_info = ty.intInfo(mod); |
| 3269 | switch (int_info.signedness) { | 3264 | switch (int_info.signedness) { |
| 3270 | .signed => switch (int_info.bits) { | 3265 | .signed => switch (int_info.bits) { |
| 3271 | 0...32 => return WValue{ .imm32 = @as(u32, @intCast(toTwosComplement( | 3266 | 0...32 => return WValue{ .imm32 = @bitCast(@as(i32, @intCast(val.toSignedInt(mod)))) }, |
| 3272 | val.toSignedInt(mod), | 3267 | 33...64 => return WValue{ .imm64 = @bitCast(val.toSignedInt(mod)) }, |
| 3273 | @as(u6, @intCast(int_info.bits)), | | |
| 3274 | ))) }, | | |
| 3275 | 33...64 => return WValue{ .imm64 = toTwosComplement( | | |
| 3276 | val.toSignedInt(mod), | | |
| 3277 | @as(u7, @intCast(int_info.bits)), | | |
| 3278 | ) }, | | |
| 3279 | else => unreachable, | 3268 | else => unreachable, |
| 3280 | }, | 3269 | }, |
| 3281 | .unsigned => switch (int_info.bits) { | 3270 | .unsigned => switch (int_info.bits) { |
| 3282 | 0...32 => return WValue{ .imm32 = @as(u32, @intCast(val.toUnsignedInt(mod))) }, | 3271 | 0...32 => return WValue{ .imm32 = @intCast(val.toUnsignedInt(mod)) }, |
| 3283 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(mod) }, | 3272 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(mod) }, |
| 3284 | else => unreachable, | 3273 | else => unreachable, |
| 3285 | }, | 3274 | }, |
| ... | @@ -3618,29 +3607,11 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO | ... | @@ -3618,29 +3607,11 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3618 | // incase of an actual integer, we emit the correct signedness | 3607 | // incase of an actual integer, we emit the correct signedness |
| 3619 | break :blk ty.intInfo(mod).signedness; | 3608 | break :blk ty.intInfo(mod).signedness; |
| 3620 | }; | 3609 | }; |
| 3621 | const extend_sign = blk: { | | |
| 3622 | // do we need to extend the sign bit? | | |
| 3623 | if (signedness != .signed) break :blk false; | | |
| 3624 | if (op == .eq or op == .neq) break :blk false; | | |
| 3625 | const int_bits = ty.intInfo(mod).bits; | | |
| 3626 | const wasm_bits = toWasmBits(int_bits) orelse unreachable; | | |
| 3627 | break :blk (wasm_bits != int_bits); | | |
| 3628 | }; | | |
| 3629 | | | |
| 3630 | const lhs_wasm = if (extend_sign) | | |
| 3631 | try func.signExtendInt(lhs, ty) | | |
| 3632 | else | | |
| 3633 | lhs; | | |
| 3634 | | | |
| 3635 | const rhs_wasm = if (extend_sign) | | |
| 3636 | try func.signExtendInt(rhs, ty) | | |
| 3637 | else | | |
| 3638 | rhs; | | |
| 3639 | | 3610 | |
| 3640 | // ensure that when we compare pointers, we emit | 3611 | // ensure that when we compare pointers, we emit |
| 3641 | // the true pointer of a stack value, rather than the stack pointer. | 3612 | // the true pointer of a stack value, rather than the stack pointer. |
| 3642 | try func.lowerToStack(lhs_wasm); | 3613 | try func.lowerToStack(lhs); |
| 3643 | try func.lowerToStack(rhs_wasm); | 3614 | try func.lowerToStack(rhs); |
| 3644 | | 3615 | |
| 3645 | const opcode: wasm.Opcode = buildOpcode(.{ | 3616 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 3646 | .valtype1 = typeToValtype(ty, mod), | 3617 | .valtype1 = typeToValtype(ty, mod), |
| ... | @@ -3812,25 +3783,44 @@ fn airUnreachable(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3812,25 +3783,44 @@ fn airUnreachable(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3812 | } | 3783 | } |
| 3813 | | 3784 | |
| 3814 | fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3785 | fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| | 3786 | const mod = func.bin_file.base.comp.module.?; |
| 3815 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3787 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| | 3788 | const operand = try func.resolveInst(ty_op.operand); |
| | 3789 | const wanted_ty = func.typeOfIndex(inst); |
| | 3790 | const given_ty = func.typeOf(ty_op.operand); |
| | 3791 | |
| | 3792 | const bit_size = given_ty.bitSize(mod); |
| | 3793 | const needs_wrapping = (given_ty.isSignedInt(mod) != wanted_ty.isSignedInt(mod)) and |
| | 3794 | bit_size != 32 and bit_size != 64 and bit_size != 128; |
| | 3795 | |
| 3816 | const result = result: { | 3796 | const result = result: { |
| 3817 | const operand = try func.resolveInst(ty_op.operand); | | |
| 3818 | const wanted_ty = func.typeOfIndex(inst); | | |
| 3819 | const given_ty = func.typeOf(ty_op.operand); | | |
| 3820 | if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) { | 3797 | if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) { |
| 3821 | const bitcast_result = try func.bitcast(wanted_ty, given_ty, operand); | 3798 | const bitcast_result = try func.bitcast(wanted_ty, given_ty, operand); |
| 3822 | break :result try bitcast_result.toLocal(func, wanted_ty); | 3799 | break :result try bitcast_result.toLocal(func, wanted_ty); |
| 3823 | } | 3800 | } |
| 3824 | const mod = func.bin_file.base.comp.module.?; | 3801 | |
| 3825 | if (isByRef(given_ty, mod) and !isByRef(wanted_ty, mod)) { | 3802 | if (isByRef(given_ty, mod) and !isByRef(wanted_ty, mod)) { |
| 3826 | const loaded_memory = try func.load(operand, wanted_ty, 0); | 3803 | const loaded_memory = try func.load(operand, wanted_ty, 0); |
| 3827 | break :result try loaded_memory.toLocal(func, wanted_ty); | 3804 | if (needs_wrapping) { |
| | 3805 | break :result try (try func.wrapOperand(loaded_memory, wanted_ty)).toLocal(func, wanted_ty); |
| | 3806 | } else { |
| | 3807 | break :result try loaded_memory.toLocal(func, wanted_ty); |
| | 3808 | } |
| 3828 | } | 3809 | } |
| 3829 | if (!isByRef(given_ty, mod) and isByRef(wanted_ty, mod)) { | 3810 | if (!isByRef(given_ty, mod) and isByRef(wanted_ty, mod)) { |
| 3830 | const stack_memory = try func.allocStack(wanted_ty); | 3811 | const stack_memory = try func.allocStack(wanted_ty); |
| 3831 | try func.store(stack_memory, operand, given_ty, 0); | 3812 | try func.store(stack_memory, operand, given_ty, 0); |
| 3832 | break :result stack_memory; | 3813 | if (needs_wrapping) { |
| | 3814 | break :result try (try func.wrapOperand(stack_memory, wanted_ty)).toLocal(func, wanted_ty); |
| | 3815 | } else { |
| | 3816 | break :result stack_memory; |
| | 3817 | } |
| 3833 | } | 3818 | } |
| | 3819 | |
| | 3820 | if (needs_wrapping) { |
| | 3821 | break :result try (try func.wrapOperand(operand, wanted_ty)).toLocal(func, wanted_ty); |
| | 3822 | } |
| | 3823 | |
| 3834 | break :result func.reuseOperand(ty_op.operand, operand); | 3824 | break :result func.reuseOperand(ty_op.operand, operand); |
| 3835 | }; | 3825 | }; |
| 3836 | func.finishAir(inst, result, &.{ty_op.operand}); | 3826 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | @@ -4355,7 +4345,7 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4355,7 +4345,7 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4355 | | 4345 | |
| 4356 | const op_bits = toWasmBits(@as(u16, @intCast(operand_ty.bitSize(mod)))).?; | 4346 | const op_bits = toWasmBits(@as(u16, @intCast(operand_ty.bitSize(mod)))).?; |
| 4357 | const wanted_bits = toWasmBits(@as(u16, @intCast(ty.bitSize(mod)))).?; | 4347 | const wanted_bits = toWasmBits(@as(u16, @intCast(ty.bitSize(mod)))).?; |
| 4358 | const result = if (op_bits == wanted_bits and !ty.isSignedInt(mod)) | 4348 | const result = if (op_bits == wanted_bits) |
| 4359 | func.reuseOperand(ty_op.operand, operand) | 4349 | func.reuseOperand(ty_op.operand, operand) |
| 4360 | else | 4350 | else |
| 4361 | try (try func.intcast(operand, operand_ty, ty)).toLocal(func, ty); | 4351 | try (try func.intcast(operand, operand_ty, ty)).toLocal(func, ty); |
| ... | @@ -4377,37 +4367,17 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -4377,37 +4367,17 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4377 | const op_bits = toWasmBits(given_bitsize).?; | 4367 | const op_bits = toWasmBits(given_bitsize).?; |
| 4378 | const wanted_bits = toWasmBits(wanted_bitsize).?; | 4368 | const wanted_bits = toWasmBits(wanted_bitsize).?; |
| 4379 | if (op_bits == wanted_bits) { | 4369 | if (op_bits == wanted_bits) { |
| 4380 | if (given.isSignedInt(mod)) { | | |
| 4381 | if (given_bitsize < wanted_bitsize) { | | |
| 4382 | // signed integers are stored as two's complement, | | |
| 4383 | // when we upcast from a smaller integer to larger | | |
| 4384 | // integers, we must get its absolute value similar to | | |
| 4385 | // i64_extend_i32_s instruction. | | |
| 4386 | return func.signExtendInt(operand, given); | | |
| 4387 | } | | |
| 4388 | return func.wrapOperand(operand, wanted); | | |
| 4389 | } | | |
| 4390 | return operand; | 4370 | return operand; |
| 4391 | } | 4371 | } |
| 4392 | | 4372 | |
| 4393 | if (op_bits > 32 and op_bits <= 64 and wanted_bits == 32) { | 4373 | if (op_bits == 64 and wanted_bits == 32) { |
| 4394 | try func.emitWValue(operand); | 4374 | try func.emitWValue(operand); |
| 4395 | try func.addTag(.i32_wrap_i64); | 4375 | try func.addTag(.i32_wrap_i64); |
| 4396 | if (given.isSignedInt(mod) and wanted_bitsize < 32) | 4376 | return .stack; |
| 4397 | return func.wrapOperand(.{ .stack = {} }, wanted) | 4377 | } else if (op_bits == 32 and wanted_bits == 64) { |
| 4398 | else | 4378 | try func.emitWValue(operand); |
| 4399 | return WValue{ .stack = {} }; | | |
| 4400 | } else if (op_bits == 32 and wanted_bits > 32 and wanted_bits <= 64) { | | |
| 4401 | const operand32 = if (given_bitsize < 32 and wanted.isSignedInt(mod)) | | |
| 4402 | try func.signExtendInt(operand, given) | | |
| 4403 | else | | |
| 4404 | operand; | | |
| 4405 | try func.emitWValue(operand32); | | |
| 4406 | try func.addTag(if (wanted.isSignedInt(mod)) .i64_extend_i32_s else .i64_extend_i32_u); | 4379 | try func.addTag(if (wanted.isSignedInt(mod)) .i64_extend_i32_s else .i64_extend_i32_u); |
| 4407 | if (given.isSignedInt(mod) and wanted_bitsize < 64) | 4380 | return .stack; |
| 4408 | return func.wrapOperand(.{ .stack = {} }, wanted) | | |
| 4409 | else | | |
| 4410 | return WValue{ .stack = {} }; | | |
| 4411 | } else if (wanted_bits == 128) { | 4381 | } else if (wanted_bits == 128) { |
| 4412 | // for 128bit integers we store the integer in the virtual stack, rather than a local | 4382 | // for 128bit integers we store the integer in the virtual stack, rather than a local |
| 4413 | const stack_ptr = try func.allocStack(wanted); | 4383 | const stack_ptr = try func.allocStack(wanted); |
| ... | @@ -4416,17 +4386,18 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -4416,17 +4386,18 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4416 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it | 4386 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it |
| 4417 | // meaning less store operations are required. | 4387 | // meaning less store operations are required. |
| 4418 | const lhs = if (op_bits == 32) blk: { | 4388 | const lhs = if (op_bits == 32) blk: { |
| 4419 | break :blk try func.intcast(operand, given, if (wanted.isSignedInt(mod)) Type.i64 else Type.u64); | 4389 | const sign_ty = if (wanted.isSignedInt(mod)) Type.i64 else Type.u64; |
| | 4390 | break :blk try (try func.intcast(operand, given, sign_ty)).toLocal(func, sign_ty); |
| 4420 | } else operand; | 4391 | } else operand; |
| 4421 | | 4392 | |
| 4422 | // store msb first | 4393 | // store msb first |
| 4423 | try func.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset()); | 4394 | try func.store(.stack, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 4424 | | 4395 | |
| 4425 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value | 4396 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 4426 | if (wanted.isSignedInt(mod)) { | 4397 | if (wanted.isSignedInt(mod)) { |
| 4427 | try func.emitWValue(stack_ptr); | 4398 | try func.emitWValue(stack_ptr); |
| 4428 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); | 4399 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| 4429 | try func.store(.{ .stack = {} }, shr, Type.u64, 8 + stack_ptr.offset()); | 4400 | try func.store(.stack, shr, Type.u64, 8 + stack_ptr.offset()); |
| 4430 | } else { | 4401 | } else { |
| 4431 | // Ensure memory of lsb is zero'd | 4402 | // Ensure memory of lsb is zero'd |
| 4432 | try func.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); | 4403 | try func.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); |
| ... | @@ -5823,25 +5794,34 @@ fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5823,25 +5794,34 @@ fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5823 | }; | 5794 | }; |
| 5824 | | 5795 | |
| 5825 | switch (wasm_bits) { | 5796 | switch (wasm_bits) { |
| | 5797 | 32 => { |
| | 5798 | try func.emitWValue(operand); |
| | 5799 | if (op_ty.isSignedInt(mod) and bits != wasm_bits) { |
| | 5800 | _ = try func.wrapOperand(.stack, try mod.intType(.unsigned, bits)); |
| | 5801 | } |
| | 5802 | try func.addTag(.i32_popcnt); |
| | 5803 | }, |
| | 5804 | 64 => { |
| | 5805 | try func.emitWValue(operand); |
| | 5806 | if (op_ty.isSignedInt(mod) and bits != wasm_bits) { |
| | 5807 | _ = try func.wrapOperand(.stack, try mod.intType(.unsigned, bits)); |
| | 5808 | } |
| | 5809 | try func.addTag(.i64_popcnt); |
| | 5810 | try func.addTag(.i32_wrap_i64); |
| | 5811 | try func.emitWValue(operand); |
| | 5812 | }, |
| 5826 | 128 => { | 5813 | 128 => { |
| 5827 | _ = try func.load(operand, Type.u64, 0); | 5814 | _ = try func.load(operand, Type.u64, 0); |
| 5828 | try func.addTag(.i64_popcnt); | 5815 | try func.addTag(.i64_popcnt); |
| 5829 | _ = try func.load(operand, Type.u64, 8); | 5816 | _ = try func.load(operand, Type.u64, 8); |
| | 5817 | if (op_ty.isSignedInt(mod) and bits != wasm_bits) { |
| | 5818 | _ = try func.wrapOperand(.stack, try mod.intType(.unsigned, bits - 64)); |
| | 5819 | } |
| 5830 | try func.addTag(.i64_popcnt); | 5820 | try func.addTag(.i64_popcnt); |
| 5831 | try func.addTag(.i64_add); | 5821 | try func.addTag(.i64_add); |
| 5832 | try func.addTag(.i32_wrap_i64); | 5822 | try func.addTag(.i32_wrap_i64); |
| 5833 | }, | 5823 | }, |
| 5834 | else => { | 5824 | else => unreachable, |
| 5835 | try func.emitWValue(operand); | | |
| 5836 | switch (wasm_bits) { | | |
| 5837 | 32 => try func.addTag(.i32_popcnt), | | |
| 5838 | 64 => { | | |
| 5839 | try func.addTag(.i64_popcnt); | | |
| 5840 | try func.addTag(.i32_wrap_i64); | | |
| 5841 | }, | | |
| 5842 | else => unreachable, | | |
| 5843 | } | | |
| 5844 | }, | | |
| 5845 | } | 5825 | } |
| 5846 | | 5826 | |
| 5847 | const result = try func.allocLocal(result_ty); | 5827 | const result = try func.allocLocal(result_ty); |
| ... | @@ -5877,7 +5857,7 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5877,7 +5857,7 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5877 | const reversed = if (bits == 32) | 5857 | const reversed = if (bits == 32) |
| 5878 | intrin_ret | 5858 | intrin_ret |
| 5879 | else | 5859 | else |
| 5880 | try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, Type.u32, .shr); | 5860 | try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, ty, .shr); |
| 5881 | const result = try reversed.toLocal(func, ty); | 5861 | const result = try reversed.toLocal(func, ty); |
| 5882 | func.finishAir(inst, result, &.{ty_op.operand}); | 5862 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5883 | }, | 5863 | }, |
| ... | @@ -5891,7 +5871,7 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5891,7 +5871,7 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5891 | const reversed = if (bits == 64) | 5871 | const reversed = if (bits == 64) |
| 5892 | intrin_ret | 5872 | intrin_ret |
| 5893 | else | 5873 | else |
| 5894 | try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, Type.u64, .shr); | 5874 | try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, ty, .shr); |
| 5895 | const result = try reversed.toLocal(func, ty); | 5875 | const result = try reversed.toLocal(func, ty); |
| 5896 | func.finishAir(inst, result, &.{ty_op.operand}); | 5876 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5897 | }, | 5877 | }, |
| ... | @@ -5928,7 +5908,11 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5928,7 +5908,11 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5928 | defer tmp.free(func); | 5908 | defer tmp.free(func); |
| 5929 | try func.addLabel(.local_tee, tmp.local.value); | 5909 | try func.addLabel(.local_tee, tmp.local.value); |
| 5930 | try func.emitWValue(.{ .imm64 = 128 - bits }); | 5910 | try func.emitWValue(.{ .imm64 = 128 - bits }); |
| 5931 | try func.addTag(.i64_shr_u); | 5911 | if (ty.isSignedInt(mod)) { |
| | 5912 | try func.addTag(.i64_shr_s); |
| | 5913 | } else { |
| | 5914 | try func.addTag(.i64_shr_u); |
| | 5915 | } |
| 5932 | try func.store(.stack, .stack, Type.u64, result.offset() + 8); | 5916 | try func.store(.stack, .stack, Type.u64, result.offset() + 8); |
| 5933 | try func.addLabel(.local_get, tmp.local.value); | 5917 | try func.addLabel(.local_get, tmp.local.value); |
| 5934 | try func.emitWValue(.{ .imm64 = bits - 64 }); | 5918 | try func.emitWValue(.{ .imm64 = bits - 64 }); |
| ... | @@ -5996,8 +5980,8 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -5996,8 +5980,8 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5996 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 5980 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 5997 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 5981 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5998 | | 5982 | |
| 5999 | const lhs_op = try func.resolveInst(extra.lhs); | 5983 | const lhs = try func.resolveInst(extra.lhs); |
| 6000 | const rhs_op = try func.resolveInst(extra.rhs); | 5984 | const rhs = try func.resolveInst(extra.rhs); |
| 6001 | const lhs_ty = func.typeOf(extra.lhs); | 5985 | const lhs_ty = func.typeOf(extra.lhs); |
| 6002 | const mod = func.bin_file.base.comp.module.?; | 5986 | const mod = func.bin_file.base.comp.module.?; |
| 6003 | | 5987 | |
| ... | @@ -6012,7 +5996,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -6012,7 +5996,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 6012 | }; | 5996 | }; |
| 6013 | | 5997 | |
| 6014 | if (wasm_bits == 128) { | 5998 | if (wasm_bits == 128) { |
| 6015 | const result = try func.addSubWithOverflowBigInt(lhs_op, rhs_op, lhs_ty, func.typeOfIndex(inst), op); | 5999 | const result = try func.addSubWithOverflowBigInt(lhs, rhs, lhs_ty, func.typeOfIndex(inst), op); |
| 6016 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); | 6000 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); |
| 6017 | } | 6001 | } |
| 6018 | | 6002 | |
| ... | @@ -6022,24 +6006,6 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -6022,24 +6006,6 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 6022 | else => unreachable, | 6006 | else => unreachable, |
| 6023 | }; | 6007 | }; |
| 6024 | | 6008 | |
| 6025 | // for signed integers, we first apply signed shifts by the difference in bits | | |
| 6026 | // to get the signed value, as we store it internally as 2's complement. | | |
| 6027 | var lhs = if (wasm_bits != int_info.bits and is_signed) blk: { | | |
| 6028 | break :blk try (try func.signExtendInt(lhs_op, lhs_ty)).toLocal(func, lhs_ty); | | |
| 6029 | } else lhs_op; | | |
| 6030 | var rhs = if (wasm_bits != int_info.bits and is_signed) blk: { | | |
| 6031 | break :blk try (try func.signExtendInt(rhs_op, lhs_ty)).toLocal(func, lhs_ty); | | |
| 6032 | } else rhs_op; | | |
| 6033 | | | |
| 6034 | // in this case, we performed a signExtendInt which created a temporary local | | |
| 6035 | // so let's free this so it can be re-used instead. | | |
| 6036 | // In the other case we do not want to free it, because that would free the | | |
| 6037 | // resolved instructions which may be referenced by other instructions. | | |
| 6038 | defer if (wasm_bits != int_info.bits and is_signed) { | | |
| 6039 | lhs.free(func); | | |
| 6040 | rhs.free(func); | | |
| 6041 | }; | | |
| 6042 | | | |
| 6043 | const bin_op = try (try func.binOp(lhs, rhs, lhs_ty, op)).toLocal(func, lhs_ty); | 6009 | const bin_op = try (try func.binOp(lhs, rhs, lhs_ty, op)).toLocal(func, lhs_ty); |
| 6044 | var result = if (wasm_bits != int_info.bits) blk: { | 6010 | var result = if (wasm_bits != int_info.bits) blk: { |
| 6045 | break :blk try (try func.wrapOperand(bin_op, lhs_ty)).toLocal(func, lhs_ty); | 6011 | break :blk try (try func.wrapOperand(bin_op, lhs_ty)).toLocal(func, lhs_ty); |
| ... | @@ -6053,8 +6019,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -6053,8 +6019,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 6053 | const lt = try func.cmp(bin_op, lhs, lhs_ty, .lt); | 6019 | const lt = try func.cmp(bin_op, lhs, lhs_ty, .lt); |
| 6054 | break :blk try func.binOp(cmp_zero, lt, Type.u32, .xor); | 6020 | break :blk try func.binOp(cmp_zero, lt, Type.u32, .xor); |
| 6055 | } | 6021 | } |
| 6056 | const abs = try func.signExtendInt(bin_op, lhs_ty); | 6022 | break :blk try func.cmp(bin_op, bin_op, lhs_ty, .neq); |
| 6057 | break :blk try func.cmp(abs, bin_op, lhs_ty, .neq); | | |
| 6058 | } else if (wasm_bits == int_info.bits) | 6023 | } else if (wasm_bits == int_info.bits) |
| 6059 | try func.cmp(bin_op, lhs, lhs_ty, cmp_op) | 6024 | try func.cmp(bin_op, lhs, lhs_ty, cmp_op) |
| 6060 | else | 6025 | else |
| ... | @@ -6150,7 +6115,6 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6150,7 +6115,6 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6150 | } | 6115 | } |
| 6151 | | 6116 | |
| 6152 | const int_info = lhs_ty.intInfo(mod); | 6117 | const int_info = lhs_ty.intInfo(mod); |
| 6153 | const is_signed = int_info.signedness == .signed; | | |
| 6154 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 6118 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6155 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); | 6119 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 6156 | }; | 6120 | }; |
| ... | @@ -6170,13 +6134,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6170,13 +6134,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6170 | } else shl; | 6134 | } else shl; |
| 6171 | defer result.free(func); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits) | 6135 | defer result.free(func); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits) |
| 6172 | | 6136 | |
| 6173 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { | 6137 | const overflow_bit = blk: { |
| 6174 | // emit lhs to stack to we can keep 'wrapped' on the stack also | | |
| 6175 | try func.emitWValue(lhs); | | |
| 6176 | const abs = try func.signExtendInt(shl, lhs_ty); | | |
| 6177 | const wrapped = try func.wrapBinOp(abs, rhs_final, lhs_ty, .shr); | | |
| 6178 | break :blk try func.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq); | | |
| 6179 | } else blk: { | | |
| 6180 | try func.emitWValue(lhs); | 6138 | try func.emitWValue(lhs); |
| 6181 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); | 6139 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); |
| 6182 | break :blk try func.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); | 6140 | break :blk try func.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); |
| ... | @@ -6245,10 +6203,8 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6245,10 +6203,8 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6245 | break :blk down_cast; | 6203 | break :blk down_cast; |
| 6246 | } | 6204 | } |
| 6247 | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { | 6205 | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { |
| 6248 | const lhs_abs = try func.signExtendInt(lhs, lhs_ty); | 6206 | const bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| 6249 | const rhs_abs = try func.signExtendInt(rhs, lhs_ty); | 6207 | const mul_abs = try func.wrapOperand(bin_op, lhs_ty); |
| 6250 | const bin_op = try (try func.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(func, lhs_ty); | | |
| 6251 | const mul_abs = try func.signExtendInt(bin_op, lhs_ty); | | |
| 6252 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); | 6208 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 6253 | try func.addLabel(.local_set, overflow_bit.local.value); | 6209 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6254 | break :blk try func.wrapOperand(bin_op, lhs_ty); | 6210 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| ... | @@ -6697,6 +6653,9 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6697,6 +6653,9 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6697 | return func.fail("TODO: @byteSwap for vectors", .{}); | 6653 | return func.fail("TODO: @byteSwap for vectors", .{}); |
| 6698 | } | 6654 | } |
| 6699 | const int_info = ty.intInfo(mod); | 6655 | const int_info = ty.intInfo(mod); |
| | 6656 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| | 6657 | return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}); |
| | 6658 | }; |
| 6700 | | 6659 | |
| 6701 | // bytes are no-op | 6660 | // bytes are no-op |
| 6702 | if (int_info.bits == 8) { | 6661 | if (int_info.bits == 8) { |
| ... | @@ -6704,73 +6663,34 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6704,73 +6663,34 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6704 | } | 6663 | } |
| 6705 | | 6664 | |
| 6706 | const result = result: { | 6665 | const result = result: { |
| 6707 | switch (int_info.bits) { | 6666 | switch (wasm_bits) { |
| 6708 | 16 => { | | |
| 6709 | const shl_res = try func.binOp(operand, .{ .imm32 = 8 }, ty, .shl); | | |
| 6710 | const lhs = try func.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and"); | | |
| 6711 | const shr_res = try func.binOp(operand, .{ .imm32 = 8 }, ty, .shr); | | |
| 6712 | const res = if (int_info.signedness == .signed) blk: { | | |
| 6713 | break :blk try func.wrapOperand(shr_res, Type.u8); | | |
| 6714 | } else shr_res; | | |
| 6715 | break :result try (try func.binOp(lhs, res, ty, .@"or")).toLocal(func, ty); | | |
| 6716 | }, | | |
| 6717 | 24 => { | | |
| 6718 | var msb = try (try func.wrapOperand(operand, Type.u16)).toLocal(func, Type.u16); | | |
| 6719 | defer msb.free(func); | | |
| 6720 | | | |
| 6721 | const shl_res = try func.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); | | |
| 6722 | const lhs = try func.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and"); | | |
| 6723 | const shr_res = try func.binOp(msb, .{ .imm32 = 8 }, ty, .shr); | | |
| 6724 | | | |
| 6725 | const res = if (int_info.signedness == .signed) blk: { | | |
| 6726 | break :blk try func.wrapOperand(shr_res, Type.u8); | | |
| 6727 | } else shr_res; | | |
| 6728 | const lhs_tmp = try func.binOp(lhs, res, ty, .@"or"); | | |
| 6729 | const lhs_result = try func.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr); | | |
| 6730 | const rhs_wrap = try func.wrapOperand(msb, Type.u8); | | |
| 6731 | const rhs_result = try func.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl); | | |
| 6732 | | | |
| 6733 | const lsb = try func.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); | | |
| 6734 | const tmp = try func.binOp(lhs_result, rhs_result, ty, .@"or"); | | |
| 6735 | break :result try (try func.binOp(tmp, lsb, ty, .@"or")).toLocal(func, ty); | | |
| 6736 | }, | | |
| 6737 | 32 => { | 6667 | 32 => { |
| 6738 | const shl_tmp = try func.binOp(operand, .{ .imm32 = 8 }, Type.u32, .shl); | 6668 | const intrin_ret = try func.callIntrinsic( |
| 6739 | const lhs = try func.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, Type.u32, .@"and"); | 6669 | "__bswapsi2", |
| 6740 | const shr_tmp = try func.binOp(operand, .{ .imm32 = 8 }, Type.u32, .shr); | 6670 | &.{.u32_type}, |
| 6741 | const rhs = try func.binOp(shr_tmp, .{ .imm32 = 0x00FF00FF }, Type.u32, .@"and"); | 6671 | Type.u32, |
| 6742 | var tmp_or = try (try func.binOp(lhs, rhs, Type.u32, .@"or")).toLocal(func, Type.u32); | 6672 | &.{operand}, |
| 6743 | | 6673 | ); |
| 6744 | const shl = try func.binOp(tmp_or, .{ .imm32 = 16 }, Type.u32, .shl); | 6674 | const swapped = if (int_info.bits == 32) |
| 6745 | const shr = try func.binOp(tmp_or, .{ .imm32 = 16 }, Type.u32, .shr); | 6675 | intrin_ret |
| 6746 | | 6676 | else |
| 6747 | tmp_or.free(func); | 6677 | try func.binOp(intrin_ret, .{ .imm32 = 32 - int_info.bits }, ty, .shr); |
| 6748 | | 6678 | |
| 6749 | break :result try (try func.binOp(shl, shr, Type.u32, .@"or")).toLocal(func, Type.u32); | 6679 | break :result try swapped.toLocal(func, ty); |
| 6750 | }, | 6680 | }, |
| 6751 | 64 => { | 6681 | 64 => { |
| 6752 | const shl_tmp_1 = try func.binOp(operand, .{ .imm64 = 8 }, Type.u64, .shl); | 6682 | const intrin_ret = try func.callIntrinsic( |
| 6753 | const lhs_1 = try func.binOp(shl_tmp_1, .{ .imm64 = 0xFF00FF00FF00FF00 }, Type.u64, .@"and"); | 6683 | "__bswapdi2", |
| 6754 | | 6684 | &.{.u64_type}, |
| 6755 | const shr_tmp_1 = try func.binOp(operand, .{ .imm64 = 8 }, Type.u64, .shr); | 6685 | Type.u64, |
| 6756 | const rhs_1 = try func.binOp(shr_tmp_1, .{ .imm64 = 0x00FF00FF00FF00FF }, Type.u64, .@"and"); | 6686 | &.{operand}, |
| 6757 | | 6687 | ); |
| 6758 | var tmp_or_1 = try (try func.binOp(lhs_1, rhs_1, Type.u64, .@"or")).toLocal(func, Type.u64); | 6688 | const swapped = if (int_info.bits == 64) |
| 6759 | | 6689 | intrin_ret |
| 6760 | const shl_tmp_2 = try func.binOp(tmp_or_1, .{ .imm64 = 16 }, Type.u64, .shl); | 6690 | else |
| 6761 | const lhs_2 = try func.binOp(shl_tmp_2, .{ .imm64 = 0xFFFF0000FFFF0000 }, Type.u64, .@"and"); | 6691 | try func.binOp(intrin_ret, .{ .imm64 = 64 - int_info.bits }, ty, .shr); |
| 6762 | | | |
| 6763 | const shr_tmp_2 = try func.binOp(tmp_or_1, .{ .imm64 = 16 }, Type.u64, .shr); | | |
| 6764 | tmp_or_1.free(func); | | |
| 6765 | const rhs_2 = try func.binOp(shr_tmp_2, .{ .imm64 = 0x0000FFFF0000FFFF }, Type.u64, .@"and"); | | |
| 6766 | | | |
| 6767 | var tmp_or_2 = try (try func.binOp(lhs_2, rhs_2, Type.u64, .@"or")).toLocal(func, Type.u64); | | |
| 6768 | | | |
| 6769 | const shl = try func.binOp(tmp_or_2, .{ .imm64 = 32 }, Type.u64, .shl); | | |
| 6770 | const shr = try func.binOp(tmp_or_2, .{ .imm64 = 32 }, Type.u64, .shr); | | |
| 6771 | tmp_or_2.free(func); | | |
| 6772 | | 6692 | |
| 6773 | break :result try (try func.binOp(shl, shr, Type.u64, .@"or")).toLocal(func, Type.u64); | 6693 | break :result try swapped.toLocal(func, ty); |
| 6774 | }, | 6694 | }, |
| 6775 | else => return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), | 6695 | else => return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), |
| 6776 | } | 6696 | } |
| ... | @@ -6779,32 +6699,24 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6779,32 +6699,24 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6779 | } | 6699 | } |
| 6780 | | 6700 | |
| 6781 | fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6701 | fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6782 | const mod = func.bin_file.base.comp.module.?; | | |
| 6783 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 6702 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6784 | | 6703 | |
| 6785 | const ty = func.typeOfIndex(inst); | 6704 | const ty = func.typeOfIndex(inst); |
| 6786 | const lhs = try func.resolveInst(bin_op.lhs); | 6705 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6787 | const rhs = try func.resolveInst(bin_op.rhs); | 6706 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6788 | | 6707 | |
| 6789 | const result = if (ty.isSignedInt(mod)) | 6708 | const result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6790 | try func.divSigned(lhs, rhs, ty) | | |
| 6791 | else | | |
| 6792 | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); | | |
| 6793 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 6709 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 6794 | } | 6710 | } |
| 6795 | | 6711 | |
| 6796 | fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6712 | fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6797 | const mod = func.bin_file.base.comp.module.?; | | |
| 6798 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 6713 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6799 | | 6714 | |
| 6800 | const ty = func.typeOfIndex(inst); | 6715 | const ty = func.typeOfIndex(inst); |
| 6801 | const lhs = try func.resolveInst(bin_op.lhs); | 6716 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6802 | const rhs = try func.resolveInst(bin_op.rhs); | 6717 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6803 | | 6718 | |
| 6804 | const div_result = if (ty.isSignedInt(mod)) | 6719 | const div_result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6805 | try func.divSigned(lhs, rhs, ty) | | |
| 6806 | else | | |
| 6807 | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); | | |
| 6808 | | 6720 | |
| 6809 | if (ty.isAnyFloat()) { | 6721 | if (ty.isAnyFloat()) { |
| 6810 | const trunc_result = try (try func.floatOp(.trunc, ty, &.{div_result})).toLocal(func, ty); | 6722 | const trunc_result = try (try func.floatOp(.trunc, ty, &.{div_result})).toLocal(func, ty); |
| ... | @@ -6834,16 +6746,6 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6834,16 +6746,6 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6834 | return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); | 6746 | return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| 6835 | } | 6747 | } |
| 6836 | | 6748 | |
| 6837 | const lhs_wasm = if (wasm_bits != int_bits) | | |
| 6838 | try (try func.signExtendInt(lhs, ty)).toLocal(func, ty) | | |
| 6839 | else | | |
| 6840 | lhs; | | |
| 6841 | | | |
| 6842 | const rhs_wasm = if (wasm_bits != int_bits) | | |
| 6843 | try (try func.signExtendInt(rhs, ty)).toLocal(func, ty) | | |
| 6844 | else | | |
| 6845 | rhs; | | |
| 6846 | | | |
| 6847 | const zero = switch (wasm_bits) { | 6749 | const zero = switch (wasm_bits) { |
| 6848 | 32 => WValue{ .imm32 = 0 }, | 6750 | 32 => WValue{ .imm32 = 0 }, |
| 6849 | 64 => WValue{ .imm64 = 0 }, | 6751 | 64 => WValue{ .imm64 = 0 }, |
| ... | @@ -6852,7 +6754,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6852,7 +6754,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6852 | | 6754 | |
| 6853 | // tee leaves the value on the stack and stores it in a local. | 6755 | // tee leaves the value on the stack and stores it in a local. |
| 6854 | const quotient = try func.allocLocal(ty); | 6756 | const quotient = try func.allocLocal(ty); |
| 6855 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .div); | 6757 | _ = try func.binOp(lhs, rhs, ty, .div); |
| 6856 | try func.addLabel(.local_tee, quotient.local.value); | 6758 | try func.addLabel(.local_tee, quotient.local.value); |
| 6857 | | 6759 | |
| 6858 | // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow | 6760 | // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow |
| ... | @@ -6864,7 +6766,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6864,7 +6766,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6864 | } | 6766 | } |
| 6865 | | 6767 | |
| 6866 | // 0 if the signs of rhs_wasm and lhs_wasm are the same, 1 otherwise. | 6768 | // 0 if the signs of rhs_wasm and lhs_wasm are the same, 1 otherwise. |
| 6867 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .xor); | 6769 | _ = try func.binOp(lhs, rhs, ty, .xor); |
| 6868 | _ = try func.cmp(.stack, zero, ty, .lt); | 6770 | _ = try func.cmp(.stack, zero, ty, .lt); |
| 6869 | | 6771 | |
| 6870 | switch (wasm_bits) { | 6772 | switch (wasm_bits) { |
| ... | @@ -6879,7 +6781,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6879,7 +6781,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6879 | else => unreachable, | 6781 | else => unreachable, |
| 6880 | } | 6782 | } |
| 6881 | | 6783 | |
| 6882 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .rem); | 6784 | _ = try func.binOp(lhs, rhs, ty, .rem); |
| 6883 | | 6785 | |
| 6884 | if (wasm_bits == 64) { | 6786 | if (wasm_bits == 64) { |
| 6885 | try func.addTag(.i64_eqz); | 6787 | try func.addTag(.i64_eqz); |
| ... | @@ -6929,68 +6831,14 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6929,68 +6831,14 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6929 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 6831 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 6930 | } | 6832 | } |
| 6931 | | 6833 | |
| 6932 | fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue { | | |
| 6933 | const mod = func.bin_file.base.comp.module.?; | | |
| 6934 | const int_bits = ty.intInfo(mod).bits; | | |
| 6935 | const wasm_bits = toWasmBits(int_bits) orelse { | | |
| 6936 | return func.fail("TODO: Implement signed division for integers with bitsize '{d}'", .{int_bits}); | | |
| 6937 | }; | | |
| 6938 | | | |
| 6939 | if (wasm_bits == 128) { | | |
| 6940 | return func.fail("TODO: Implement signed division for 128-bit integerrs", .{}); | | |
| 6941 | } | | |
| 6942 | | | |
| 6943 | if (wasm_bits != int_bits) { | | |
| 6944 | // Leave both values on the stack | | |
| 6945 | _ = try func.signExtendInt(lhs, ty); | | |
| 6946 | _ = try func.signExtendInt(rhs, ty); | | |
| 6947 | } else { | | |
| 6948 | try func.emitWValue(lhs); | | |
| 6949 | try func.emitWValue(rhs); | | |
| 6950 | } | | |
| 6951 | switch (wasm_bits) { | | |
| 6952 | 32 => try func.addTag(.i32_div_s), | | |
| 6953 | 64 => try func.addTag(.i64_div_s), | | |
| 6954 | else => unreachable, | | |
| 6955 | } | | |
| 6956 | _ = try func.wrapOperand(.stack, ty); | | |
| 6957 | | | |
| 6958 | const result = try func.allocLocal(ty); | | |
| 6959 | try func.addLabel(.local_set, result.local.value); | | |
| 6960 | return result; | | |
| 6961 | } | | |
| 6962 | | | |
| 6963 | fn airRem(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6834 | fn airRem(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6964 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 6835 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6965 | | 6836 | |
| 6966 | const mod = func.bin_file.base.comp.module.?; | | |
| 6967 | const ty = func.typeOfIndex(inst); | 6837 | const ty = func.typeOfIndex(inst); |
| 6968 | const lhs = try func.resolveInst(bin_op.lhs); | 6838 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6969 | const rhs = try func.resolveInst(bin_op.rhs); | 6839 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6970 | | 6840 | |
| 6971 | const result = if (ty.isSignedInt(mod)) result: { | 6841 | const result = try func.binOp(lhs, rhs, ty, .rem); |
| 6972 | const int_bits = ty.intInfo(mod).bits; | | |
| 6973 | const wasm_bits = toWasmBits(int_bits) orelse { | | |
| 6974 | return func.fail("TODO: `@rem` for signed integers larger than 128 bits ({d} bits requested)", .{int_bits}); | | |
| 6975 | }; | | |
| 6976 | | | |
| 6977 | if (wasm_bits > 64) { | | |
| 6978 | return func.fail("TODO: `@rem` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); | | |
| 6979 | } | | |
| 6980 | | | |
| 6981 | const lhs_wasm = if (wasm_bits != int_bits) | | |
| 6982 | try (try func.signExtendInt(lhs, ty)).toLocal(func, ty) | | |
| 6983 | else | | |
| 6984 | lhs; | | |
| 6985 | | | |
| 6986 | const rhs_wasm = if (wasm_bits != int_bits) | | |
| 6987 | try (try func.signExtendInt(rhs, ty)).toLocal(func, ty) | | |
| 6988 | else | | |
| 6989 | rhs; | | |
| 6990 | | | |
| 6991 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .rem); | | |
| 6992 | break :result try func.wrapOperand(.stack, ty); | | |
| 6993 | } else try func.binOp(lhs, rhs, ty, .rem); | | |
| 6994 | | 6842 | |
| 6995 | const return_local = try result.toLocal(func, ty); | 6843 | const return_local = try result.toLocal(func, ty); |
| 6996 | func.finishAir(inst, return_local, &.{ bin_op.lhs, bin_op.rhs }); | 6844 | func.finishAir(inst, return_local, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | @@ -7022,19 +6870,9 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7022,19 +6870,9 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7022 | return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); | 6870 | return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| 7023 | } | 6871 | } |
| 7024 | | 6872 | |
| 7025 | const lhs_wasm = if (wasm_bits != int_bits) | 6873 | _ = try func.binOp(lhs, rhs, ty, .rem); |
| 7026 | try (try func.signExtendInt(lhs, ty)).toLocal(func, ty) | 6874 | _ = try func.binOp(.stack, rhs, ty, .add); |
| 7027 | else | 6875 | _ = try func.binOp(.stack, rhs, ty, .rem); |
| 7028 | lhs; | | |
| 7029 | | | |
| 7030 | const rhs_wasm = if (wasm_bits != int_bits) | | |
| 7031 | try (try func.signExtendInt(rhs, ty)).toLocal(func, ty) | | |
| 7032 | else | | |
| 7033 | rhs; | | |
| 7034 | | | |
| 7035 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .rem); | | |
| 7036 | _ = try func.binOp(.stack, rhs_wasm, ty, .add); | | |
| 7037 | _ = try func.binOp(.stack, rhs_wasm, ty, .rem); | | |
| 7038 | } else { | 6876 | } else { |
| 7039 | return func.fail("TODO: implement `@mod` on floating point types for {}", .{func.target.cpu.arch}); | 6877 | return func.fail("TODO: implement `@mod` on floating point types for {}", .{func.target.cpu.arch}); |
| 7040 | } | 6878 | } |
| ... | @@ -7044,42 +6882,6 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7044,42 +6882,6 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7044 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 6882 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 7045 | } | 6883 | } |
| 7046 | | 6884 | |
| 7047 | /// Sign extends an N bit signed integer and pushes the result to the stack. | | |
| 7048 | /// The result will be sign extended to 32 bits if N <= 32 or 64 bits if N <= 64. | | |
| 7049 | /// Support for integers wider than 64 bits has not yet been implemented. | | |
| 7050 | fn signExtendInt(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | | |
| 7051 | const mod = func.bin_file.base.comp.module.?; | | |
| 7052 | const int_bits = ty.intInfo(mod).bits; | | |
| 7053 | const wasm_bits = toWasmBits(int_bits) orelse { | | |
| 7054 | return func.fail("TODO: signExtendInt for signed integers larger than '{d}' bits", .{int_bits}); | | |
| 7055 | }; | | |
| 7056 | | | |
| 7057 | const shift_val = switch (wasm_bits) { | | |
| 7058 | 32 => WValue{ .imm32 = wasm_bits - int_bits }, | | |
| 7059 | 64 => WValue{ .imm64 = wasm_bits - int_bits }, | | |
| 7060 | else => return func.fail("TODO: signExtendInt for i128", .{}), | | |
| 7061 | }; | | |
| 7062 | | | |
| 7063 | try func.emitWValue(operand); | | |
| 7064 | switch (wasm_bits) { | | |
| 7065 | 32 => { | | |
| 7066 | try func.emitWValue(shift_val); | | |
| 7067 | try func.addTag(.i32_shl); | | |
| 7068 | try func.emitWValue(shift_val); | | |
| 7069 | try func.addTag(.i32_shr_s); | | |
| 7070 | }, | | |
| 7071 | 64 => { | | |
| 7072 | try func.emitWValue(shift_val); | | |
| 7073 | try func.addTag(.i64_shl); | | |
| 7074 | try func.emitWValue(shift_val); | | |
| 7075 | try func.addTag(.i64_shr_s); | | |
| 7076 | }, | | |
| 7077 | else => unreachable, | | |
| 7078 | } | | |
| 7079 | | | |
| 7080 | return WValue{ .stack = {} }; | | |
| 7081 | } | | |
| 7082 | | | |
| 7083 | fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | 6885 | fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 7084 | assert(op == .add or op == .sub); | 6886 | assert(op == .add or op == .sub); |
| 7085 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 6887 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | @@ -7131,20 +6933,13 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -7131,20 +6933,13 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 7131 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 6933 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 7132 | } | 6934 | } |
| 7133 | | 6935 | |
| 7134 | fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op: Op) InnerError!WValue { | 6936 | fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 7135 | const mod = func.bin_file.base.comp.module.?; | 6937 | const mod = func.bin_file.base.comp.module.?; |
| 7136 | const int_info = ty.intInfo(mod); | 6938 | const int_info = ty.intInfo(mod); |
| 7137 | const wasm_bits = toWasmBits(int_info.bits).?; | 6939 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 7138 | const is_wasm_bits = wasm_bits == int_info.bits; | 6940 | const is_wasm_bits = wasm_bits == int_info.bits; |
| 7139 | const ext_ty = if (!is_wasm_bits) try mod.intType(int_info.signedness, wasm_bits) else ty; | 6941 | const ext_ty = if (!is_wasm_bits) try mod.intType(int_info.signedness, wasm_bits) else ty; |
| 7140 | | 6942 | |
| 7141 | var lhs = if (!is_wasm_bits) lhs: { | | |
| 7142 | break :lhs try (try func.signExtendInt(lhs_operand, ty)).toLocal(func, ext_ty); | | |
| 7143 | } else lhs_operand; | | |
| 7144 | var rhs = if (!is_wasm_bits) rhs: { | | |
| 7145 | break :rhs try (try func.signExtendInt(rhs_operand, ty)).toLocal(func, ext_ty); | | |
| 7146 | } else rhs_operand; | | |
| 7147 | | | |
| 7148 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); | 6943 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); |
| 7149 | const min_val: i64 = (-@as(i64, @intCast(@as(u63, @intCast(max_val))))) - 1; | 6944 | const min_val: i64 = (-@as(i64, @intCast(@as(u63, @intCast(max_val))))) - 1; |
| 7150 | const max_wvalue = switch (wasm_bits) { | 6945 | const max_wvalue = switch (wasm_bits) { |
| ... | @@ -7161,8 +6956,6 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, | ... | @@ -7161,8 +6956,6 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, |
| 7161 | var bin_result = try (try func.binOp(lhs, rhs, ext_ty, op)).toLocal(func, ext_ty); | 6956 | var bin_result = try (try func.binOp(lhs, rhs, ext_ty, op)).toLocal(func, ext_ty); |
| 7162 | if (!is_wasm_bits) { | 6957 | if (!is_wasm_bits) { |
| 7163 | defer bin_result.free(func); // not returned in this branch | 6958 | defer bin_result.free(func); // not returned in this branch |
| 7164 | defer lhs.free(func); // uses temporary local for absvalue | | |
| 7165 | defer rhs.free(func); // uses temporary local for absvalue | | |
| 7166 | try func.emitWValue(bin_result); | 6959 | try func.emitWValue(bin_result); |
| 7167 | try func.emitWValue(max_wvalue); | 6960 | try func.emitWValue(max_wvalue); |
| 7168 | _ = try func.cmp(bin_result, max_wvalue, ext_ty, .lt); | 6961 | _ = try func.cmp(bin_result, max_wvalue, ext_ty, .lt); |