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