| ... | ... | @@ -2659,10 +2659,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2659 | 2659 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2660 | 2660 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2661 | 2661 | const operand_ty = self.air.typeOf(bin_op.lhs); |
| 2662 | | return self.cmp(lhs, rhs, operand_ty, op); |
| 2662 | return (try self.cmp(lhs, rhs, operand_ty, op)).toLocal(self, Type.u32); // comparison result is always 32 bits |
| 2663 | 2663 | } |
| 2664 | 2664 | |
| 2665 | /// Compares two operands. |
| 2666 | /// Asserts rhs is not a stack value when the lhs isn't a stack value either |
| 2667 | /// NOTE: This leaves the result on top of the stack, rather than a new local. |
| 2665 | 2668 | fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 2669 | assert(!(lhs != .stack and rhs == .stack)); |
| 2666 | 2670 | if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) { |
| 2667 | 2671 | var buf: Type.Payload.ElemType = undefined; |
| 2668 | 2672 | const payload_ty = ty.optionalChild(&buf); |
| ... | ... | @@ -2704,9 +2708,7 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper |
| 2704 | 2708 | }); |
| 2705 | 2709 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2706 | 2710 | |
| 2707 | | const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32 |
| 2708 | | try self.addLabel(.local_set, cmp_tmp.local); |
| 2709 | | return cmp_tmp; |
| 2711 | return WValue{ .stack = {} }; |
| 2710 | 2712 | } |
| 2711 | 2713 | |
| 2712 | 2714 | fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue { |
| ... | ... | @@ -2729,9 +2731,7 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato |
| 2729 | 2731 | try self.emitWValue(ext_rhs); |
| 2730 | 2732 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2731 | 2733 | |
| 2732 | | const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i32 |
| 2733 | | try self.addLabel(.local_set, result.local); |
| 2734 | | return result; |
| 2734 | return WValue{ .stack = {} }; |
| 2735 | 2735 | } |
| 2736 | 2736 | |
| 2737 | 2737 | fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -3982,13 +3982,16 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 3982 | 3982 | try self.addImm32(0); |
| 3983 | 3983 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); |
| 3984 | 3984 | try self.addLabel(.local_set, result.local); |
| 3985 | | return result; |
| 3985 | try self.emitWValue(result); |
| 3986 | return WValue{ .stack = {} }; |
| 3986 | 3987 | } |
| 3987 | 3988 | |
| 3988 | 3989 | /// Compares big integers by checking both its high bits and low bits. |
| 3990 | /// NOTE: Leaves the result of the comparison on top of the stack. |
| 3989 | 3991 | /// TODO: Lower this to compiler_rt call when bitsize > 128 |
| 3990 | 3992 | fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3991 | 3993 | assert(operand_ty.abiSize(self.target) >= 16); |
| 3994 | assert(!(lhs != .stack and rhs == .stack)); |
| 3992 | 3995 | if (operand_ty.intInfo(self.target).bits > 128) { |
| 3993 | 3996 | return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits}); |
| 3994 | 3997 | } |
| ... | ... | @@ -4012,20 +4015,15 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma |
| 4012 | 4015 | }, |
| 4013 | 4016 | else => { |
| 4014 | 4017 | const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64; |
| 4015 | | const high_bit_eql = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq); |
| 4016 | | const high_bit_cmp = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op); |
| 4017 | | const low_bit_cmp = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op); |
| 4018 | | |
| 4019 | | try self.emitWValue(low_bit_cmp); |
| 4020 | | try self.emitWValue(high_bit_cmp); |
| 4021 | | try self.emitWValue(high_bit_eql); |
| 4018 | // leave those value on top of the stack for '.select' |
| 4019 | _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op); |
| 4020 | _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op); |
| 4021 | _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq); |
| 4022 | 4022 | try self.addTag(.select); |
| 4023 | 4023 | }, |
| 4024 | 4024 | } |
| 4025 | 4025 | |
| 4026 | | const result = try self.allocLocal(Type.initTag(.i32)); |
| 4027 | | try self.addLabel(.local_set, result.local); |
| 4028 | | return result; |
| 4026 | return WValue{ .stack = {} }; |
| 4029 | 4027 | } |
| 4030 | 4028 | |
| 4031 | 4029 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -4350,7 +4348,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4350 | 4348 | if (wasm_bits == int_info.bits) { |
| 4351 | 4349 | const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op); |
| 4352 | 4350 | const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt); |
| 4353 | | break :blk try (try self.binOp(cmp_zero, lt, Type.u32, .xor)).toLocal(self, Type.u32); // result of cmp_zero and lt is always 32bit |
| 4351 | break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); |
| 4354 | 4352 | } |
| 4355 | 4353 | const abs = try self.signAbsValue(bin_op, lhs_ty); |
| 4356 | 4354 | break :blk try self.cmp(abs, bin_op, lhs_ty, .neq); |
| ... | ... | @@ -4358,11 +4356,12 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4358 | 4356 | try self.cmp(bin_op, lhs, lhs_ty, cmp_op) |
| 4359 | 4357 | else |
| 4360 | 4358 | try self.cmp(bin_op, result, lhs_ty, .neq); |
| 4359 | const overflow_local = try overflow_bit.toLocal(self, Type.u32); |
| 4361 | 4360 | |
| 4362 | 4361 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); |
| 4363 | 4362 | try self.store(result_ptr, result, lhs_ty, 0); |
| 4364 | 4363 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); |
| 4365 | | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); |
| 4364 | try self.store(result_ptr, overflow_local, Type.initTag(.u1), offset); |
| 4366 | 4365 | |
| 4367 | 4366 | return result_ptr; |
| 4368 | 4367 | } |
| ... | ... | @@ -4384,9 +4383,9 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, |
| 4384 | 4383 | const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64); |
| 4385 | 4384 | |
| 4386 | 4385 | const lt = if (op == .add) blk: { |
| 4387 | | break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt); |
| 4386 | break :blk try (try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32); |
| 4388 | 4387 | } else if (op == .sub) blk: { |
| 4389 | | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); |
| 4388 | break :blk try (try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32); |
| 4390 | 4389 | } else unreachable; |
| 4391 | 4390 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 4392 | 4391 | const tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64); |
| ... | ... | @@ -4400,27 +4399,23 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, |
| 4400 | 4399 | const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and"); |
| 4401 | 4400 | break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed |
| 4402 | 4401 | } else blk: { |
| 4403 | | const eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq); |
| 4404 | | const op_eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt); |
| 4405 | | |
| 4406 | 4402 | const first_arg = if (op == .sub) arg: { |
| 4407 | 4403 | break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt); |
| 4408 | 4404 | } else lt; |
| 4409 | 4405 | |
| 4410 | 4406 | try self.emitWValue(first_arg); |
| 4411 | | try self.emitWValue(op_eq); |
| 4412 | | try self.emitWValue(eq); |
| 4407 | _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt); |
| 4408 | _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq); |
| 4413 | 4409 | try self.addTag(.select); |
| 4414 | 4410 | |
| 4415 | | const overflow_bit = try self.allocLocal(Type.initTag(.u1)); |
| 4416 | | try self.addLabel(.local_set, overflow_bit.local); |
| 4417 | | break :blk overflow_bit; |
| 4411 | break :blk WValue{ .stack = {} }; |
| 4418 | 4412 | }; |
| 4413 | const overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1)); |
| 4419 | 4414 | |
| 4420 | 4415 | const result_ptr = try self.allocStack(result_ty); |
| 4421 | 4416 | try self.store(result_ptr, high_op_res, Type.u64, 0); |
| 4422 | 4417 | try self.store(result_ptr, tmp_op, Type.u64, 8); |
| 4423 | | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), 16); |
| 4418 | try self.store(result_ptr, overflow_local, Type.initTag(.u1), 16); |
| 4424 | 4419 | |
| 4425 | 4420 | return result_ptr; |
| 4426 | 4421 | } |
| ... | ... | @@ -4455,11 +4450,12 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4455 | 4450 | const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty); |
| 4456 | 4451 | break :blk try self.cmp(lhs, shr, lhs_ty, .neq); |
| 4457 | 4452 | }; |
| 4453 | const overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1)); |
| 4458 | 4454 | |
| 4459 | 4455 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); |
| 4460 | 4456 | try self.store(result_ptr, result, lhs_ty, 0); |
| 4461 | 4457 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); |
| 4462 | | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); |
| 4458 | try self.store(result_ptr, overflow_local, Type.initTag(.u1), offset); |
| 4463 | 4459 | |
| 4464 | 4460 | return result_ptr; |
| 4465 | 4461 | } |
| ... | ... | @@ -4502,8 +4498,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4502 | 4498 | if (int_info.signedness == .unsigned) { |
| 4503 | 4499 | const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 4504 | 4500 | const wrap = try self.intcast(shr, new_ty, lhs_ty); |
| 4505 | | const cmp_res = try self.cmp(wrap, zero, lhs_ty, .neq); |
| 4506 | | try self.emitWValue(cmp_res); |
| 4501 | _ = try self.cmp(wrap, zero, lhs_ty, .neq); |
| 4507 | 4502 | try self.addLabel(.local_set, overflow_bit.local); |
| 4508 | 4503 | break :blk try self.intcast(bin_op, new_ty, lhs_ty); |
| 4509 | 4504 | } else { |
| ... | ... | @@ -4512,8 +4507,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4512 | 4507 | |
| 4513 | 4508 | const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 4514 | 4509 | const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty); |
| 4515 | | const cmp_res = try self.cmp(down_shr_res, shr, lhs_ty, .neq); |
| 4516 | | try self.emitWValue(cmp_res); |
| 4510 | _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq); |
| 4517 | 4511 | try self.addLabel(.local_set, overflow_bit.local); |
| 4518 | 4512 | break :blk down_cast; |
| 4519 | 4513 | } |
| ... | ... | @@ -4522,8 +4516,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4522 | 4516 | const rhs_abs = try self.signAbsValue(rhs, lhs_ty); |
| 4523 | 4517 | const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty); |
| 4524 | 4518 | const mul_abs = try self.signAbsValue(bin_op, lhs_ty); |
| 4525 | | const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 4526 | | try self.emitWValue(cmp_op); |
| 4519 | _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 4527 | 4520 | try self.addLabel(.local_set, overflow_bit.local); |
| 4528 | 4521 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4529 | 4522 | } else blk: { |
| ... | ... | @@ -4533,8 +4526,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4533 | 4526 | else |
| 4534 | 4527 | WValue{ .imm64 = int_info.bits }; |
| 4535 | 4528 | const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr); |
| 4536 | | const cmp_op = try self.cmp(shr, zero, lhs_ty, .neq); |
| 4537 | | try self.emitWValue(cmp_op); |
| 4529 | _ = try self.cmp(shr, zero, lhs_ty, .neq); |
| 4538 | 4530 | try self.addLabel(.local_set, overflow_bit.local); |
| 4539 | 4531 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4540 | 4532 | }; |
| ... | ... | @@ -4562,12 +4554,10 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro |
| 4562 | 4554 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4563 | 4555 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4564 | 4556 | |
| 4565 | | const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt); |
| 4566 | | |
| 4567 | 4557 | // operands to select from |
| 4568 | 4558 | try self.lowerToStack(lhs); |
| 4569 | 4559 | try self.lowerToStack(rhs); |
| 4570 | | try self.emitWValue(cmp_result); |
| 4560 | _ = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt); |
| 4571 | 4561 | |
| 4572 | 4562 | // based on the result from comparison, return operand 0 or 1. |
| 4573 | 4563 | try self.addTag(.select); |
| ... | ... | @@ -4638,7 +4628,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4638 | 4628 | 128 => { |
| 4639 | 4629 | const msb = try self.load(operand, Type.u64, 0); |
| 4640 | 4630 | const lsb = try self.load(operand, Type.u64, 8); |
| 4641 | | const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4642 | 4631 | |
| 4643 | 4632 | try self.emitWValue(lsb); |
| 4644 | 4633 | try self.addTag(.i64_clz); |
| ... | ... | @@ -4646,7 +4635,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4646 | 4635 | try self.addTag(.i64_clz); |
| 4647 | 4636 | try self.emitWValue(.{ .imm64 = 64 }); |
| 4648 | 4637 | try self.addTag(.i64_add); |
| 4649 | | try self.emitWValue(neq); |
| 4638 | _ = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4650 | 4639 | try self.addTag(.select); |
| 4651 | 4640 | try self.addTag(.i32_wrap_i64); |
| 4652 | 4641 | }, |
| ... | ... | @@ -4700,7 +4689,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4700 | 4689 | 128 => { |
| 4701 | 4690 | const msb = try self.load(operand, Type.u64, 0); |
| 4702 | 4691 | const lsb = try self.load(operand, Type.u64, 8); |
| 4703 | | const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4704 | 4692 | |
| 4705 | 4693 | try self.emitWValue(msb); |
| 4706 | 4694 | try self.addTag(.i64_ctz); |
| ... | ... | @@ -4716,7 +4704,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4716 | 4704 | } else { |
| 4717 | 4705 | try self.addTag(.i64_add); |
| 4718 | 4706 | } |
| 4719 | | try self.emitWValue(neq); |
| 4707 | _ = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4720 | 4708 | try self.addTag(.select); |
| 4721 | 4709 | try self.addTag(.i32_wrap_i64); |
| 4722 | 4710 | }, |
| ... | ... | @@ -4952,15 +4940,13 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4952 | 4940 | 64 => WValue{ .imm64 = 0 }, |
| 4953 | 4941 | else => unreachable, |
| 4954 | 4942 | }; |
| 4955 | | const lhs_less_than_zero = try self.cmp(lhs_res, zero, ty, .lt); |
| 4956 | | const rhs_less_than_zero = try self.cmp(rhs_res, zero, ty, .lt); |
| 4957 | 4943 | |
| 4958 | 4944 | const div_result = try self.allocLocal(ty); |
| 4959 | 4945 | // leave on stack |
| 4960 | 4946 | _ = try self.binOp(lhs_res, rhs_res, ty, .div); |
| 4961 | 4947 | try self.addLabel(.local_tee, div_result.local); |
| 4962 | | try self.emitWValue(lhs_less_than_zero); |
| 4963 | | try self.emitWValue(rhs_less_than_zero); |
| 4948 | _ = try self.cmp(lhs_res, zero, ty, .lt); |
| 4949 | _ = try self.cmp(rhs_res, zero, ty, .lt); |
| 4964 | 4950 | switch (wasm_bits) { |
| 4965 | 4951 | 32 => { |
| 4966 | 4952 | try self.addTag(.i32_xor); |
| ... | ... | @@ -5140,19 +5126,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 5140 | 5126 | else => unreachable, |
| 5141 | 5127 | }; |
| 5142 | 5128 | |
| 5143 | | const cmp_result = try self.cmp(bin_result, imm_val, ty, .lt); |
| 5144 | 5129 | try self.emitWValue(bin_result); |
| 5145 | 5130 | try self.emitWValue(imm_val); |
| 5146 | | try self.emitWValue(cmp_result); |
| 5131 | _ = try self.cmp(bin_result, imm_val, ty, .lt); |
| 5147 | 5132 | } else { |
| 5148 | | const cmp_result = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt); |
| 5149 | 5133 | switch (wasm_bits) { |
| 5150 | 5134 | 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0), |
| 5151 | 5135 | 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0), |
| 5152 | 5136 | else => unreachable, |
| 5153 | 5137 | } |
| 5154 | 5138 | try self.emitWValue(bin_result); |
| 5155 | | try self.emitWValue(cmp_result); |
| 5139 | _ = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt); |
| 5156 | 5140 | } |
| 5157 | 5141 | |
| 5158 | 5142 | try self.addTag(.select); |
| ... | ... | @@ -5184,17 +5168,15 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5184 | 5168 | |
| 5185 | 5169 | const bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 5186 | 5170 | if (!is_wasm_bits) { |
| 5187 | | const cmp_result_lt = try self.cmp(bin_result, max_wvalue, ty, .lt); |
| 5188 | 5171 | try self.emitWValue(bin_result); |
| 5189 | 5172 | try self.emitWValue(max_wvalue); |
| 5190 | | try self.emitWValue(cmp_result_lt); |
| 5173 | _ = try self.cmp(bin_result, max_wvalue, ty, .lt); |
| 5191 | 5174 | try self.addTag(.select); |
| 5192 | 5175 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5193 | 5176 | |
| 5194 | | const cmp_result_gt = try self.cmp(bin_result, min_wvalue, ty, .gt); |
| 5195 | 5177 | try self.emitWValue(bin_result); |
| 5196 | 5178 | try self.emitWValue(min_wvalue); |
| 5197 | | try self.emitWValue(cmp_result_gt); |
| 5179 | _ = try self.cmp(bin_result, min_wvalue, ty, .gt); |
| 5198 | 5180 | try self.addTag(.select); |
| 5199 | 5181 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5200 | 5182 | return self.wrapOperand(bin_result, ty); |
| ... | ... | @@ -5204,15 +5186,14 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5204 | 5186 | 64 => WValue{ .imm64 = 0 }, |
| 5205 | 5187 | else => unreachable, |
| 5206 | 5188 | }; |
| 5207 | | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); |
| 5208 | | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); |
| 5209 | | const cmp_bin_zero_result = try self.cmp(bin_result, zero, ty, .lt); |
| 5210 | 5189 | try self.emitWValue(max_wvalue); |
| 5211 | 5190 | try self.emitWValue(min_wvalue); |
| 5212 | | try self.emitWValue(cmp_bin_zero_result); |
| 5191 | _ = try self.cmp(bin_result, zero, ty, .lt); |
| 5213 | 5192 | try self.addTag(.select); |
| 5214 | 5193 | try self.emitWValue(bin_result); |
| 5215 | 5194 | // leave on stack |
| 5195 | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); |
| 5196 | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); |
| 5216 | 5197 | _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. |
| 5217 | 5198 | try self.addTag(.select); |
| 5218 | 5199 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| ... | ... | @@ -5239,7 +5220,6 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5239 | 5220 | if (wasm_bits == int_info.bits) { |
| 5240 | 5221 | const shl = try (try self.binOp(lhs, rhs, ty, .shl)).toLocal(self, ty); |
| 5241 | 5222 | const shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty); |
| 5242 | | const cmp_result = try self.cmp(lhs, shr, ty, .neq); |
| 5243 | 5223 | |
| 5244 | 5224 | switch (wasm_bits) { |
| 5245 | 5225 | 32 => blk: { |
| ... | ... | @@ -5247,10 +5227,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5247 | 5227 | try self.addImm32(-1); |
| 5248 | 5228 | break :blk; |
| 5249 | 5229 | } |
| 5250 | | const less_than_zero = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt); |
| 5251 | 5230 | try self.addImm32(std.math.minInt(i32)); |
| 5252 | 5231 | try self.addImm32(std.math.maxInt(i32)); |
| 5253 | | try self.emitWValue(less_than_zero); |
| 5232 | _ = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt); |
| 5254 | 5233 | try self.addTag(.select); |
| 5255 | 5234 | }, |
| 5256 | 5235 | 64 => blk: { |
| ... | ... | @@ -5258,16 +5237,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5258 | 5237 | try self.addImm64(@bitCast(u64, @as(i64, -1))); |
| 5259 | 5238 | break :blk; |
| 5260 | 5239 | } |
| 5261 | | const less_than_zero = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt); |
| 5262 | 5240 | try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64)))); |
| 5263 | 5241 | try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64)))); |
| 5264 | | try self.emitWValue(less_than_zero); |
| 5242 | _ = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt); |
| 5265 | 5243 | try self.addTag(.select); |
| 5266 | 5244 | }, |
| 5267 | 5245 | else => unreachable, |
| 5268 | 5246 | } |
| 5269 | 5247 | try self.emitWValue(shl); |
| 5270 | | try self.emitWValue(cmp_result); |
| 5248 | _ = try self.cmp(lhs, shr, ty, .neq); |
| 5271 | 5249 | try self.addTag(.select); |
| 5272 | 5250 | try self.addLabel(.local_set, result.local); |
| 5273 | 5251 | return result; |
| ... | ... | @@ -5282,7 +5260,6 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5282 | 5260 | const shl_res = try (try self.binOp(lhs, shift_value, ty, .shl)).toLocal(self, ty); |
| 5283 | 5261 | const shl = try (try self.binOp(shl_res, rhs, ty, .shl)).toLocal(self, ty); |
| 5284 | 5262 | const shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty); |
| 5285 | | const cmp_result = try self.cmp(shl_res, shr, ty, .neq); |
| 5286 | 5263 | |
| 5287 | 5264 | switch (wasm_bits) { |
| 5288 | 5265 | 32 => blk: { |
| ... | ... | @@ -5291,10 +5268,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5291 | 5268 | break :blk; |
| 5292 | 5269 | } |
| 5293 | 5270 | |
| 5294 | | const less_than_zero = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt); |
| 5295 | 5271 | try self.addImm32(std.math.minInt(i32)); |
| 5296 | 5272 | try self.addImm32(std.math.maxInt(i32)); |
| 5297 | | try self.emitWValue(less_than_zero); |
| 5273 | _ = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt); |
| 5298 | 5274 | try self.addTag(.select); |
| 5299 | 5275 | }, |
| 5300 | 5276 | 64 => blk: { |
| ... | ... | @@ -5303,16 +5279,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5303 | 5279 | break :blk; |
| 5304 | 5280 | } |
| 5305 | 5281 | |
| 5306 | | const less_than_zero = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt); |
| 5307 | 5282 | try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64)))); |
| 5308 | 5283 | try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64)))); |
| 5309 | | try self.emitWValue(less_than_zero); |
| 5284 | _ = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt); |
| 5310 | 5285 | try self.addTag(.select); |
| 5311 | 5286 | }, |
| 5312 | 5287 | else => unreachable, |
| 5313 | 5288 | } |
| 5314 | 5289 | try self.emitWValue(shl); |
| 5315 | | try self.emitWValue(cmp_result); |
| 5290 | _ = try self.cmp(shl_res, shr, ty, .neq); |
| 5316 | 5291 | try self.addTag(.select); |
| 5317 | 5292 | try self.addLabel(.local_set, result.local); |
| 5318 | 5293 | const shift_result = try (try self.binOp(result, shift_value, ty, .shr)).toLocal(self, ty); |