| ... | ... | @@ -11,10 +11,8 @@ const log = std.log.scoped(.codegen); |
| 11 | 11 | |
| 12 | 12 | const codegen = @import("../../codegen.zig"); |
| 13 | 13 | const Zcu = @import("../../Zcu.zig"); |
| 14 | | /// Deprecated. |
| 15 | | const Module = Zcu; |
| 16 | 14 | const InternPool = @import("../../InternPool.zig"); |
| 17 | | const Decl = Module.Decl; |
| 15 | const Decl = Zcu.Decl; |
| 18 | 16 | const Type = @import("../../type.zig").Type; |
| 19 | 17 | const Value = @import("../../Value.zig"); |
| 20 | 18 | const Compilation = @import("../../Compilation.zig"); |
| ... | ... | @@ -674,7 +672,7 @@ local_index: u32 = 0, |
| 674 | 672 | /// Used to track which argument is being referenced in `airArg`. |
| 675 | 673 | arg_index: u32 = 0, |
| 676 | 674 | /// If codegen fails, an error messages will be allocated and saved in `err_msg` |
| 677 | | err_msg: *Module.ErrorMsg, |
| 675 | err_msg: *Zcu.ErrorMsg, |
| 678 | 676 | /// List of all locals' types generated throughout this declaration |
| 679 | 677 | /// used to emit locals count at start of 'code' section. |
| 680 | 678 | locals: std.ArrayListUnmanaged(u8), |
| ... | ... | @@ -768,7 +766,7 @@ pub fn deinit(func: *CodeGen) void { |
| 768 | 766 | fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError { |
| 769 | 767 | const mod = func.bin_file.base.comp.module.?; |
| 770 | 768 | const src_loc = func.decl.navSrcLoc(mod).upgrade(mod); |
| 771 | | func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args); |
| 769 | func.err_msg = try Zcu.ErrorMsg.create(func.gpa, src_loc, fmt, args); |
| 772 | 770 | return error.CodegenFail; |
| 773 | 771 | } |
| 774 | 772 | |
| ... | ... | @@ -992,7 +990,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 |
| 992 | 990 | } |
| 993 | 991 | |
| 994 | 992 | /// Using a given `Type`, returns the corresponding type |
| 995 | | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 993 | fn typeToValtype(ty: Type, mod: *Zcu) wasm.Valtype { |
| 996 | 994 | const target = mod.getTarget(); |
| 997 | 995 | const ip = &mod.intern_pool; |
| 998 | 996 | return switch (ty.zigTypeTag(mod)) { |
| ... | ... | @@ -1032,14 +1030,14 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 1032 | 1030 | } |
| 1033 | 1031 | |
| 1034 | 1032 | /// Using a given `Type`, returns the byte representation of its wasm value type |
| 1035 | | fn genValtype(ty: Type, mod: *Module) u8 { |
| 1033 | fn genValtype(ty: Type, mod: *Zcu) u8 { |
| 1036 | 1034 | return wasm.valtype(typeToValtype(ty, mod)); |
| 1037 | 1035 | } |
| 1038 | 1036 | |
| 1039 | 1037 | /// Using a given `Type`, returns the corresponding wasm value type |
| 1040 | 1038 | /// Differently from `genValtype` this also allows `void` to create a block |
| 1041 | 1039 | /// with no return type |
| 1042 | | fn genBlockType(ty: Type, mod: *Module) u8 { |
| 1040 | fn genBlockType(ty: Type, mod: *Zcu) u8 { |
| 1043 | 1041 | return switch (ty.ip_index) { |
| 1044 | 1042 | .void_type, .noreturn_type => wasm.block_empty, |
| 1045 | 1043 | else => genValtype(ty, mod), |
| ... | ... | @@ -1149,7 +1147,7 @@ fn genFunctype( |
| 1149 | 1147 | cc: std.builtin.CallingConvention, |
| 1150 | 1148 | params: []const InternPool.Index, |
| 1151 | 1149 | return_type: Type, |
| 1152 | | mod: *Module, |
| 1150 | mod: *Zcu, |
| 1153 | 1151 | ) !wasm.Type { |
| 1154 | 1152 | var temp_params = std.ArrayList(wasm.Valtype).init(gpa); |
| 1155 | 1153 | defer temp_params.deinit(); |
| ... | ... | @@ -1204,7 +1202,7 @@ fn genFunctype( |
| 1204 | 1202 | |
| 1205 | 1203 | pub fn generate( |
| 1206 | 1204 | bin_file: *link.File, |
| 1207 | | src_loc: Module.SrcLoc, |
| 1205 | src_loc: Zcu.SrcLoc, |
| 1208 | 1206 | func_index: InternPool.Index, |
| 1209 | 1207 | air: Air, |
| 1210 | 1208 | liveness: Liveness, |
| ... | ... | @@ -1405,7 +1403,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1405 | 1403 | return result; |
| 1406 | 1404 | } |
| 1407 | 1405 | |
| 1408 | | fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, mod: *Module) bool { |
| 1406 | fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, mod: *Zcu) bool { |
| 1409 | 1407 | switch (cc) { |
| 1410 | 1408 | .Unspecified, .Inline => return isByRef(return_type, mod), |
| 1411 | 1409 | .C => { |
| ... | ... | @@ -1713,7 +1711,7 @@ fn arch(func: *const CodeGen) std.Target.Cpu.Arch { |
| 1713 | 1711 | |
| 1714 | 1712 | /// For a given `Type`, will return true when the type will be passed |
| 1715 | 1713 | /// by reference, rather than by value |
| 1716 | | fn isByRef(ty: Type, mod: *Module) bool { |
| 1714 | fn isByRef(ty: Type, mod: *Zcu) bool { |
| 1717 | 1715 | const ip = &mod.intern_pool; |
| 1718 | 1716 | const target = mod.getTarget(); |
| 1719 | 1717 | switch (ty.zigTypeTag(mod)) { |
| ... | ... | @@ -1785,7 +1783,7 @@ const SimdStoreStrategy = enum { |
| 1785 | 1783 | /// This means when a given type is 128 bits and either the simd128 or relaxed-simd |
| 1786 | 1784 | /// features are enabled, the function will return `.direct`. This would allow to store |
| 1787 | 1785 | /// it using a instruction, rather than an unrolled version. |
| 1788 | | fn determineSimdStoreStrategy(ty: Type, mod: *Module) SimdStoreStrategy { |
| 1786 | fn determineSimdStoreStrategy(ty: Type, mod: *Zcu) SimdStoreStrategy { |
| 1789 | 1787 | std.debug.assert(ty.zigTypeTag(mod) == .Vector); |
| 1790 | 1788 | if (ty.bitSize(mod) != 128) return .unrolled; |
| 1791 | 1789 | const hasFeature = std.Target.wasm.featureSetHas; |
| ... | ... | @@ -2325,14 +2323,19 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 2325 | 2323 | WValue{ .imm32 = @as(u32, @truncate(mask)) } |
| 2326 | 2324 | else |
| 2327 | 2325 | WValue{ .imm64 = mask }; |
| 2326 | const wrap_mask_val = if (ptr_info.packed_offset.host_size <= 4) |
| 2327 | WValue{ .imm32 = @truncate(~@as(u64, 0) >> @intCast(64 - ty.bitSize(mod))) } |
| 2328 | else |
| 2329 | WValue{ .imm64 = ~@as(u64, 0) >> @intCast(64 - ty.bitSize(mod)) }; |
| 2328 | 2330 | |
| 2329 | 2331 | try func.emitWValue(lhs); |
| 2330 | 2332 | const loaded = try func.load(lhs, int_elem_ty, 0); |
| 2331 | 2333 | const anded = try func.binOp(loaded, mask_val, int_elem_ty, .@"and"); |
| 2332 | 2334 | const extended_value = try func.intcast(rhs, ty, int_elem_ty); |
| 2335 | const masked_value = try func.binOp(extended_value, wrap_mask_val, int_elem_ty, .@"and"); |
| 2333 | 2336 | 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); |
| 2335 | | } else extended_value; |
| 2337 | break :shifted try func.binOp(masked_value, shift_val, int_elem_ty, .shl); |
| 2338 | } else masked_value; |
| 2336 | 2339 | const result = try func.binOp(anded, shifted_value, int_elem_ty, .@"or"); |
| 2337 | 2340 | // lhs is still on the stack |
| 2338 | 2341 | try func.store(.stack, result, int_elem_ty, lhs.offset()); |
| ... | ... | @@ -2515,7 +2518,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2515 | 2518 | .valtype1 = typeToValtype(ty, mod), |
| 2516 | 2519 | .width = abi_size * 8, |
| 2517 | 2520 | .op = .load, |
| 2518 | | .signedness = .unsigned, |
| 2521 | .signedness = if (ty.isSignedInt(mod)) .signed else .unsigned, |
| 2519 | 2522 | }); |
| 2520 | 2523 | |
| 2521 | 2524 | try func.addMemArg( |
| ... | ... | @@ -2800,10 +2803,7 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2800 | 2803 | switch (wasm_bits) { |
| 2801 | 2804 | 32 => { |
| 2802 | 2805 | try func.emitWValue(operand); |
| 2803 | | if (wasm_bits != int_bits) { |
| 2804 | | try func.addImm32(wasm_bits - int_bits); |
| 2805 | | try func.addTag(.i32_shl); |
| 2806 | | } |
| 2806 | |
| 2807 | 2807 | try func.addImm32(31); |
| 2808 | 2808 | try func.addTag(.i32_shr_s); |
| 2809 | 2809 | |
| ... | ... | @@ -2815,15 +2815,10 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2815 | 2815 | try func.addTag(.i32_xor); |
| 2816 | 2816 | try func.emitWValue(tmp); |
| 2817 | 2817 | try func.addTag(.i32_sub); |
| 2818 | | |
| 2819 | | _ = try func.wrapOperand(.stack, ty); |
| 2820 | 2818 | }, |
| 2821 | 2819 | 64 => { |
| 2822 | 2820 | try func.emitWValue(operand); |
| 2823 | | if (wasm_bits != int_bits) { |
| 2824 | | try func.addImm64(wasm_bits - int_bits); |
| 2825 | | try func.addTag(.i64_shl); |
| 2826 | | } |
| 2821 | |
| 2827 | 2822 | try func.addImm64(63); |
| 2828 | 2823 | try func.addTag(.i64_shr_s); |
| 2829 | 2824 | |
| ... | ... | @@ -2835,8 +2830,6 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2835 | 2830 | try func.addTag(.i64_xor); |
| 2836 | 2831 | try func.emitWValue(tmp); |
| 2837 | 2832 | try func.addTag(.i64_sub); |
| 2838 | | |
| 2839 | | _ = try func.wrapOperand(.stack, ty); |
| 2840 | 2833 | }, |
| 2841 | 2834 | 128 => { |
| 2842 | 2835 | const mask = try func.allocStack(Type.u128); |
| ... | ... | @@ -2844,10 +2837,6 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2844 | 2837 | try func.emitWValue(mask); |
| 2845 | 2838 | |
| 2846 | 2839 | _ = 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 | 2840 | try func.addImm64(63); |
| 2852 | 2841 | try func.addTag(.i64_shr_s); |
| 2853 | 2842 | |
| ... | ... | @@ -2860,9 +2849,8 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2860 | 2849 | |
| 2861 | 2850 | const a = try func.binOpBigInt(operand, mask, Type.u128, .xor); |
| 2862 | 2851 | const b = try func.binOpBigInt(a, mask, Type.u128, .sub); |
| 2863 | | const result = try func.wrapOperand(b, ty); |
| 2864 | 2852 | |
| 2865 | | func.finishAir(inst, result, &.{ty_op.operand}); |
| 2853 | func.finishAir(inst, b, &.{ty_op.operand}); |
| 2866 | 2854 | return; |
| 2867 | 2855 | }, |
| 2868 | 2856 | else => unreachable, |
| ... | ... | @@ -3058,14 +3046,28 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 3058 | 3046 | switch (wasm_bits) { |
| 3059 | 3047 | 32 => { |
| 3060 | 3048 | try func.emitWValue(operand); |
| 3061 | | try func.addImm32((@as(u32, 1) << @intCast(int_bits)) - 1); |
| 3062 | | try func.addTag(.i32_and); |
| 3049 | if (ty.isSignedInt(mod)) { |
| 3050 | try func.addImm32(32 - int_bits); |
| 3051 | try func.addTag(.i32_shl); |
| 3052 | try func.addImm32(32 - int_bits); |
| 3053 | try func.addTag(.i32_shr_s); |
| 3054 | } else { |
| 3055 | try func.addImm32(~@as(u32, 0) >> @intCast(32 - int_bits)); |
| 3056 | try func.addTag(.i32_and); |
| 3057 | } |
| 3063 | 3058 | return .stack; |
| 3064 | 3059 | }, |
| 3065 | 3060 | 64 => { |
| 3066 | 3061 | try func.emitWValue(operand); |
| 3067 | | try func.addImm64((@as(u64, 1) << @intCast(int_bits)) - 1); |
| 3068 | | try func.addTag(.i64_and); |
| 3062 | if (ty.isSignedInt(mod)) { |
| 3063 | try func.addImm64(64 - int_bits); |
| 3064 | try func.addTag(.i64_shl); |
| 3065 | try func.addImm64(64 - int_bits); |
| 3066 | try func.addTag(.i64_shr_s); |
| 3067 | } else { |
| 3068 | try func.addImm64(~@as(u64, 0) >> @intCast(64 - int_bits)); |
| 3069 | try func.addTag(.i64_and); |
| 3070 | } |
| 3069 | 3071 | return .stack; |
| 3070 | 3072 | }, |
| 3071 | 3073 | 128 => { |
| ... | ... | @@ -3078,8 +3080,15 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 3078 | 3080 | |
| 3079 | 3081 | try func.emitWValue(result); |
| 3080 | 3082 | _ = try func.load(operand, Type.u64, 8); |
| 3081 | | try func.addImm64((@as(u64, 1) << @intCast(int_bits - 64)) - 1); |
| 3082 | | try func.addTag(.i64_and); |
| 3083 | if (ty.isSignedInt(mod)) { |
| 3084 | try func.addImm64(128 - int_bits); |
| 3085 | try func.addTag(.i64_shl); |
| 3086 | try func.addImm64(128 - int_bits); |
| 3087 | try func.addTag(.i64_shr_s); |
| 3088 | } else { |
| 3089 | try func.addImm64(~@as(u64, 0) >> @intCast(128 - int_bits)); |
| 3090 | try func.addTag(.i64_and); |
| 3091 | } |
| 3083 | 3092 | try func.store(.stack, .stack, Type.u64, result.offset() + 8); |
| 3084 | 3093 | |
| 3085 | 3094 | return result; |
| ... | ... | @@ -3201,22 +3210,6 @@ fn lowerDeclRefValue(func: *CodeGen, decl_index: InternPool.DeclIndex, offset: u |
| 3201 | 3210 | } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } }; |
| 3202 | 3211 | } |
| 3203 | 3212 | |
| 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 | 3213 | /// Asserts that `isByRef` returns `false` for `ty`. |
| 3221 | 3214 | fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3222 | 3215 | const mod = func.bin_file.base.comp.module.?; |
| ... | ... | @@ -3268,18 +3261,12 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3268 | 3261 | const int_info = ty.intInfo(mod); |
| 3269 | 3262 | switch (int_info.signedness) { |
| 3270 | 3263 | .signed => switch (int_info.bits) { |
| 3271 | | 0...32 => return WValue{ .imm32 = @as(u32, @intCast(toTwosComplement( |
| 3272 | | 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 | | ) }, |
| 3264 | 0...32 => return WValue{ .imm32 = @bitCast(@as(i32, @intCast(val.toSignedInt(mod)))) }, |
| 3265 | 33...64 => return WValue{ .imm64 = @bitCast(val.toSignedInt(mod)) }, |
| 3279 | 3266 | else => unreachable, |
| 3280 | 3267 | }, |
| 3281 | 3268 | .unsigned => switch (int_info.bits) { |
| 3282 | | 0...32 => return WValue{ .imm32 = @as(u32, @intCast(val.toUnsignedInt(mod))) }, |
| 3269 | 0...32 => return WValue{ .imm32 = @intCast(val.toUnsignedInt(mod)) }, |
| 3283 | 3270 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(mod) }, |
| 3284 | 3271 | else => unreachable, |
| 3285 | 3272 | }, |
| ... | ... | @@ -3447,7 +3434,7 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 3447 | 3434 | assert(ptr.base_addr == .int); |
| 3448 | 3435 | return @intCast(ptr.byte_offset); |
| 3449 | 3436 | }, |
| 3450 | | .err => |err| @as(i32, @bitCast(@as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(err.name).?)))), |
| 3437 | .err => |err| @as(i32, @bitCast(@as(Zcu.ErrorInt, @intCast(mod.global_error_set.getIndex(err.name).?)))), |
| 3451 | 3438 | else => unreachable, |
| 3452 | 3439 | }, |
| 3453 | 3440 | } |
| ... | ... | @@ -3458,11 +3445,11 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 3458 | 3445 | }; |
| 3459 | 3446 | } |
| 3460 | 3447 | |
| 3461 | | fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index, mod: *Module) i32 { |
| 3448 | fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index, mod: *Zcu) i32 { |
| 3462 | 3449 | return intStorageAsI32(ip.indexToKey(int).int.storage, mod); |
| 3463 | 3450 | } |
| 3464 | 3451 | |
| 3465 | | fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { |
| 3452 | fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Zcu) i32 { |
| 3466 | 3453 | return switch (storage) { |
| 3467 | 3454 | .i64 => |x| @as(i32, @intCast(x)), |
| 3468 | 3455 | .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))), |
| ... | ... | @@ -3618,29 +3605,11 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3618 | 3605 | // incase of an actual integer, we emit the correct signedness |
| 3619 | 3606 | break :blk ty.intInfo(mod).signedness; |
| 3620 | 3607 | }; |
| 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 | 3608 | |
| 3640 | 3609 | // ensure that when we compare pointers, we emit |
| 3641 | 3610 | // the true pointer of a stack value, rather than the stack pointer. |
| 3642 | | try func.lowerToStack(lhs_wasm); |
| 3643 | | try func.lowerToStack(rhs_wasm); |
| 3611 | try func.lowerToStack(lhs); |
| 3612 | try func.lowerToStack(rhs); |
| 3644 | 3613 | |
| 3645 | 3614 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 3646 | 3615 | .valtype1 = typeToValtype(ty, mod), |
| ... | ... | @@ -3760,32 +3729,49 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3760 | 3729 | try func.addLabel(.local_set, not_tmp.local.value); |
| 3761 | 3730 | break :result not_tmp; |
| 3762 | 3731 | } else { |
| 3763 | | const operand_bits = operand_ty.intInfo(mod).bits; |
| 3764 | | const wasm_bits = toWasmBits(operand_bits) orelse { |
| 3765 | | return func.fail("TODO: Implement binary NOT for integer with bitsize '{d}'", .{operand_bits}); |
| 3732 | const int_info = operand_ty.intInfo(mod); |
| 3733 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 3734 | return func.fail("TODO: Implement binary NOT for {}", .{operand_ty.fmt(mod)}); |
| 3766 | 3735 | }; |
| 3767 | 3736 | |
| 3768 | 3737 | switch (wasm_bits) { |
| 3769 | 3738 | 32 => { |
| 3770 | | const bin_op = try func.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); |
| 3771 | | break :result try (try func.wrapOperand(bin_op, operand_ty)).toLocal(func, operand_ty); |
| 3739 | try func.emitWValue(operand); |
| 3740 | try func.addImm32(switch (int_info.signedness) { |
| 3741 | .unsigned => ~@as(u32, 0) >> @intCast(32 - int_info.bits), |
| 3742 | .signed => ~@as(u32, 0), |
| 3743 | }); |
| 3744 | try func.addTag(.i32_xor); |
| 3745 | break :result try @as(WValue, .stack).toLocal(func, operand_ty); |
| 3772 | 3746 | }, |
| 3773 | 3747 | 64 => { |
| 3774 | | const bin_op = try func.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); |
| 3775 | | break :result try (try func.wrapOperand(bin_op, operand_ty)).toLocal(func, operand_ty); |
| 3748 | try func.emitWValue(operand); |
| 3749 | try func.addImm64(switch (int_info.signedness) { |
| 3750 | .unsigned => ~@as(u64, 0) >> @intCast(64 - int_info.bits), |
| 3751 | .signed => ~@as(u64, 0), |
| 3752 | }); |
| 3753 | try func.addTag(.i64_xor); |
| 3754 | break :result try @as(WValue, .stack).toLocal(func, operand_ty); |
| 3776 | 3755 | }, |
| 3777 | 3756 | 128 => { |
| 3778 | | const result_ptr = try func.allocStack(operand_ty); |
| 3779 | | try func.emitWValue(result_ptr); |
| 3780 | | const msb = try func.load(operand, Type.u64, 0); |
| 3781 | | const msb_xor = try func.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 3782 | | try func.store(.{ .stack = {} }, msb_xor, Type.u64, 0 + result_ptr.offset()); |
| 3783 | | |
| 3784 | | try func.emitWValue(result_ptr); |
| 3785 | | const lsb = try func.load(operand, Type.u64, 8); |
| 3786 | | const lsb_xor = try func.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 3787 | | try func.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset()); |
| 3788 | | break :result result_ptr; |
| 3757 | const ptr = try func.allocStack(operand_ty); |
| 3758 | |
| 3759 | try func.emitWValue(ptr); |
| 3760 | _ = try func.load(operand, Type.u64, 0); |
| 3761 | try func.addImm64(~@as(u64, 0)); |
| 3762 | try func.addTag(.i64_xor); |
| 3763 | try func.store(.stack, .stack, Type.u64, ptr.offset()); |
| 3764 | |
| 3765 | try func.emitWValue(ptr); |
| 3766 | _ = try func.load(operand, Type.u64, 8); |
| 3767 | try func.addImm64(switch (int_info.signedness) { |
| 3768 | .unsigned => ~@as(u64, 0) >> @intCast(128 - int_info.bits), |
| 3769 | .signed => ~@as(u64, 0), |
| 3770 | }); |
| 3771 | try func.addTag(.i64_xor); |
| 3772 | try func.store(.stack, .stack, Type.u64, ptr.offset() + 8); |
| 3773 | |
| 3774 | break :result ptr; |
| 3789 | 3775 | }, |
| 3790 | 3776 | else => unreachable, |
| 3791 | 3777 | } |
| ... | ... | @@ -3812,25 +3798,44 @@ fn airUnreachable(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3812 | 3798 | } |
| 3813 | 3799 | |
| 3814 | 3800 | fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3801 | const mod = func.bin_file.base.comp.module.?; |
| 3815 | 3802 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3803 | const operand = try func.resolveInst(ty_op.operand); |
| 3804 | const wanted_ty = func.typeOfIndex(inst); |
| 3805 | const given_ty = func.typeOf(ty_op.operand); |
| 3806 | |
| 3807 | const bit_size = given_ty.bitSize(mod); |
| 3808 | const needs_wrapping = (given_ty.isSignedInt(mod) != wanted_ty.isSignedInt(mod)) and |
| 3809 | bit_size != 32 and bit_size != 64 and bit_size != 128; |
| 3810 | |
| 3816 | 3811 | 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 | 3812 | if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) { |
| 3821 | 3813 | const bitcast_result = try func.bitcast(wanted_ty, given_ty, operand); |
| 3822 | 3814 | break :result try bitcast_result.toLocal(func, wanted_ty); |
| 3823 | 3815 | } |
| 3824 | | const mod = func.bin_file.base.comp.module.?; |
| 3816 | |
| 3825 | 3817 | if (isByRef(given_ty, mod) and !isByRef(wanted_ty, mod)) { |
| 3826 | 3818 | const loaded_memory = try func.load(operand, wanted_ty, 0); |
| 3827 | | break :result try loaded_memory.toLocal(func, wanted_ty); |
| 3819 | if (needs_wrapping) { |
| 3820 | break :result try (try func.wrapOperand(loaded_memory, wanted_ty)).toLocal(func, wanted_ty); |
| 3821 | } else { |
| 3822 | break :result try loaded_memory.toLocal(func, wanted_ty); |
| 3823 | } |
| 3828 | 3824 | } |
| 3829 | 3825 | if (!isByRef(given_ty, mod) and isByRef(wanted_ty, mod)) { |
| 3830 | 3826 | const stack_memory = try func.allocStack(wanted_ty); |
| 3831 | 3827 | try func.store(stack_memory, operand, given_ty, 0); |
| 3832 | | break :result stack_memory; |
| 3828 | if (needs_wrapping) { |
| 3829 | break :result try (try func.wrapOperand(stack_memory, wanted_ty)).toLocal(func, wanted_ty); |
| 3830 | } else { |
| 3831 | break :result stack_memory; |
| 3832 | } |
| 3833 | } |
| 3834 | |
| 3835 | if (needs_wrapping) { |
| 3836 | break :result try (try func.wrapOperand(operand, wanted_ty)).toLocal(func, wanted_ty); |
| 3833 | 3837 | } |
| 3838 | |
| 3834 | 3839 | break :result func.reuseOperand(ty_op.operand, operand); |
| 3835 | 3840 | }; |
| 3836 | 3841 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | ... | @@ -4355,7 +4360,7 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4355 | 4360 | |
| 4356 | 4361 | const op_bits = toWasmBits(@as(u16, @intCast(operand_ty.bitSize(mod)))).?; |
| 4357 | 4362 | const wanted_bits = toWasmBits(@as(u16, @intCast(ty.bitSize(mod)))).?; |
| 4358 | | const result = if (op_bits == wanted_bits and !ty.isSignedInt(mod)) |
| 4363 | const result = if (op_bits == wanted_bits) |
| 4359 | 4364 | func.reuseOperand(ty_op.operand, operand) |
| 4360 | 4365 | else |
| 4361 | 4366 | try (try func.intcast(operand, operand_ty, ty)).toLocal(func, ty); |
| ... | ... | @@ -4377,37 +4382,17 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4377 | 4382 | const op_bits = toWasmBits(given_bitsize).?; |
| 4378 | 4383 | const wanted_bits = toWasmBits(wanted_bitsize).?; |
| 4379 | 4384 | 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 | 4385 | return operand; |
| 4391 | 4386 | } |
| 4392 | 4387 | |
| 4393 | | if (op_bits > 32 and op_bits <= 64 and wanted_bits == 32) { |
| 4388 | if (op_bits == 64 and wanted_bits == 32) { |
| 4394 | 4389 | try func.emitWValue(operand); |
| 4395 | 4390 | try func.addTag(.i32_wrap_i64); |
| 4396 | | if (given.isSignedInt(mod) and wanted_bitsize < 32) |
| 4397 | | return func.wrapOperand(.{ .stack = {} }, wanted) |
| 4398 | | else |
| 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); |
| 4391 | return .stack; |
| 4392 | } else if (op_bits == 32 and wanted_bits == 64) { |
| 4393 | try func.emitWValue(operand); |
| 4406 | 4394 | 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) |
| 4408 | | return func.wrapOperand(.{ .stack = {} }, wanted) |
| 4409 | | else |
| 4410 | | return WValue{ .stack = {} }; |
| 4395 | return .stack; |
| 4411 | 4396 | } else if (wanted_bits == 128) { |
| 4412 | 4397 | // for 128bit integers we store the integer in the virtual stack, rather than a local |
| 4413 | 4398 | const stack_ptr = try func.allocStack(wanted); |
| ... | ... | @@ -4416,17 +4401,18 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4416 | 4401 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it |
| 4417 | 4402 | // meaning less store operations are required. |
| 4418 | 4403 | const lhs = if (op_bits == 32) blk: { |
| 4419 | | break :blk try func.intcast(operand, given, if (wanted.isSignedInt(mod)) Type.i64 else Type.u64); |
| 4404 | const sign_ty = if (wanted.isSignedInt(mod)) Type.i64 else Type.u64; |
| 4405 | break :blk try (try func.intcast(operand, given, sign_ty)).toLocal(func, sign_ty); |
| 4420 | 4406 | } else operand; |
| 4421 | 4407 | |
| 4422 | 4408 | // store msb first |
| 4423 | | try func.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 4409 | try func.store(.stack, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 4424 | 4410 | |
| 4425 | 4411 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 4426 | 4412 | if (wanted.isSignedInt(mod)) { |
| 4427 | 4413 | try func.emitWValue(stack_ptr); |
| 4428 | 4414 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| 4429 | | try func.store(.{ .stack = {} }, shr, Type.u64, 8 + stack_ptr.offset()); |
| 4415 | try func.store(.stack, shr, Type.u64, 8 + stack_ptr.offset()); |
| 4430 | 4416 | } else { |
| 4431 | 4417 | // Ensure memory of lsb is zero'd |
| 4432 | 4418 | try func.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); |
| ... | ... | @@ -5823,25 +5809,34 @@ fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5823 | 5809 | }; |
| 5824 | 5810 | |
| 5825 | 5811 | switch (wasm_bits) { |
| 5812 | 32 => { |
| 5813 | try func.emitWValue(operand); |
| 5814 | if (op_ty.isSignedInt(mod) and bits != wasm_bits) { |
| 5815 | _ = try func.wrapOperand(.stack, try mod.intType(.unsigned, bits)); |
| 5816 | } |
| 5817 | try func.addTag(.i32_popcnt); |
| 5818 | }, |
| 5819 | 64 => { |
| 5820 | try func.emitWValue(operand); |
| 5821 | if (op_ty.isSignedInt(mod) and bits != wasm_bits) { |
| 5822 | _ = try func.wrapOperand(.stack, try mod.intType(.unsigned, bits)); |
| 5823 | } |
| 5824 | try func.addTag(.i64_popcnt); |
| 5825 | try func.addTag(.i32_wrap_i64); |
| 5826 | try func.emitWValue(operand); |
| 5827 | }, |
| 5826 | 5828 | 128 => { |
| 5827 | 5829 | _ = try func.load(operand, Type.u64, 0); |
| 5828 | 5830 | try func.addTag(.i64_popcnt); |
| 5829 | 5831 | _ = try func.load(operand, Type.u64, 8); |
| 5832 | if (op_ty.isSignedInt(mod) and bits != wasm_bits) { |
| 5833 | _ = try func.wrapOperand(.stack, try mod.intType(.unsigned, bits - 64)); |
| 5834 | } |
| 5830 | 5835 | try func.addTag(.i64_popcnt); |
| 5831 | 5836 | try func.addTag(.i64_add); |
| 5832 | 5837 | try func.addTag(.i32_wrap_i64); |
| 5833 | 5838 | }, |
| 5834 | | else => { |
| 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 | | }, |
| 5839 | else => unreachable, |
| 5845 | 5840 | } |
| 5846 | 5841 | |
| 5847 | 5842 | const result = try func.allocLocal(result_ty); |
| ... | ... | @@ -5877,7 +5872,7 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5877 | 5872 | const reversed = if (bits == 32) |
| 5878 | 5873 | intrin_ret |
| 5879 | 5874 | else |
| 5880 | | try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, Type.u32, .shr); |
| 5875 | try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, ty, .shr); |
| 5881 | 5876 | const result = try reversed.toLocal(func, ty); |
| 5882 | 5877 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5883 | 5878 | }, |
| ... | ... | @@ -5891,7 +5886,7 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5891 | 5886 | const reversed = if (bits == 64) |
| 5892 | 5887 | intrin_ret |
| 5893 | 5888 | else |
| 5894 | | try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, Type.u64, .shr); |
| 5889 | try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, ty, .shr); |
| 5895 | 5890 | const result = try reversed.toLocal(func, ty); |
| 5896 | 5891 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5897 | 5892 | }, |
| ... | ... | @@ -5928,7 +5923,11 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5928 | 5923 | defer tmp.free(func); |
| 5929 | 5924 | try func.addLabel(.local_tee, tmp.local.value); |
| 5930 | 5925 | try func.emitWValue(.{ .imm64 = 128 - bits }); |
| 5931 | | try func.addTag(.i64_shr_u); |
| 5926 | if (ty.isSignedInt(mod)) { |
| 5927 | try func.addTag(.i64_shr_s); |
| 5928 | } else { |
| 5929 | try func.addTag(.i64_shr_u); |
| 5930 | } |
| 5932 | 5931 | try func.store(.stack, .stack, Type.u64, result.offset() + 8); |
| 5933 | 5932 | try func.addLabel(.local_get, tmp.local.value); |
| 5934 | 5933 | try func.emitWValue(.{ .imm64 = bits - 64 }); |
| ... | ... | @@ -5996,8 +5995,8 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5996 | 5995 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 5997 | 5996 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5998 | 5997 | |
| 5999 | | const lhs_op = try func.resolveInst(extra.lhs); |
| 6000 | | const rhs_op = try func.resolveInst(extra.rhs); |
| 5998 | const lhs = try func.resolveInst(extra.lhs); |
| 5999 | const rhs = try func.resolveInst(extra.rhs); |
| 6001 | 6000 | const lhs_ty = func.typeOf(extra.lhs); |
| 6002 | 6001 | const mod = func.bin_file.base.comp.module.?; |
| 6003 | 6002 | |
| ... | ... | @@ -6012,7 +6011,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 6012 | 6011 | }; |
| 6013 | 6012 | |
| 6014 | 6013 | if (wasm_bits == 128) { |
| 6015 | | const result = try func.addSubWithOverflowBigInt(lhs_op, rhs_op, lhs_ty, func.typeOfIndex(inst), op); |
| 6014 | const result = try func.addSubWithOverflowBigInt(lhs, rhs, lhs_ty, func.typeOfIndex(inst), op); |
| 6016 | 6015 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); |
| 6017 | 6016 | } |
| 6018 | 6017 | |
| ... | ... | @@ -6022,24 +6021,6 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 6022 | 6021 | else => unreachable, |
| 6023 | 6022 | }; |
| 6024 | 6023 | |
| 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 | 6024 | const bin_op = try (try func.binOp(lhs, rhs, lhs_ty, op)).toLocal(func, lhs_ty); |
| 6044 | 6025 | var result = if (wasm_bits != int_info.bits) blk: { |
| 6045 | 6026 | break :blk try (try func.wrapOperand(bin_op, lhs_ty)).toLocal(func, lhs_ty); |
| ... | ... | @@ -6053,8 +6034,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 6053 | 6034 | const lt = try func.cmp(bin_op, lhs, lhs_ty, .lt); |
| 6054 | 6035 | break :blk try func.binOp(cmp_zero, lt, Type.u32, .xor); |
| 6055 | 6036 | } |
| 6056 | | const abs = try func.signExtendInt(bin_op, lhs_ty); |
| 6057 | | break :blk try func.cmp(abs, bin_op, lhs_ty, .neq); |
| 6037 | break :blk try func.cmp(bin_op, bin_op, lhs_ty, .neq); |
| 6058 | 6038 | } else if (wasm_bits == int_info.bits) |
| 6059 | 6039 | try func.cmp(bin_op, lhs, lhs_ty, cmp_op) |
| 6060 | 6040 | else |
| ... | ... | @@ -6150,7 +6130,6 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6150 | 6130 | } |
| 6151 | 6131 | |
| 6152 | 6132 | const int_info = lhs_ty.intInfo(mod); |
| 6153 | | const is_signed = int_info.signedness == .signed; |
| 6154 | 6133 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6155 | 6134 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 6156 | 6135 | }; |
| ... | ... | @@ -6170,13 +6149,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6170 | 6149 | } else shl; |
| 6171 | 6150 | defer result.free(func); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits) |
| 6172 | 6151 | |
| 6173 | | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) 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: { |
| 6152 | const overflow_bit = blk: { |
| 6180 | 6153 | try func.emitWValue(lhs); |
| 6181 | 6154 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); |
| 6182 | 6155 | break :blk try func.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); |
| ... | ... | @@ -6245,10 +6218,8 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6245 | 6218 | break :blk down_cast; |
| 6246 | 6219 | } |
| 6247 | 6220 | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { |
| 6248 | | const lhs_abs = try func.signExtendInt(lhs, lhs_ty); |
| 6249 | | const rhs_abs = try func.signExtendInt(rhs, 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); |
| 6221 | const bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| 6222 | const mul_abs = try func.wrapOperand(bin_op, lhs_ty); |
| 6252 | 6223 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 6253 | 6224 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6254 | 6225 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| ... | ... | @@ -6697,6 +6668,9 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6697 | 6668 | return func.fail("TODO: @byteSwap for vectors", .{}); |
| 6698 | 6669 | } |
| 6699 | 6670 | const int_info = ty.intInfo(mod); |
| 6671 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6672 | return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}); |
| 6673 | }; |
| 6700 | 6674 | |
| 6701 | 6675 | // bytes are no-op |
| 6702 | 6676 | if (int_info.bits == 8) { |
| ... | ... | @@ -6704,73 +6678,34 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6704 | 6678 | } |
| 6705 | 6679 | |
| 6706 | 6680 | const result = result: { |
| 6707 | | switch (int_info.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 | | }, |
| 6681 | switch (wasm_bits) { |
| 6737 | 6682 | 32 => { |
| 6738 | | const shl_tmp = try func.binOp(operand, .{ .imm32 = 8 }, Type.u32, .shl); |
| 6739 | | const lhs = try func.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, Type.u32, .@"and"); |
| 6740 | | const shr_tmp = try func.binOp(operand, .{ .imm32 = 8 }, Type.u32, .shr); |
| 6741 | | const rhs = try func.binOp(shr_tmp, .{ .imm32 = 0x00FF00FF }, Type.u32, .@"and"); |
| 6742 | | var tmp_or = try (try func.binOp(lhs, rhs, Type.u32, .@"or")).toLocal(func, Type.u32); |
| 6743 | | |
| 6744 | | const shl = try func.binOp(tmp_or, .{ .imm32 = 16 }, Type.u32, .shl); |
| 6745 | | const shr = try func.binOp(tmp_or, .{ .imm32 = 16 }, Type.u32, .shr); |
| 6746 | | |
| 6747 | | tmp_or.free(func); |
| 6683 | const intrin_ret = try func.callIntrinsic( |
| 6684 | "__bswapsi2", |
| 6685 | &.{.u32_type}, |
| 6686 | Type.u32, |
| 6687 | &.{operand}, |
| 6688 | ); |
| 6689 | const swapped = if (int_info.bits == 32) |
| 6690 | intrin_ret |
| 6691 | else |
| 6692 | try func.binOp(intrin_ret, .{ .imm32 = 32 - int_info.bits }, ty, .shr); |
| 6748 | 6693 | |
| 6749 | | break :result try (try func.binOp(shl, shr, Type.u32, .@"or")).toLocal(func, Type.u32); |
| 6694 | break :result try swapped.toLocal(func, ty); |
| 6750 | 6695 | }, |
| 6751 | 6696 | 64 => { |
| 6752 | | const shl_tmp_1 = try func.binOp(operand, .{ .imm64 = 8 }, Type.u64, .shl); |
| 6753 | | const lhs_1 = try func.binOp(shl_tmp_1, .{ .imm64 = 0xFF00FF00FF00FF00 }, Type.u64, .@"and"); |
| 6754 | | |
| 6755 | | const shr_tmp_1 = try func.binOp(operand, .{ .imm64 = 8 }, Type.u64, .shr); |
| 6756 | | const rhs_1 = try func.binOp(shr_tmp_1, .{ .imm64 = 0x00FF00FF00FF00FF }, Type.u64, .@"and"); |
| 6757 | | |
| 6758 | | var tmp_or_1 = try (try func.binOp(lhs_1, rhs_1, Type.u64, .@"or")).toLocal(func, Type.u64); |
| 6759 | | |
| 6760 | | const shl_tmp_2 = try func.binOp(tmp_or_1, .{ .imm64 = 16 }, Type.u64, .shl); |
| 6761 | | const lhs_2 = try func.binOp(shl_tmp_2, .{ .imm64 = 0xFFFF0000FFFF0000 }, Type.u64, .@"and"); |
| 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); |
| 6697 | const intrin_ret = try func.callIntrinsic( |
| 6698 | "__bswapdi2", |
| 6699 | &.{.u64_type}, |
| 6700 | Type.u64, |
| 6701 | &.{operand}, |
| 6702 | ); |
| 6703 | const swapped = if (int_info.bits == 64) |
| 6704 | intrin_ret |
| 6705 | else |
| 6706 | try func.binOp(intrin_ret, .{ .imm64 = 64 - int_info.bits }, ty, .shr); |
| 6772 | 6707 | |
| 6773 | | break :result try (try func.binOp(shl, shr, Type.u64, .@"or")).toLocal(func, Type.u64); |
| 6708 | break :result try swapped.toLocal(func, ty); |
| 6774 | 6709 | }, |
| 6775 | 6710 | else => return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), |
| 6776 | 6711 | } |
| ... | ... | @@ -6779,32 +6714,24 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6779 | 6714 | } |
| 6780 | 6715 | |
| 6781 | 6716 | fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6782 | | const mod = func.bin_file.base.comp.module.?; |
| 6783 | 6717 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6784 | 6718 | |
| 6785 | 6719 | const ty = func.typeOfIndex(inst); |
| 6786 | 6720 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6787 | 6721 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6788 | 6722 | |
| 6789 | | const result = if (ty.isSignedInt(mod)) |
| 6790 | | try func.divSigned(lhs, rhs, ty) |
| 6791 | | else |
| 6792 | | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6723 | const result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6793 | 6724 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 6794 | 6725 | } |
| 6795 | 6726 | |
| 6796 | 6727 | fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6797 | | const mod = func.bin_file.base.comp.module.?; |
| 6798 | 6728 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6799 | 6729 | |
| 6800 | 6730 | const ty = func.typeOfIndex(inst); |
| 6801 | 6731 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6802 | 6732 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6803 | 6733 | |
| 6804 | | const div_result = if (ty.isSignedInt(mod)) |
| 6805 | | try func.divSigned(lhs, rhs, ty) |
| 6806 | | else |
| 6807 | | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6734 | const div_result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6808 | 6735 | |
| 6809 | 6736 | if (ty.isAnyFloat()) { |
| 6810 | 6737 | const trunc_result = try (try func.floatOp(.trunc, ty, &.{div_result})).toLocal(func, ty); |
| ... | ... | @@ -6834,16 +6761,6 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6834 | 6761 | return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| 6835 | 6762 | } |
| 6836 | 6763 | |
| 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 | 6764 | const zero = switch (wasm_bits) { |
| 6848 | 6765 | 32 => WValue{ .imm32 = 0 }, |
| 6849 | 6766 | 64 => WValue{ .imm64 = 0 }, |
| ... | ... | @@ -6852,7 +6769,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6852 | 6769 | |
| 6853 | 6770 | // tee leaves the value on the stack and stores it in a local. |
| 6854 | 6771 | const quotient = try func.allocLocal(ty); |
| 6855 | | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .div); |
| 6772 | _ = try func.binOp(lhs, rhs, ty, .div); |
| 6856 | 6773 | try func.addLabel(.local_tee, quotient.local.value); |
| 6857 | 6774 | |
| 6858 | 6775 | // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow |
| ... | ... | @@ -6864,7 +6781,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6864 | 6781 | } |
| 6865 | 6782 | |
| 6866 | 6783 | // 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); |
| 6784 | _ = try func.binOp(lhs, rhs, ty, .xor); |
| 6868 | 6785 | _ = try func.cmp(.stack, zero, ty, .lt); |
| 6869 | 6786 | |
| 6870 | 6787 | switch (wasm_bits) { |
| ... | ... | @@ -6879,7 +6796,7 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6879 | 6796 | else => unreachable, |
| 6880 | 6797 | } |
| 6881 | 6798 | |
| 6882 | | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .rem); |
| 6799 | _ = try func.binOp(lhs, rhs, ty, .rem); |
| 6883 | 6800 | |
| 6884 | 6801 | if (wasm_bits == 64) { |
| 6885 | 6802 | try func.addTag(.i64_eqz); |
| ... | ... | @@ -6929,68 +6846,14 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6929 | 6846 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 6930 | 6847 | } |
| 6931 | 6848 | |
| 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 | 6849 | fn airRem(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6964 | 6850 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6965 | 6851 | |
| 6966 | | const mod = func.bin_file.base.comp.module.?; |
| 6967 | 6852 | const ty = func.typeOfIndex(inst); |
| 6968 | 6853 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6969 | 6854 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6970 | 6855 | |
| 6971 | | const result = if (ty.isSignedInt(mod)) result: { |
| 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); |
| 6856 | const result = try func.binOp(lhs, rhs, ty, .rem); |
| 6994 | 6857 | |
| 6995 | 6858 | const return_local = try result.toLocal(func, ty); |
| 6996 | 6859 | func.finishAir(inst, return_local, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | ... | @@ -7022,19 +6885,9 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7022 | 6885 | return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| 7023 | 6886 | } |
| 7024 | 6887 | |
| 7025 | | const lhs_wasm = if (wasm_bits != int_bits) |
| 7026 | | try (try func.signExtendInt(lhs, ty)).toLocal(func, ty) |
| 7027 | | else |
| 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); |
| 6888 | _ = try func.binOp(lhs, rhs, ty, .rem); |
| 6889 | _ = try func.binOp(.stack, rhs, ty, .add); |
| 6890 | _ = try func.binOp(.stack, rhs, ty, .rem); |
| 7038 | 6891 | } else { |
| 7039 | 6892 | return func.fail("TODO: implement `@mod` on floating point types for {}", .{func.target.cpu.arch}); |
| 7040 | 6893 | } |
| ... | ... | @@ -7044,42 +6897,6 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7044 | 6897 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 7045 | 6898 | } |
| 7046 | 6899 | |
| 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 | 6900 | fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 7084 | 6901 | assert(op == .add or op == .sub); |
| 7085 | 6902 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -7131,20 +6948,13 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 7131 | 6948 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 7132 | 6949 | } |
| 7133 | 6950 | |
| 7134 | | fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op: Op) InnerError!WValue { |
| 6951 | fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 7135 | 6952 | const mod = func.bin_file.base.comp.module.?; |
| 7136 | 6953 | const int_info = ty.intInfo(mod); |
| 7137 | 6954 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 7138 | 6955 | const is_wasm_bits = wasm_bits == int_info.bits; |
| 7139 | 6956 | const ext_ty = if (!is_wasm_bits) try mod.intType(int_info.signedness, wasm_bits) else ty; |
| 7140 | 6957 | |
| 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 | 6958 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); |
| 7149 | 6959 | const min_val: i64 = (-@as(i64, @intCast(@as(u63, @intCast(max_val))))) - 1; |
| 7150 | 6960 | const max_wvalue = switch (wasm_bits) { |
| ... | ... | @@ -7161,8 +6971,6 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, |
| 7161 | 6971 | var bin_result = try (try func.binOp(lhs, rhs, ext_ty, op)).toLocal(func, ext_ty); |
| 7162 | 6972 | if (!is_wasm_bits) { |
| 7163 | 6973 | 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 | 6974 | try func.emitWValue(bin_result); |
| 7167 | 6975 | try func.emitWValue(max_wvalue); |
| 7168 | 6976 | _ = try func.cmp(bin_result, max_wvalue, ext_ty, .lt); |
| ... | ... | @@ -7547,7 +7355,7 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7547 | 7355 | var lowest: ?u32 = null; |
| 7548 | 7356 | var highest: ?u32 = null; |
| 7549 | 7357 | for (0..names.len) |name_index| { |
| 7550 | | const err_int: Module.ErrorInt = @intCast(mod.global_error_set.getIndex(names.get(ip)[name_index]).?); |
| 7358 | const err_int: Zcu.ErrorInt = @intCast(mod.global_error_set.getIndex(names.get(ip)[name_index]).?); |
| 7551 | 7359 | if (lowest) |*l| { |
| 7552 | 7360 | if (err_int < l.*) { |
| 7553 | 7361 | l.* = err_int; |