authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2024-06-23 13:28:39+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-06-24 20:50:39+02:00
log3e9ab6aa7b2d90c25cb906d425a148abf9da3dcb
tree4dd8938e6995381cd8a6cccdb1cd3896bfb41f1c
parentab4c461b76ff7b1d10e6d2010370ea0984f97efe

stage2-wasm: abs 128 bit


2 files changed, 175 insertions(+), 82 deletions(-)

src/arch/wasm/CodeGen.zig+111-82
...@@ -918,8 +918,11 @@ fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!vo...@@ -918,8 +918,11 @@ fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!vo
918 try func.addInst(.{ .tag = tag, .data = .{ .label = label } });918 try func.addInst(.{ .tag = tag, .data = .{ .label = label } });
919}919}
920920
921fn addImm32(func: *CodeGen, imm: i32) error{OutOfMemory}!void {921/// Accepts an unsigned 32bit integer rather than a signed integer to
922 try func.addInst(.{ .tag = .i32_const, .data = .{ .imm32 = imm } });922/// prevent us from having to bitcast multiple times as most values
923/// within codegen are represented as unsigned rather than signed.
924fn addImm32(func: *CodeGen, imm: u32) error{OutOfMemory}!void {
925 try func.addInst(.{ .tag = .i32_const, .data = .{ .imm32 = @bitCast(imm) } });
923}926}
924927
925/// Accepts an unsigned 64bit integer rather than a signed integer to928/// Accepts an unsigned 64bit integer rather than a signed integer to
...@@ -1049,7 +1052,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {...@@ -1049,7 +1052,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
1049 .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?)1052 .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?)
1050 .none, .stack => {}, // no-op1053 .none, .stack => {}, // no-op
1051 .local => |idx| try func.addLabel(.local_get, idx.value),1054 .local => |idx| try func.addLabel(.local_get, idx.value),
1052 .imm32 => |val| try func.addImm32(@as(i32, @bitCast(val))),1055 .imm32 => |val| try func.addImm32(val),
1053 .imm64 => |val| try func.addImm64(val),1056 .imm64 => |val| try func.addImm64(val),
1054 .imm128 => |val| try func.addImm128(val),1057 .imm128 => |val| try func.addImm128(val),
1055 .float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),1058 .float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
...@@ -1467,7 +1470,7 @@ fn lowerToStack(func: *CodeGen, value: WValue) !void {...@@ -1467,7 +1470,7 @@ fn lowerToStack(func: *CodeGen, value: WValue) !void {
1467 if (offset.value > 0) {1470 if (offset.value > 0) {
1468 switch (func.arch()) {1471 switch (func.arch()) {
1469 .wasm32 => {1472 .wasm32 => {
1470 try func.addImm32(@as(i32, @bitCast(offset.value)));1473 try func.addImm32(offset.value);
1471 try func.addTag(.i32_add);1474 try func.addTag(.i32_add);
1472 },1475 },
1473 .wasm64 => {1476 .wasm64 => {
...@@ -1809,7 +1812,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en...@@ -1809,7 +1812,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en
1809 if (offset + ptr_value.offset() > 0) {1812 if (offset + ptr_value.offset() > 0) {
1810 switch (func.arch()) {1813 switch (func.arch()) {
1811 .wasm32 => {1814 .wasm32 => {
1812 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(offset + ptr_value.offset())))));1815 try func.addImm32(@intCast(offset + ptr_value.offset()));
1813 try func.addTag(.i32_add);1816 try func.addTag(.i32_add);
1814 },1817 },
1815 .wasm64 => {1818 .wasm64 => {
...@@ -2794,11 +2797,9 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2794,11 +2797,9 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2794 return func.fail("TODO: airAbs for signed integers larger than '{d}' bits", .{int_bits});2797 return func.fail("TODO: airAbs for signed integers larger than '{d}' bits", .{int_bits});
2795 };2798 };
27962799
2797 const op = try operand.toLocal(func, ty);
2798
2799 try func.emitWValue(op);
2800 switch (wasm_bits) {2800 switch (wasm_bits) {
2801 32 => {2801 32 => {
2802 try func.emitWValue(operand);
2802 if (wasm_bits != int_bits) {2803 if (wasm_bits != int_bits) {
2803 try func.addImm32(wasm_bits - int_bits);2804 try func.addImm32(wasm_bits - int_bits);
2804 try func.addTag(.i32_shl);2805 try func.addTag(.i32_shl);
...@@ -2806,20 +2807,19 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2806,20 +2807,19 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2806 try func.addImm32(31);2807 try func.addImm32(31);
2807 try func.addTag(.i32_shr_s);2808 try func.addTag(.i32_shr_s);
28082809
2809 const tmp = try func.allocLocal(ty);2810 var tmp = try func.allocLocal(ty);
2811 defer tmp.free(func);
2810 try func.addLabel(.local_tee, tmp.local.value);2812 try func.addLabel(.local_tee, tmp.local.value);
28112813
2812 try func.emitWValue(op);2814 try func.emitWValue(operand);
2813 try func.addTag(.i32_xor);2815 try func.addTag(.i32_xor);
2814 try func.emitWValue(tmp);2816 try func.emitWValue(tmp);
2815 try func.addTag(.i32_sub);2817 try func.addTag(.i32_sub);
28162818
2817 if (int_bits != wasm_bits) {2819 _ = try func.wrapOperand(.stack, ty);
2818 try func.emitWValue(WValue{ .imm32 = (@as(u32, 1) << @intCast(int_bits)) - 1 });
2819 try func.addTag(.i32_and);
2820 }
2821 },2820 },
2822 64 => {2821 64 => {
2822 try func.emitWValue(operand);
2823 if (wasm_bits != int_bits) {2823 if (wasm_bits != int_bits) {
2824 try func.addImm64(wasm_bits - int_bits);2824 try func.addImm64(wasm_bits - int_bits);
2825 try func.addTag(.i64_shl);2825 try func.addTag(.i64_shl);
...@@ -2827,20 +2827,45 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2827,20 +2827,45 @@ fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2827 try func.addImm64(63);2827 try func.addImm64(63);
2828 try func.addTag(.i64_shr_s);2828 try func.addTag(.i64_shr_s);
28292829
2830 const tmp = try func.allocLocal(ty);2830 var tmp = try func.allocLocal(ty);
2831 defer tmp.free(func);
2831 try func.addLabel(.local_tee, tmp.local.value);2832 try func.addLabel(.local_tee, tmp.local.value);
28322833
2833 try func.emitWValue(op);2834 try func.emitWValue(operand);
2834 try func.addTag(.i64_xor);2835 try func.addTag(.i64_xor);
2835 try func.emitWValue(tmp);2836 try func.emitWValue(tmp);
2836 try func.addTag(.i64_sub);2837 try func.addTag(.i64_sub);
28372838
2838 if (int_bits != wasm_bits) {2839 _ = try func.wrapOperand(.stack, ty);
2839 try func.emitWValue(WValue{ .imm64 = (@as(u64, 1) << @intCast(int_bits)) - 1 });2840 },
2840 try func.addTag(.i64_and);2841 128 => {
2842 const mask = try func.allocStack(Type.u128);
2843 try func.emitWValue(mask);
2844 try func.emitWValue(mask);
2845
2846 _ = 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);
2841 }2850 }
2851 try func.addImm64(63);
2852 try func.addTag(.i64_shr_s);
2853
2854 var tmp = try func.allocLocal(Type.u64);
2855 defer tmp.free(func);
2856 try func.addLabel(.local_tee, tmp.local.value);
2857 try func.store(.stack, .stack, Type.u64, mask.offset() + 0);
2858 try func.emitWValue(tmp);
2859 try func.store(.stack, .stack, Type.u64, mask.offset() + 8);
2860
2861 const a = try func.binOpBigInt(operand, mask, Type.u128, .xor);
2862 const b = try func.binOpBigInt(a, mask, Type.u128, .sub);
2863 const result = try func.wrapOperand(b, ty);
2864
2865 func.finishAir(inst, result, &.{ty_op.operand});
2866 return;
2842 },2867 },
2843 else => return func.fail("TODO: Implement airAbs for {}", .{ty.fmt(mod)}),2868 else => unreachable,
2844 }2869 }
28452870
2846 const result = try (WValue{ .stack = {} }).toLocal(func, ty);2871 const result = try (WValue{ .stack = {} }).toLocal(func, ty);
...@@ -2932,7 +2957,7 @@ fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {...@@ -2932,7 +2957,7 @@ fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {
2932 switch (float_bits) {2957 switch (float_bits) {
2933 16 => {2958 16 => {
2934 try func.emitWValue(arg);2959 try func.emitWValue(arg);
2935 try func.addImm32(std.math.minInt(i16));2960 try func.addImm32(0x8000);
2936 try func.addTag(.i32_xor);2961 try func.addTag(.i32_xor);
2937 return .stack;2962 return .stack;
2938 },2963 },
...@@ -3019,44 +3044,48 @@ fn wrapBinOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr...@@ -3019,44 +3044,48 @@ fn wrapBinOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr
30193044
3020/// Wraps an operand based on a given type's bitsize.3045/// Wraps an operand based on a given type's bitsize.
3021/// Asserts `Type` is <= 128 bits.3046/// Asserts `Type` is <= 128 bits.
3022/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack.3047/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack, if wrapping was needed.
3023fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {3048fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
3024 const mod = func.bin_file.base.comp.module.?;3049 const mod = func.bin_file.base.comp.module.?;
3025 assert(ty.abiSize(mod) <= 16);3050 assert(ty.abiSize(mod) <= 16);
3026 const bitsize = @as(u16, @intCast(ty.bitSize(mod)));3051 const int_bits = @as(u16, @intCast(ty.bitSize(mod))); // TODO use ty.intInfo(mod).bits
3027 const wasm_bits = toWasmBits(bitsize) orelse {3052 const wasm_bits = toWasmBits(int_bits) orelse {
3028 return func.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});3053 return func.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{int_bits});
3029 };3054 };
30303055
3031 if (wasm_bits == bitsize) return operand;3056 if (wasm_bits == int_bits) return operand;
30323057
3033 if (wasm_bits == 128) {3058 switch (wasm_bits) {
3034 assert(operand != .stack);3059 32 => {
3035 const lsb = try func.load(operand, Type.u64, 8);3060 try func.emitWValue(operand);
3061 try func.addImm32((@as(u32, 1) << @intCast(int_bits)) - 1);
3062 try func.addTag(.i32_and);
3063 return .stack;
3064 },
3065 64 => {
3066 try func.emitWValue(operand);
3067 try func.addImm64((@as(u64, 1) << @intCast(int_bits)) - 1);
3068 try func.addTag(.i64_and);
3069 return .stack;
3070 },
3071 128 => {
3072 assert(operand != .stack);
3073 const result = try func.allocStack(ty);
30363074
3037 const result_ptr = try func.allocStack(ty);3075 try func.emitWValue(result);
3038 try func.emitWValue(result_ptr);3076 _ = try func.load(operand, Type.u64, 0);
3039 try func.store(.{ .stack = {} }, lsb, Type.u64, 8 + result_ptr.offset());3077 try func.store(.stack, .stack, Type.u64, result.offset());
3040 const result = (@as(u64, 1) << @as(u6, @intCast(64 - (wasm_bits - bitsize)))) - 1;
3041 try func.emitWValue(result_ptr);
3042 _ = try func.load(operand, Type.u64, 0);
3043 try func.addImm64(result);
3044 try func.addTag(.i64_and);
3045 try func.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 });
3046 return result_ptr;
3047 }
30483078
3049 const result = (@as(u64, 1) << @as(u6, @intCast(bitsize))) - 1;3079 try func.emitWValue(result);
3050 try func.emitWValue(operand);3080 _ = try func.load(operand, Type.u64, 8);
3051 if (bitsize <= 32) {3081 try func.addImm64((@as(u64, 1) << @intCast(int_bits - 64)) - 1);
3052 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(result)))));3082 try func.addTag(.i64_and);
3053 try func.addTag(.i32_and);3083 try func.store(.stack, .stack, Type.u64, result.offset() + 8);
3054 } else if (bitsize <= 64) {
3055 try func.addImm64(result);
3056 try func.addTag(.i64_and);
3057 } else unreachable;
30583084
3059 return WValue{ .stack = {} };3085 return result;
3086 },
3087 else => unreachable,
3088 }
3060}3089}
30613090
3062fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {3091fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
...@@ -4062,11 +4091,11 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4062,11 +4091,11 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4062 if (lowest < 0) {4091 if (lowest < 0) {
4063 // since br_table works using indexes, starting from '0', we must ensure all values4092 // since br_table works using indexes, starting from '0', we must ensure all values
4064 // we put inside, are atleast 0.4093 // we put inside, are atleast 0.
4065 try func.addImm32(lowest * -1);4094 try func.addImm32(@bitCast(lowest * -1));
4066 try func.addTag(.i32_add);4095 try func.addTag(.i32_add);
4067 } else if (lowest > 0) {4096 } else if (lowest > 0) {
4068 // make the index start from 0 by substracting the lowest value4097 // make the index start from 0 by substracting the lowest value
4069 try func.addImm32(lowest);4098 try func.addImm32(@bitCast(lowest));
4070 try func.addTag(.i32_sub);4099 try func.addTag(.i32_sub);
4071 }4100 }
40724101
...@@ -4588,7 +4617,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4588,7 +4617,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
45884617
4589 // calculate index into slice4618 // calculate index into slice
4590 try func.emitWValue(index);4619 try func.emitWValue(index);
4591 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(elem_size)))));4620 try func.addImm32(@intCast(elem_size));
4592 try func.addTag(.i32_mul);4621 try func.addTag(.i32_mul);
4593 try func.addTag(.i32_add);4622 try func.addTag(.i32_add);
45944623
...@@ -4618,7 +4647,7 @@ fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4618,7 +4647,7 @@ fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
46184647
4619 // calculate index into slice4648 // calculate index into slice
4620 try func.emitWValue(index);4649 try func.emitWValue(index);
4621 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(elem_size)))));4650 try func.addImm32(@intCast(elem_size));
4622 try func.addTag(.i32_mul);4651 try func.addTag(.i32_mul);
4623 try func.addTag(.i32_add);4652 try func.addTag(.i32_add);
46244653
...@@ -4737,7 +4766,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4737,7 +4766,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
47374766
4738 // calculate index into slice4767 // calculate index into slice
4739 try func.emitWValue(index);4768 try func.emitWValue(index);
4740 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(elem_size)))));4769 try func.addImm32(@intCast(elem_size));
4741 try func.addTag(.i32_mul);4770 try func.addTag(.i32_mul);
4742 try func.addTag(.i32_add);4771 try func.addTag(.i32_add);
47434772
...@@ -4776,7 +4805,7 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4776,7 +4805,7 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
47764805
4777 // calculate index into ptr4806 // calculate index into ptr
4778 try func.emitWValue(index);4807 try func.emitWValue(index);
4779 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(elem_size)))));4808 try func.addImm32(@intCast(elem_size));
4780 try func.addTag(.i32_mul);4809 try func.addTag(.i32_mul);
4781 try func.addTag(.i32_add);4810 try func.addTag(.i32_add);
47824811
...@@ -4804,7 +4833,7 @@ fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -4804,7 +4833,7 @@ fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
48044833
4805 try func.lowerToStack(ptr);4834 try func.lowerToStack(ptr);
4806 try func.emitWValue(offset);4835 try func.emitWValue(offset);
4807 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(pointee_ty.abiSize(mod))))));4836 try func.addImm32(@intCast(pointee_ty.abiSize(mod)));
4808 try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode));4837 try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode));
4809 try func.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));4838 try func.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));
48104839
...@@ -4948,7 +4977,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4948,7 +4977,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4948 if (isByRef(array_ty, mod)) {4977 if (isByRef(array_ty, mod)) {
4949 try func.lowerToStack(array);4978 try func.lowerToStack(array);
4950 try func.emitWValue(index);4979 try func.emitWValue(index);
4951 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(elem_size)))));4980 try func.addImm32(@intCast(elem_size));
4952 try func.addTag(.i32_mul);4981 try func.addTag(.i32_mul);
4953 try func.addTag(.i32_add);4982 try func.addTag(.i32_add);
4954 } else {4983 } else {
...@@ -4981,7 +5010,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4981,7 +5010,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4981 // Is a non-unrolled vector (v128)5010 // Is a non-unrolled vector (v128)
4982 try func.lowerToStack(stack_vec);5011 try func.lowerToStack(stack_vec);
4983 try func.emitWValue(index);5012 try func.emitWValue(index);
4984 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(elem_size)))));5013 try func.addImm32(@intCast(elem_size));
4985 try func.addTag(.i32_mul);5014 try func.addTag(.i32_mul);
4986 try func.addTag(.i32_add);5015 try func.addTag(.i32_add);
4987 },5016 },
...@@ -5717,7 +5746,7 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5717,7 +5746,7 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5717 const result = if (field_offset != 0) result: {5746 const result = if (field_offset != 0) result: {
5718 const base = try func.buildPointerOffset(field_ptr, 0, .new);5747 const base = try func.buildPointerOffset(field_ptr, 0, .new);
5719 try func.addLabel(.local_get, base.local.value);5748 try func.addLabel(.local_get, base.local.value);
5720 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(field_offset)))));5749 try func.addImm32(@intCast(field_offset));
5721 try func.addTag(.i32_sub);5750 try func.addTag(.i32_sub);
5722 try func.addLabel(.local_set, base.local.value);5751 try func.addLabel(.local_set, base.local.value);
5723 break :result base;5752 break :result base;
...@@ -5938,7 +5967,7 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5938,7 +5967,7 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5938 try func.emitWValue(operand);5967 try func.emitWValue(operand);
5939 switch (func.arch()) {5968 switch (func.arch()) {
5940 .wasm32 => {5969 .wasm32 => {
5941 try func.addImm32(@as(i32, @bitCast(@as(u32, @intCast(abi_size)))));5970 try func.addImm32(@intCast(abi_size));
5942 try func.addTag(.i32_mul);5971 try func.addTag(.i32_mul);
5943 try func.addTag(.i32_add);5972 try func.addTag(.i32_add);
5944 },5973 },
...@@ -7078,7 +7107,7 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -7078,7 +7107,7 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
7078 if (wasm_bits != int_info.bits and op == .add) {7107 if (wasm_bits != int_info.bits and op == .add) {
7079 const val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits))) - 1));7108 const val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits))) - 1));
7080 const imm_val = switch (wasm_bits) {7109 const imm_val = switch (wasm_bits) {
7081 32 => WValue{ .imm32 = @as(u32, @intCast(val)) },7110 32 => WValue{ .imm32 = @intCast(val) },
7082 64 => WValue{ .imm64 = val },7111 64 => WValue{ .imm64 = val },
7083 else => unreachable,7112 else => unreachable,
7084 };7113 };
...@@ -7088,8 +7117,8 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -7088,8 +7117,8 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
7088 _ = try func.cmp(bin_result, imm_val, ty, .lt);7117 _ = try func.cmp(bin_result, imm_val, ty, .lt);
7089 } else {7118 } else {
7090 switch (wasm_bits) {7119 switch (wasm_bits) {
7091 32 => try func.addImm32(if (op == .add) @as(i32, -1) else 0),7120 32 => try func.addImm32(if (op == .add) std.math.maxInt(u32) else 0),
7092 64 => try func.addImm64(if (op == .add) @as(u64, @bitCast(@as(i64, -1))) else 0),7121 64 => try func.addImm64(if (op == .add) std.math.maxInt(u64) else 0),
7093 else => unreachable,7122 else => unreachable,
7094 }7123 }
7095 try func.emitWValue(bin_result);7124 try func.emitWValue(bin_result);
...@@ -7192,21 +7221,21 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7192,21 +7221,21 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7192 switch (wasm_bits) {7221 switch (wasm_bits) {
7193 32 => blk: {7222 32 => blk: {
7194 if (!is_signed) {7223 if (!is_signed) {
7195 try func.addImm32(-1);7224 try func.addImm32(std.math.maxInt(u32));
7196 break :blk;7225 break :blk;
7197 }7226 }
7198 try func.addImm32(std.math.minInt(i32));7227 try func.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
7199 try func.addImm32(std.math.maxInt(i32));7228 try func.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
7200 _ = try func.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);7229 _ = try func.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
7201 try func.addTag(.select);7230 try func.addTag(.select);
7202 },7231 },
7203 64 => blk: {7232 64 => blk: {
7204 if (!is_signed) {7233 if (!is_signed) {
7205 try func.addImm64(@as(u64, @bitCast(@as(i64, -1))));7234 try func.addImm64(std.math.maxInt(u64));
7206 break :blk;7235 break :blk;
7207 }7236 }
7208 try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.minInt(i64)))));7237 try func.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
7209 try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.maxInt(i64)))));7238 try func.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
7210 _ = try func.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);7239 _ = try func.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
7211 try func.addTag(.select);7240 try func.addTag(.select);
7212 },7241 },
...@@ -7236,23 +7265,23 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7236,23 +7265,23 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7236 switch (wasm_bits) {7265 switch (wasm_bits) {
7237 32 => blk: {7266 32 => blk: {
7238 if (!is_signed) {7267 if (!is_signed) {
7239 try func.addImm32(-1);7268 try func.addImm32(std.math.maxInt(u32));
7240 break :blk;7269 break :blk;
7241 }7270 }
72427271
7243 try func.addImm32(std.math.minInt(i32));7272 try func.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
7244 try func.addImm32(std.math.maxInt(i32));7273 try func.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
7245 _ = try func.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt);7274 _ = try func.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt);
7246 try func.addTag(.select);7275 try func.addTag(.select);
7247 },7276 },
7248 64 => blk: {7277 64 => blk: {
7249 if (!is_signed) {7278 if (!is_signed) {
7250 try func.addImm64(@as(u64, @bitCast(@as(i64, -1))));7279 try func.addImm64(std.math.maxInt(u64));
7251 break :blk;7280 break :blk;
7252 }7281 }
72537282
7254 try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.minInt(i64)))));7283 try func.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
7255 try func.addImm64(@as(u64, @bitCast(@as(i64, std.math.maxInt(i64)))));7284 try func.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
7256 _ = try func.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt);7285 _ = try func.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt);
7257 try func.addTag(.select);7286 try func.addTag(.select);
7258 },7287 },
...@@ -7546,7 +7575,7 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7546,7 +7575,7 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
75467575
7547 // lower operand to determine jump table target7576 // lower operand to determine jump table target
7548 try func.emitWValue(operand);7577 try func.emitWValue(operand);
7549 try func.addImm32(@as(i32, @intCast(lowest.?)));7578 try func.addImm32(lowest.?);
7550 try func.addTag(.i32_sub);7579 try func.addTag(.i32_sub);
75517580
7552 // Account for default branch so always add '1'7581 // Account for default branch so always add '1'
...@@ -7641,7 +7670,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7641,7 +7670,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76417670
7642 const result_ptr = if (isByRef(result_ty, mod)) val: {7671 const result_ptr = if (isByRef(result_ty, mod)) val: {
7643 try func.emitWValue(cmp_result);7672 try func.emitWValue(cmp_result);
7644 try func.addImm32(-1);7673 try func.addImm32(~@as(u32, 0));
7645 try func.addTag(.i32_xor);7674 try func.addTag(.i32_xor);
7646 try func.addImm32(1);7675 try func.addImm32(1);
7647 try func.addTag(.i32_and);7676 try func.addTag(.i32_and);
...@@ -7717,9 +7746,9 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7717,9 +7746,9 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
77177746
7718 const and_res = try func.binOp(value, operand, ty, .@"and");7747 const and_res = try func.binOp(value, operand, ty, .@"and");
7719 if (wasm_bits == 32)7748 if (wasm_bits == 32)
7720 try func.addImm32(-1)7749 try func.addImm32(~@as(u32, 0))
7721 else if (wasm_bits == 64)7750 else if (wasm_bits == 64)
7722 try func.addImm64(@as(u64, @bitCast(@as(i64, -1))))7751 try func.addImm64(~@as(u64, 0))
7723 else7752 else
7724 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});7753 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7725 _ = try func.binOp(and_res, .stack, ty, .xor);7754 _ = try func.binOp(and_res, .stack, ty, .xor);
...@@ -7849,9 +7878,9 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7849,9 +7878,9 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7849 try func.emitWValue(ptr);7878 try func.emitWValue(ptr);
7850 const and_res = try func.binOp(result, operand, ty, .@"and");7879 const and_res = try func.binOp(result, operand, ty, .@"and");
7851 if (wasm_bits == 32)7880 if (wasm_bits == 32)
7852 try func.addImm32(-1)7881 try func.addImm32(~@as(u32, 0))
7853 else if (wasm_bits == 64)7882 else if (wasm_bits == 64)
7854 try func.addImm64(@as(u64, @bitCast(@as(i64, -1))))7883 try func.addImm64(~@as(u64, 0))
7855 else7884 else
7856 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});7885 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7857 _ = try func.binOp(and_res, .stack, ty, .xor);7886 _ = try func.binOp(and_res, .stack, ty, .xor);
test/behavior/abs.zig+64
...@@ -87,6 +87,70 @@ fn testAbsUnsignedIntegers() !void {...@@ -87,6 +87,70 @@ fn testAbsUnsignedIntegers() !void {
87 }87 }
88}88}
8989
90test "@abs big int <= 128 bits" {
91 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
96 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
98
99 try comptime testAbsSignedBigInt();
100 try testAbsSignedBigInt();
101
102 try comptime testAbsUnsignedBigInt();
103 try testAbsUnsignedBigInt();
104}
105
106fn abs(comptime T: type, a: T) std.meta.Int(.unsigned, @typeInfo(T).Int.bits) {
107 return @abs(a);
108}
109
110fn testAbsSignedBigInt() !void {
111 try expect(abs(i65, -18446744073709551616) == 18446744073709551616);
112 try expect(abs(i65, 18446744073709551615) == 18446744073709551615);
113 try expect(abs(i65, 1234) == 1234);
114 try expect(abs(i65, -1234) == 1234);
115
116 try expect(abs(i84, -9671406556917033397649408) == 9671406556917033397649408);
117 try expect(abs(i84, 9671406556917033397649407) == 9671406556917033397649407);
118 try expect(abs(i84, 1234) == 1234);
119 try expect(abs(i84, -1234) == 1234);
120
121 try expect(abs(i96, -39614081257132168796771975168) == 39614081257132168796771975168);
122 try expect(abs(i96, 39614081257132168796771975167) == 39614081257132168796771975167);
123 try expect(abs(i96, 1234) == 1234);
124 try expect(abs(i96, -1234) == 1234);
125
126 try expect(abs(i105, -20282409603651670423947251286016) == 20282409603651670423947251286016);
127 try expect(abs(i105, 20282409603651670423947251286015) == 20282409603651670423947251286015);
128 try expect(abs(i105, 1234) == 1234);
129 try expect(abs(i105, -1234) == 1234);
130
131 try expect(abs(i128, -170141183460469231731687303715884105728) == 170141183460469231731687303715884105728);
132 try expect(abs(i128, 170141183460469231731687303715884105727) == 170141183460469231731687303715884105727);
133 try expect(abs(i128, 1234) == 1234);
134 try expect(abs(i128, -1234) == 1234);
135}
136
137fn testAbsUnsignedBigInt() !void {
138 try expect(abs(u65, 36893488147419103231) == 36893488147419103231);
139 try expect(abs(u65, 1234) == 1234);
140
141 try expect(abs(u84, 19342813113834066795298815) == 19342813113834066795298815);
142 try expect(abs(u84, 1234) == 1234);
143
144 try expect(abs(u96, 79228162514264337593543950335) == 79228162514264337593543950335);
145 try expect(abs(u96, 1234) == 1234);
146
147 try expect(abs(u105, 40564819207303340847894502572031) == 40564819207303340847894502572031);
148 try expect(abs(u105, 1234) == 1234);
149
150 try expect(abs(u128, 340282366920938463463374607431768211455) == 340282366920938463463374607431768211455);
151 try expect(abs(u128, 1234) == 1234);
152}
153
90test "@abs floats" {154test "@abs floats" {
91 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO