| ... | ... | @@ -2681,41 +2681,41 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner |
| 2681 | 2681 | .@"and", .@"or", .xor => { |
| 2682 | 2682 | const result = try func.allocStack(ty); |
| 2683 | 2683 | try func.emitWValue(result); |
| 2684 | | const lhs_low_bit = try func.load(lhs, Type.u64, 0); |
| 2685 | | const rhs_low_bit = try func.load(rhs, Type.u64, 0); |
| 2686 | | const op_low_bit = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); |
| 2687 | | try func.store(.stack, op_low_bit, Type.u64, result.offset()); |
| 2684 | const lhs_lsb = try func.load(lhs, Type.u64, 0); |
| 2685 | const rhs_lsb = try func.load(rhs, Type.u64, 0); |
| 2686 | const op_lsb = try func.binOp(lhs_lsb, rhs_lsb, Type.u64, op); |
| 2687 | try func.store(.stack, op_lsb, Type.u64, result.offset()); |
| 2688 | 2688 | |
| 2689 | 2689 | try func.emitWValue(result); |
| 2690 | | const lhs_high_bit = try func.load(lhs, Type.u64, 8); |
| 2691 | | const rhs_high_bit = try func.load(rhs, Type.u64, 8); |
| 2692 | | const op_high_bit = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); |
| 2693 | | try func.store(.stack, op_high_bit, Type.u64, result.offset() + 8); |
| 2690 | const lhs_msb = try func.load(lhs, Type.u64, 8); |
| 2691 | const rhs_msb = try func.load(rhs, Type.u64, 8); |
| 2692 | const op_msb = try func.binOp(lhs_msb, rhs_msb, Type.u64, op); |
| 2693 | try func.store(.stack, op_msb, Type.u64, result.offset() + 8); |
| 2694 | 2694 | return result; |
| 2695 | 2695 | }, |
| 2696 | 2696 | .add, .sub => { |
| 2697 | 2697 | const result = try func.allocStack(ty); |
| 2698 | | var lhs_low_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 2699 | | defer lhs_low_bit.free(func); |
| 2700 | | var rhs_low_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 2701 | | defer rhs_low_bit.free(func); |
| 2702 | | var low_op_res = try (try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(func, Type.u64); |
| 2703 | | defer low_op_res.free(func); |
| 2698 | var lhs_lsb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 2699 | defer lhs_lsb.free(func); |
| 2700 | var rhs_lsb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 2701 | defer rhs_lsb.free(func); |
| 2702 | var op_lsb = try (try func.binOp(lhs_lsb, rhs_lsb, Type.u64, op)).toLocal(func, Type.u64); |
| 2703 | defer op_lsb.free(func); |
| 2704 | 2704 | |
| 2705 | | const lhs_high_bit = try func.load(lhs, Type.u64, 8); |
| 2706 | | const rhs_high_bit = try func.load(rhs, Type.u64, 8); |
| 2707 | | const high_op_res = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); |
| 2705 | const lhs_msb = try func.load(lhs, Type.u64, 8); |
| 2706 | const rhs_msb = try func.load(rhs, Type.u64, 8); |
| 2707 | const op_msb = try func.binOp(lhs_msb, rhs_msb, Type.u64, op); |
| 2708 | 2708 | |
| 2709 | 2709 | const lt = if (op == .add) blk: { |
| 2710 | | break :blk try func.cmp(low_op_res, rhs_low_bit, Type.u64, .lt); |
| 2710 | break :blk try func.cmp(op_lsb, rhs_lsb, Type.u64, .lt); |
| 2711 | 2711 | } else if (op == .sub) blk: { |
| 2712 | | break :blk try func.cmp(lhs_low_bit, rhs_low_bit, Type.u64, .lt); |
| 2712 | break :blk try func.cmp(lhs_lsb, rhs_lsb, Type.u64, .lt); |
| 2713 | 2713 | } else unreachable; |
| 2714 | 2714 | const tmp = try func.intcast(lt, Type.u32, Type.u64); |
| 2715 | | var tmp_op = try (try func.binOp(high_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64); |
| 2715 | var tmp_op = try (try func.binOp(op_msb, tmp, Type.u64, op)).toLocal(func, Type.u64); |
| 2716 | 2716 | defer tmp_op.free(func); |
| 2717 | 2717 | |
| 2718 | | try func.store(result, low_op_res, Type.u64, 0); |
| 2718 | try func.store(result, op_lsb, Type.u64, 0); |
| 2719 | 2719 | try func.store(result, tmp_op, Type.u64, 8); |
| 2720 | 2720 | return result; |
| 2721 | 2721 | }, |
| ... | ... | @@ -4419,16 +4419,16 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4419 | 4419 | break :blk try (try func.intcast(operand, given, sign_ty)).toLocal(func, sign_ty); |
| 4420 | 4420 | } else operand; |
| 4421 | 4421 | |
| 4422 | | // store msb first |
| 4422 | // store lsb first |
| 4423 | 4423 | try func.store(.stack, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 4424 | 4424 | |
| 4425 | | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 4425 | // For signed integers we shift lsb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 4426 | 4426 | if (wanted.isSignedInt(mod)) { |
| 4427 | 4427 | try func.emitWValue(stack_ptr); |
| 4428 | 4428 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| 4429 | 4429 | try func.store(.stack, shr, Type.u64, 8 + stack_ptr.offset()); |
| 4430 | 4430 | } else { |
| 4431 | | // Ensure memory of lsb is zero'd |
| 4431 | // Ensure memory of msb is zero'd |
| 4432 | 4432 | try func.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); |
| 4433 | 4433 | } |
| 4434 | 4434 | return stack_ptr; |
| ... | ... | @@ -5529,17 +5529,17 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 5529 | 5529 | return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(pt)}); |
| 5530 | 5530 | } |
| 5531 | 5531 | |
| 5532 | | var lhs_high_bit = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 5533 | | defer lhs_high_bit.free(func); |
| 5534 | | var rhs_high_bit = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 5535 | | defer rhs_high_bit.free(func); |
| 5532 | var lhs_msb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 5533 | defer lhs_msb.free(func); |
| 5534 | var rhs_msb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 5535 | defer rhs_msb.free(func); |
| 5536 | 5536 | |
| 5537 | 5537 | switch (op) { |
| 5538 | 5538 | .eq, .neq => { |
| 5539 | | const xor_high = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor); |
| 5540 | | const lhs_low_bit = try func.load(lhs, Type.u64, 0); |
| 5541 | | const rhs_low_bit = try func.load(rhs, Type.u64, 0); |
| 5542 | | const xor_low = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); |
| 5539 | const xor_high = try func.binOp(lhs_msb, rhs_msb, Type.u64, .xor); |
| 5540 | const lhs_lsb = try func.load(lhs, Type.u64, 0); |
| 5541 | const rhs_lsb = try func.load(rhs, Type.u64, 0); |
| 5542 | const xor_low = try func.binOp(lhs_lsb, rhs_lsb, Type.u64, .xor); |
| 5543 | 5543 | const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or"); |
| 5544 | 5544 | |
| 5545 | 5545 | switch (op) { |
| ... | ... | @@ -5551,11 +5551,11 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 5551 | 5551 | else => { |
| 5552 | 5552 | const ty = if (operand_ty.isSignedInt(mod)) Type.i64 else Type.u64; |
| 5553 | 5553 | // leave those value on top of the stack for '.select' |
| 5554 | | const lhs_low_bit = try func.load(lhs, Type.u64, 0); |
| 5555 | | const rhs_low_bit = try func.load(rhs, Type.u64, 0); |
| 5556 | | _ = try func.cmp(lhs_low_bit, rhs_low_bit, Type.u64, op); |
| 5557 | | _ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, op); |
| 5558 | | _ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, .eq); |
| 5554 | const lhs_lsb = try func.load(lhs, Type.u64, 0); |
| 5555 | const rhs_lsb = try func.load(rhs, Type.u64, 0); |
| 5556 | _ = try func.cmp(lhs_lsb, rhs_lsb, Type.u64, op); |
| 5557 | _ = try func.cmp(lhs_msb, rhs_msb, ty, op); |
| 5558 | _ = try func.cmp(lhs_msb, rhs_msb, ty, .eq); |
| 5559 | 5559 | try func.addTag(.select); |
| 5560 | 5560 | }, |
| 5561 | 5561 | } |
| ... | ... | @@ -6106,11 +6106,11 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6106 | 6106 | |
| 6107 | 6107 | const lhs = try func.resolveInst(extra.lhs); |
| 6108 | 6108 | const rhs = try func.resolveInst(extra.rhs); |
| 6109 | | const lhs_ty = func.typeOf(extra.lhs); |
| 6109 | const ty = func.typeOf(extra.lhs); |
| 6110 | 6110 | const pt = func.pt; |
| 6111 | 6111 | const mod = pt.zcu; |
| 6112 | 6112 | |
| 6113 | | if (lhs_ty.zigTypeTag(mod) == .Vector) { |
| 6113 | if (ty.zigTypeTag(mod) == .Vector) { |
| 6114 | 6114 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 6115 | 6115 | } |
| 6116 | 6116 | |
| ... | ... | @@ -6119,7 +6119,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6119 | 6119 | var overflow_bit = try func.ensureAllocLocal(Type.u1); |
| 6120 | 6120 | defer overflow_bit.free(func); |
| 6121 | 6121 | |
| 6122 | | const int_info = lhs_ty.intInfo(mod); |
| 6122 | const int_info = ty.intInfo(mod); |
| 6123 | 6123 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6124 | 6124 | return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); |
| 6125 | 6125 | }; |
| ... | ... | @@ -6131,147 +6131,106 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6131 | 6131 | }; |
| 6132 | 6132 | |
| 6133 | 6133 | // for 32 bit integers we upcast it to a 64bit integer |
| 6134 | | const bin_op = if (int_info.bits == 32) blk: { |
| 6134 | const mul = if (wasm_bits == 32) blk: { |
| 6135 | 6135 | const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64; |
| 6136 | | const lhs_upcast = try func.intcast(lhs, lhs_ty, new_ty); |
| 6137 | | const rhs_upcast = try func.intcast(rhs, lhs_ty, new_ty); |
| 6136 | const lhs_upcast = try func.intcast(lhs, ty, new_ty); |
| 6137 | const rhs_upcast = try func.intcast(rhs, ty, new_ty); |
| 6138 | 6138 | const bin_op = try (try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(func, new_ty); |
| 6139 | | if (int_info.signedness == .unsigned) { |
| 6140 | | const shr = try func.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 6141 | | const wrap = try func.intcast(shr, new_ty, lhs_ty); |
| 6142 | | _ = try func.cmp(wrap, zero, lhs_ty, .neq); |
| 6143 | | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6144 | | break :blk try func.intcast(bin_op, new_ty, lhs_ty); |
| 6145 | | } else { |
| 6146 | | const down_cast = try (try func.intcast(bin_op, new_ty, lhs_ty)).toLocal(func, lhs_ty); |
| 6147 | | var shr = try (try func.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(func, lhs_ty); |
| 6148 | | defer shr.free(func); |
| 6149 | | |
| 6150 | | const shr_res = try func.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 6151 | | const down_shr_res = try func.intcast(shr_res, new_ty, lhs_ty); |
| 6152 | | _ = try func.cmp(down_shr_res, shr, lhs_ty, .neq); |
| 6153 | | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6154 | | break :blk down_cast; |
| 6155 | | } |
| 6156 | | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { |
| 6157 | | const bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| 6158 | | const mul_abs = try func.wrapOperand(bin_op, lhs_ty); |
| 6159 | | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 6139 | const res = try (try func.trunc(bin_op, ty, new_ty)).toLocal(func, ty); |
| 6140 | const res_upcast = try func.intcast(res, ty, new_ty); |
| 6141 | _ = try func.cmp(res_upcast, bin_op, new_ty, .neq); |
| 6160 | 6142 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6161 | | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| 6162 | | } else if (wasm_bits == 32) blk: { |
| 6163 | | var bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| 6164 | | defer bin_op.free(func); |
| 6165 | | const shift_imm: WValue = if (wasm_bits == 32) |
| 6166 | | .{ .imm32 = int_info.bits } |
| 6167 | | else |
| 6168 | | .{ .imm64 = int_info.bits }; |
| 6169 | | const shr = try func.binOp(bin_op, shift_imm, lhs_ty, .shr); |
| 6170 | | _ = try func.cmp(shr, zero, lhs_ty, .neq); |
| 6171 | | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6172 | | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| 6173 | | } else if (int_info.bits == 64 and int_info.signedness == .unsigned) blk: { |
| 6174 | | const new_ty = Type.u128; |
| 6175 | | var lhs_upcast = try (try func.intcast(lhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| 6176 | | defer lhs_upcast.free(func); |
| 6177 | | var rhs_upcast = try (try func.intcast(rhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| 6178 | | defer rhs_upcast.free(func); |
| 6179 | | const bin_op = try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul); |
| 6180 | | const lsb = try func.load(bin_op, lhs_ty, 8); |
| 6181 | | _ = try func.cmp(lsb, zero, lhs_ty, .neq); |
| 6182 | | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6183 | | |
| 6184 | | break :blk try func.load(bin_op, lhs_ty, 0); |
| 6185 | | } else if (int_info.bits == 64 and int_info.signedness == .signed) blk: { |
| 6186 | | const shift_val: WValue = .{ .imm64 = 63 }; |
| 6187 | | var lhs_shifted = try (try func.binOp(lhs, shift_val, lhs_ty, .shr)).toLocal(func, lhs_ty); |
| 6188 | | defer lhs_shifted.free(func); |
| 6189 | | var rhs_shifted = try (try func.binOp(rhs, shift_val, lhs_ty, .shr)).toLocal(func, lhs_ty); |
| 6190 | | defer rhs_shifted.free(func); |
| 6191 | | |
| 6192 | | const bin_op = try func.callIntrinsic( |
| 6193 | | "__multi3", |
| 6194 | | &[_]InternPool.Index{.i64_type} ** 4, |
| 6195 | | Type.i128, |
| 6196 | | &.{ lhs, lhs_shifted, rhs, rhs_shifted }, |
| 6197 | | ); |
| 6198 | | const res = try func.allocLocal(lhs_ty); |
| 6199 | | const msb = try func.load(bin_op, lhs_ty, 0); |
| 6200 | | try func.addLabel(.local_tee, res.local.value); |
| 6201 | | const msb_shifted = try func.binOp(msb, shift_val, lhs_ty, .shr); |
| 6202 | | const lsb = try func.load(bin_op, lhs_ty, 8); |
| 6203 | | _ = try func.cmp(lsb, msb_shifted, lhs_ty, .neq); |
| 6143 | break :blk res; |
| 6144 | } else if (wasm_bits == 64) blk: { |
| 6145 | const new_ty = if (int_info.signedness == .signed) Type.i128 else Type.u128; |
| 6146 | const lhs_upcast = try func.intcast(lhs, ty, new_ty); |
| 6147 | const rhs_upcast = try func.intcast(rhs, ty, new_ty); |
| 6148 | const bin_op = try (try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(func, new_ty); |
| 6149 | const res = try (try func.trunc(bin_op, ty, new_ty)).toLocal(func, ty); |
| 6150 | const res_upcast = try func.intcast(res, ty, new_ty); |
| 6151 | _ = try func.cmp(res_upcast, bin_op, new_ty, .neq); |
| 6204 | 6152 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6205 | 6153 | break :blk res; |
| 6206 | 6154 | } else if (int_info.bits == 128 and int_info.signedness == .unsigned) blk: { |
| 6207 | | var lhs_msb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 6208 | | defer lhs_msb.free(func); |
| 6209 | | var lhs_lsb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 6155 | var lhs_lsb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 6210 | 6156 | defer lhs_lsb.free(func); |
| 6211 | | var rhs_msb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 6212 | | defer rhs_msb.free(func); |
| 6213 | | var rhs_lsb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 6157 | var lhs_msb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 6158 | defer lhs_msb.free(func); |
| 6159 | var rhs_lsb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 6214 | 6160 | defer rhs_lsb.free(func); |
| 6161 | var rhs_msb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 6162 | defer rhs_msb.free(func); |
| 6215 | 6163 | |
| 6216 | | const mul1 = try func.callIntrinsic( |
| 6164 | const cross_1 = try func.callIntrinsic( |
| 6217 | 6165 | "__multi3", |
| 6218 | 6166 | &[_]InternPool.Index{.i64_type} ** 4, |
| 6219 | 6167 | Type.i128, |
| 6220 | | &.{ lhs_lsb, zero, rhs_msb, zero }, |
| 6168 | &.{ lhs_msb, zero, rhs_lsb, zero }, |
| 6221 | 6169 | ); |
| 6222 | | const mul2 = try func.callIntrinsic( |
| 6170 | const cross_2 = try func.callIntrinsic( |
| 6223 | 6171 | "__multi3", |
| 6224 | 6172 | &[_]InternPool.Index{.i64_type} ** 4, |
| 6225 | 6173 | Type.i128, |
| 6226 | | &.{ rhs_lsb, zero, lhs_msb, zero }, |
| 6174 | &.{ rhs_msb, zero, lhs_lsb, zero }, |
| 6227 | 6175 | ); |
| 6228 | | const mul3 = try func.callIntrinsic( |
| 6176 | const mul_lsb = try func.callIntrinsic( |
| 6229 | 6177 | "__multi3", |
| 6230 | 6178 | &[_]InternPool.Index{.i64_type} ** 4, |
| 6231 | 6179 | Type.i128, |
| 6232 | | &.{ lhs_msb, zero, rhs_msb, zero }, |
| 6180 | &.{ rhs_lsb, zero, lhs_lsb, zero }, |
| 6233 | 6181 | ); |
| 6234 | 6182 | |
| 6235 | | const rhs_lsb_not_zero = try func.cmp(rhs_lsb, zero, Type.u64, .neq); |
| 6236 | | const lhs_lsb_not_zero = try func.cmp(lhs_lsb, zero, Type.u64, .neq); |
| 6237 | | const lsb_and = try func.binOp(rhs_lsb_not_zero, lhs_lsb_not_zero, Type.bool, .@"and"); |
| 6238 | | const mul1_lsb = try func.load(mul1, Type.u64, 8); |
| 6239 | | const mul1_lsb_not_zero = try func.cmp(mul1_lsb, zero, Type.u64, .neq); |
| 6240 | | const lsb_or1 = try func.binOp(lsb_and, mul1_lsb_not_zero, Type.bool, .@"or"); |
| 6241 | | const mul2_lsb = try func.load(mul2, Type.u64, 8); |
| 6242 | | const mul2_lsb_not_zero = try func.cmp(mul2_lsb, zero, Type.u64, .neq); |
| 6243 | | const lsb_or = try func.binOp(lsb_or1, mul2_lsb_not_zero, Type.bool, .@"or"); |
| 6244 | | |
| 6245 | | const mul1_msb = try func.load(mul1, Type.u64, 0); |
| 6246 | | const mul2_msb = try func.load(mul2, Type.u64, 0); |
| 6247 | | const mul_add1 = try func.binOp(mul1_msb, mul2_msb, Type.u64, .add); |
| 6248 | | |
| 6249 | | var mul3_lsb = try (try func.load(mul3, Type.u64, 8)).toLocal(func, Type.u64); |
| 6250 | | defer mul3_lsb.free(func); |
| 6251 | | var mul_add2 = try (try func.binOp(mul_add1, mul3_lsb, Type.u64, .add)).toLocal(func, Type.u64); |
| 6252 | | defer mul_add2.free(func); |
| 6253 | | const mul_add_lt = try func.cmp(mul_add2, mul3_lsb, Type.u64, .lt); |
| 6183 | const rhs_msb_not_zero = try func.cmp(rhs_msb, zero, Type.u64, .neq); |
| 6184 | const lhs_msb_not_zero = try func.cmp(lhs_msb, zero, Type.u64, .neq); |
| 6185 | const both_msb_not_zero = try func.binOp(rhs_msb_not_zero, lhs_msb_not_zero, Type.bool, .@"and"); |
| 6186 | const cross_1_msb = try func.load(cross_1, Type.u64, 8); |
| 6187 | const cross_1_msb_not_zero = try func.cmp(cross_1_msb, zero, Type.u64, .neq); |
| 6188 | const cond_1 = try func.binOp(both_msb_not_zero, cross_1_msb_not_zero, Type.bool, .@"or"); |
| 6189 | const cross_2_msb = try func.load(cross_2, Type.u64, 8); |
| 6190 | const cross_2_msb_not_zero = try func.cmp(cross_2_msb, zero, Type.u64, .neq); |
| 6191 | const cond_2 = try func.binOp(cond_1, cross_2_msb_not_zero, Type.bool, .@"or"); |
| 6192 | |
| 6193 | const cross_1_lsb = try func.load(cross_1, Type.u64, 0); |
| 6194 | const cross_2_lsb = try func.load(cross_2, Type.u64, 0); |
| 6195 | const cross_add = try func.binOp(cross_1_lsb, cross_2_lsb, Type.u64, .add); |
| 6196 | |
| 6197 | var mul_lsb_msb = try (try func.load(mul_lsb, Type.u64, 8)).toLocal(func, Type.u64); |
| 6198 | defer mul_lsb_msb.free(func); |
| 6199 | var all_add = try (try func.binOp(cross_add, mul_lsb_msb, Type.u64, .add)).toLocal(func, Type.u64); |
| 6200 | defer all_add.free(func); |
| 6201 | const add_overflow = try func.cmp(all_add, mul_lsb_msb, Type.u64, .lt); |
| 6254 | 6202 | |
| 6255 | 6203 | // result for overflow bit |
| 6256 | | _ = try func.binOp(lsb_or, mul_add_lt, Type.bool, .@"or"); |
| 6204 | _ = try func.binOp(cond_2, add_overflow, Type.bool, .@"or"); |
| 6257 | 6205 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6258 | 6206 | |
| 6259 | 6207 | const tmp_result = try func.allocStack(Type.u128); |
| 6260 | 6208 | try func.emitWValue(tmp_result); |
| 6261 | | const mul3_msb = try func.load(mul3, Type.u64, 0); |
| 6262 | | try func.store(.stack, mul3_msb, Type.u64, tmp_result.offset()); |
| 6263 | | try func.store(tmp_result, mul_add2, Type.u64, 8); |
| 6209 | const mul_lsb_lsb = try func.load(mul_lsb, Type.u64, 0); |
| 6210 | try func.store(.stack, mul_lsb_lsb, Type.u64, tmp_result.offset()); |
| 6211 | try func.store(tmp_result, all_add, Type.u64, 8); |
| 6264 | 6212 | break :blk tmp_result; |
| 6265 | | } else return func.fail("TODO: @mulWithOverflow for integers between 32 and 64 bits", .{}); |
| 6266 | | var bin_op_local = try bin_op.toLocal(func, lhs_ty); |
| 6213 | } else if (int_info.bits == 128 and int_info.signedness == .signed) blk: { |
| 6214 | const overflow_ret = try func.allocStack(Type.i32); |
| 6215 | const res = try func.callIntrinsic( |
| 6216 | "__muloti4", |
| 6217 | &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type }, |
| 6218 | Type.i128, |
| 6219 | &.{ lhs, rhs, overflow_ret }, |
| 6220 | ); |
| 6221 | _ = try func.load(overflow_ret, Type.i32, 0); |
| 6222 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 6223 | break :blk res; |
| 6224 | } else return func.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)}); |
| 6225 | var bin_op_local = try mul.toLocal(func, ty); |
| 6267 | 6226 | defer bin_op_local.free(func); |
| 6268 | 6227 | |
| 6269 | | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); |
| 6270 | | try func.store(result_ptr, bin_op_local, lhs_ty, 0); |
| 6271 | | const offset = @as(u32, @intCast(lhs_ty.abiSize(pt))); |
| 6272 | | try func.store(result_ptr, overflow_bit, Type.u1, offset); |
| 6228 | const result = try func.allocStack(func.typeOfIndex(inst)); |
| 6229 | const offset: u32 = @intCast(ty.abiSize(pt)); |
| 6230 | try func.store(result, bin_op_local, ty, 0); |
| 6231 | try func.store(result, overflow_bit, Type.u1, offset); |
| 6273 | 6232 | |
| 6274 | | return func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); |
| 6233 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); |
| 6275 | 6234 | } |
| 6276 | 6235 | |
| 6277 | 6236 | fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| ... | ... | @@ -6378,16 +6337,16 @@ fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6378 | 6337 | try func.addTag(.i32_wrap_i64); |
| 6379 | 6338 | }, |
| 6380 | 6339 | 128 => { |
| 6381 | | var lsb = try (try func.load(operand, Type.u64, 8)).toLocal(func, Type.u64); |
| 6382 | | defer lsb.free(func); |
| 6340 | var msb = try (try func.load(operand, Type.u64, 8)).toLocal(func, Type.u64); |
| 6341 | defer msb.free(func); |
| 6383 | 6342 | |
| 6384 | | try func.emitWValue(lsb); |
| 6343 | try func.emitWValue(msb); |
| 6385 | 6344 | try func.addTag(.i64_clz); |
| 6386 | 6345 | _ = try func.load(operand, Type.u64, 0); |
| 6387 | 6346 | try func.addTag(.i64_clz); |
| 6388 | 6347 | try func.emitWValue(.{ .imm64 = 64 }); |
| 6389 | 6348 | try func.addTag(.i64_add); |
| 6390 | | _ = try func.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 6349 | _ = try func.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 6391 | 6350 | try func.addTag(.select); |
| 6392 | 6351 | try func.addTag(.i32_wrap_i64); |
| 6393 | 6352 | }, |
| ... | ... | @@ -6438,10 +6397,10 @@ fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6438 | 6397 | try func.addTag(.i32_wrap_i64); |
| 6439 | 6398 | }, |
| 6440 | 6399 | 128 => { |
| 6441 | | var msb = try (try func.load(operand, Type.u64, 0)).toLocal(func, Type.u64); |
| 6442 | | defer msb.free(func); |
| 6400 | var lsb = try (try func.load(operand, Type.u64, 0)).toLocal(func, Type.u64); |
| 6401 | defer lsb.free(func); |
| 6443 | 6402 | |
| 6444 | | try func.emitWValue(msb); |
| 6403 | try func.emitWValue(lsb); |
| 6445 | 6404 | try func.addTag(.i64_ctz); |
| 6446 | 6405 | _ = try func.load(operand, Type.u64, 8); |
| 6447 | 6406 | if (wasm_bits != int_info.bits) { |
| ... | ... | @@ -6455,7 +6414,7 @@ fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6455 | 6414 | } else { |
| 6456 | 6415 | try func.addTag(.i64_add); |
| 6457 | 6416 | } |
| 6458 | | _ = try func.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 6417 | _ = try func.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 6459 | 6418 | try func.addTag(.select); |
| 6460 | 6419 | try func.addTag(.i32_wrap_i64); |
| 6461 | 6420 | }, |