authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-07-25 07:10:56+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-11 11:08:00+02:00
log305b113a53cd5905d837ea620e2bcae8912c5938
tree51c4733dee0daaae76060204888f1a21fe0f8aa6
parentcc6f2b67c68ece7577e27e23846670d6566ad5f2
signaturelock-open Commit is signed but in an unrecognized format.

wasm: keep result of `cmp` on the stack

By keeping the result on the stack, we prevent codegen from generating unneccesary locals when we have subsequent instructions that do not have to be re-used.

1 files changed, 50 insertions(+), 75 deletions(-)

src/arch/wasm/CodeGen.zig+50-75
...@@ -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}
26642664
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.
2665fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {2668fn 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));
27062710
2707 const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i322711 return WValue{ .stack = {} };
2708 try self.addLabel(.local_set, cmp_tmp.local);
2709 return cmp_tmp;
2710}2712}
27112713
2712fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue {2714fn 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));
27312733
2732 const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i322734 return WValue{ .stack = {} };
2733 try self.addLabel(.local_set, result.local);
2734 return result;
2735}2735}
27362736
2737fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2737fn 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}
39873988
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 > 1283991/// TODO: Lower this to compiler_rt call when bitsize > 128
3990fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3992fn 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);
40184021 _ = 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 }
40254025
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}
40304028
4031fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4029fn 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 32bit4351 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 else4357 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);
43614360
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);
43664365
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);
43854384
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 signed4400 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;
44094405
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);
44144410
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));
44194414
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);
44244419
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));
44584454
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);
44634459
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 {
45124507
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 else4526 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);
45644556
4565 const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
4566
4567 // operands to select from4557 // 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);
45714561
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);
46424631
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);
47044692
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);
49574943
4958 const div_result = try self.allocLocal(ty);4944 const div_result = try self.allocLocal(ty);
4959 // leave on stack4945 // 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 };
51425128
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 }
51575141
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
51845168
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 local5175 try self.addLabel(.local_set, bin_result.local); // re-use local
51935176
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 local5181 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 stack5194 // 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 local5199 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);
52435223
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);
52865263
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 }
52935270
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 }
53055281
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);