| ... | @@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset; | ... | @@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 29 | const WValue = union(enum) { | 29 | const WValue = union(enum) { |
| 30 | /// May be referenced but is unused | 30 | /// May be referenced but is unused |
| 31 | none: void, | 31 | none: void, |
| | 32 | /// The value lives on top of the stack |
| | 33 | stack: void, |
| 32 | /// Index of the local variable | 34 | /// Index of the local variable |
| 33 | local: u32, | 35 | local: u32, |
| 34 | /// An immediate 32bit value | 36 | /// An immediate 32bit value |
| ... | @@ -55,7 +57,7 @@ const WValue = union(enum) { | ... | @@ -55,7 +57,7 @@ const WValue = union(enum) { |
| 55 | /// In wasm function pointers are indexes into a function table, | 57 | /// In wasm function pointers are indexes into a function table, |
| 56 | /// rather than an address in the data section. | 58 | /// rather than an address in the data section. |
| 57 | function_index: u32, | 59 | function_index: u32, |
| 58 | /// Offset from the bottom of the stack, with the offset | 60 | /// Offset from the bottom of the virtual stack, with the offset |
| 59 | /// pointing to where the value lives. | 61 | /// pointing to where the value lives. |
| 60 | stack_offset: u32, | 62 | stack_offset: u32, |
| 61 | | 63 | |
| ... | @@ -71,6 +73,21 @@ const WValue = union(enum) { | ... | @@ -71,6 +73,21 @@ const WValue = union(enum) { |
| 71 | else => return 0, | 73 | else => return 0, |
| 72 | } | 74 | } |
| 73 | } | 75 | } |
| | 76 | |
| | 77 | /// Promotes a `WValue` to a local when given value is on top of the stack. |
| | 78 | /// When encountering a `local` or `stack_offset` this is essentially a no-op. |
| | 79 | /// All other tags are illegal. |
| | 80 | fn toLocal(self: WValue, gen: *Self, ty: Type) InnerError!WValue { |
| | 81 | switch (self) { |
| | 82 | .stack => { |
| | 83 | const local = try gen.allocLocal(ty); |
| | 84 | try gen.addLabel(.local_set, local.local); |
| | 85 | return local; |
| | 86 | }, |
| | 87 | .local, .stack_offset => return self, |
| | 88 | else => unreachable, |
| | 89 | } |
| | 90 | } |
| 74 | }; | 91 | }; |
| 75 | | 92 | |
| 76 | /// Wasm ops, but without input/output/signedness information | 93 | /// Wasm ops, but without input/output/signedness information |
| ... | @@ -774,7 +791,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 { | ... | @@ -774,7 +791,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 { |
| 774 | /// Writes the bytecode depending on the given `WValue` in `val` | 791 | /// Writes the bytecode depending on the given `WValue` in `val` |
| 775 | fn emitWValue(self: *Self, value: WValue) InnerError!void { | 792 | fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 776 | switch (value) { | 793 | switch (value) { |
| 777 | .none => {}, // no-op | 794 | .none, .stack => {}, // no-op |
| 778 | .local => |idx| try self.addLabel(.local_get, idx), | 795 | .local => |idx| try self.addLabel(.local_get, idx), |
| 779 | .imm32 => |val| try self.addImm32(@bitCast(i32, val)), | 796 | .imm32 => |val| try self.addImm32(@bitCast(i32, val)), |
| 780 | .imm64 => |val| try self.addImm64(val), | 797 | .imm64 => |val| try self.addImm64(val), |
| ... | @@ -1892,6 +1909,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1892,6 +1909,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1892 | } | 1909 | } |
| 1893 | | 1910 | |
| 1894 | fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { | 1911 | fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { |
| | 1912 | assert(!(lhs != .stack and rhs == .stack)); |
| 1895 | switch (ty.zigTypeTag()) { | 1913 | switch (ty.zigTypeTag()) { |
| 1896 | .ErrorUnion => { | 1914 | .ErrorUnion => { |
| 1897 | const pl_ty = ty.errorUnionPayload(); | 1915 | const pl_ty = ty.errorUnionPayload(); |
| ... | @@ -2070,10 +2088,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -2070,10 +2088,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 2070 | const rhs = try self.resolveInst(bin_op.rhs); | 2088 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2071 | const ty = self.air.typeOf(bin_op.lhs); | 2089 | const ty = self.air.typeOf(bin_op.lhs); |
| 2072 | | 2090 | |
| 2073 | return self.binOp(lhs, rhs, ty, op); | 2091 | const stack_value = try self.binOp(lhs, rhs, ty, op); |
| | 2092 | return stack_value.toLocal(self, ty); |
| 2074 | } | 2093 | } |
| 2075 | | 2094 | |
| | 2095 | /// Performs a binary operation on the given `WValue`'s |
| | 2096 | /// NOTE: THis leaves the value on top of the stack. |
| 2076 | fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2097 | fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| | 2098 | assert(!(lhs != .stack and rhs == .stack)); |
| 2077 | if (isByRef(ty, self.target)) { | 2099 | if (isByRef(ty, self.target)) { |
| 2078 | if (ty.zigTypeTag() == .Int) { | 2100 | if (ty.zigTypeTag() == .Int) { |
| 2079 | return self.binOpBigInt(lhs, rhs, ty, op); | 2101 | return self.binOpBigInt(lhs, rhs, ty, op); |
| ... | @@ -2099,10 +2121,7 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa | ... | @@ -2099,10 +2121,7 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa |
| 2099 | | 2121 | |
| 2100 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 2122 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2101 | | 2123 | |
| 2102 | // save the result in a temporary | 2124 | return WValue{ .stack = {} }; |
| 2103 | const bin_local = try self.allocLocal(ty); | | |
| 2104 | try self.addLabel(.local_set, bin_local.local); | | |
| 2105 | return bin_local; | | |
| 2106 | } | 2125 | } |
| 2107 | | 2126 | |
| 2108 | fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue { | 2127 | fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue { |
| ... | @@ -2134,8 +2153,8 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr | ... | @@ -2134,8 +2153,8 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr |
| 2134 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); | 2153 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); |
| 2135 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | 2154 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 2136 | | 2155 | |
| 2137 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); | 2156 | const low_op_res = try (try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(self, Type.u64); |
| 2138 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); | 2157 | const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64); |
| 2139 | | 2158 | |
| 2140 | const lt = if (op == .add) blk: { | 2159 | const lt = if (op == .add) blk: { |
| 2141 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); | 2160 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); |
| ... | @@ -2143,7 +2162,7 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr | ... | @@ -2143,7 +2162,7 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr |
| 2143 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); | 2162 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); |
| 2144 | } else unreachable; | 2163 | } else unreachable; |
| 2145 | const tmp = try self.intcast(lt, Type.u32, Type.u64); | 2164 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 2146 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); | 2165 | const tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64); |
| 2147 | | 2166 | |
| 2148 | try self.store(result, high_op_res, Type.u64, 0); | 2167 | try self.store(result, high_op_res, Type.u64, 0); |
| 2149 | try self.store(result, tmp_op, Type.u64, 8); | 2168 | try self.store(result, tmp_op, Type.u64, 8); |
| ... | @@ -2202,6 +2221,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -2202,6 +2221,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2202 | if (wasm_bits == bitsize) return operand; | 2221 | if (wasm_bits == bitsize) return operand; |
| 2203 | | 2222 | |
| 2204 | if (wasm_bits == 128) { | 2223 | if (wasm_bits == 128) { |
| | 2224 | assert(operand != .stack); |
| 2205 | const msb = try self.load(operand, Type.u64, 0); | 2225 | const msb = try self.load(operand, Type.u64, 0); |
| 2206 | const lsb = try self.load(operand, Type.u64, 8); | 2226 | const lsb = try self.load(operand, Type.u64, 8); |
| 2207 | | 2227 | |
| ... | @@ -2772,19 +2792,19 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2772,19 +2792,19 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2772 | switch (wasm_bits) { | 2792 | switch (wasm_bits) { |
| 2773 | 32 => { | 2793 | 32 => { |
| 2774 | const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); | 2794 | const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); |
| 2775 | return self.wrapOperand(bin_op, operand_ty); | 2795 | return (try self.wrapOperand(bin_op, operand_ty)).toLocal(self, operand_ty); |
| 2776 | }, | 2796 | }, |
| 2777 | 64 => { | 2797 | 64 => { |
| 2778 | const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); | 2798 | const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); |
| 2779 | return self.wrapOperand(bin_op, operand_ty); | 2799 | return (try self.wrapOperand(bin_op, operand_ty)).toLocal(self, operand_ty); |
| 2780 | }, | 2800 | }, |
| 2781 | 128 => { | 2801 | 128 => { |
| 2782 | const result_ptr = try self.allocStack(operand_ty); | 2802 | const result_ptr = try self.allocStack(operand_ty); |
| 2783 | const msb = try self.load(operand, Type.u64, 0); | 2803 | const msb = try self.load(operand, Type.u64, 0); |
| 2784 | const lsb = try self.load(operand, Type.u64, 8); | 2804 | const lsb = try self.load(operand, Type.u64, 8); |
| 2785 | | 2805 | |
| 2786 | const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); | 2806 | const msb_xor = try (try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor)).toLocal(self, operand_ty); |
| 2787 | const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); | 2807 | const lsb_xor = try (try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor)).toLocal(self, operand_ty); |
| 2788 | try self.store(result_ptr, msb_xor, Type.u64, 0); | 2808 | try self.store(result_ptr, msb_xor, Type.u64, 0); |
| 2789 | try self.store(result_ptr, lsb_xor, Type.u64, 8); | 2809 | try self.store(result_ptr, lsb_xor, Type.u64, 8); |
| 2790 | return result_ptr; | 2810 | return result_ptr; |
| ... | @@ -3215,7 +3235,7 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W | ... | @@ -3215,7 +3235,7 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W |
| 3215 | | 3235 | |
| 3216 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value | 3236 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 3217 | if (wanted.isSignedInt()) { | 3237 | if (wanted.isSignedInt()) { |
| 3218 | const shr = try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); | 3238 | const shr = try (try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr)).toLocal(self, Type.i64); |
| 3219 | try self.store(stack_ptr, shr, Type.u64, 8); | 3239 | try self.store(stack_ptr, shr, Type.u64, 8); |
| 3220 | } else { | 3240 | } else { |
| 3221 | // Ensure memory of lsb is zero'd | 3241 | // Ensure memory of lsb is zero'd |
| ... | @@ -4320,7 +4340,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W | ... | @@ -4320,7 +4340,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4320 | break :blk try self.signAbsValue(rhs_op, lhs_ty); | 4340 | break :blk try self.signAbsValue(rhs_op, lhs_ty); |
| 4321 | } else rhs_op; | 4341 | } else rhs_op; |
| 4322 | | 4342 | |
| 4323 | const bin_op = try self.binOp(lhs, rhs, lhs_ty, op); | 4343 | const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty); |
| 4324 | const result = if (wasm_bits != int_info.bits) blk: { | 4344 | const result = if (wasm_bits != int_info.bits) blk: { |
| 4325 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4345 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4326 | } else bin_op; | 4346 | } else bin_op; |
| ... | @@ -4330,7 +4350,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W | ... | @@ -4330,7 +4350,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4330 | if (wasm_bits == int_info.bits) { | 4350 | if (wasm_bits == int_info.bits) { |
| 4331 | const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op); | 4351 | const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op); |
| 4332 | const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt); | 4352 | const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt); |
| 4333 | break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); // result of cmp_zero and lt is always 32bit | 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 |
| 4334 | } | 4354 | } |
| 4335 | const abs = try self.signAbsValue(bin_op, lhs_ty); | 4355 | const abs = try self.signAbsValue(bin_op, lhs_ty); |
| 4336 | break :blk try self.cmp(abs, bin_op, lhs_ty, .neq); | 4356 | break :blk try self.cmp(abs, bin_op, lhs_ty, .neq); |
| ... | @@ -4360,8 +4380,8 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, | ... | @@ -4360,8 +4380,8 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, |
| 4360 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); | 4380 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); |
| 4361 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | 4381 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 4362 | | 4382 | |
| 4363 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); | 4383 | const low_op_res = try (try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(self, Type.u64); |
| 4364 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); | 4384 | const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64); |
| 4365 | | 4385 | |
| 4366 | const lt = if (op == .add) blk: { | 4386 | const lt = if (op == .add) blk: { |
| 4367 | break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt); | 4387 | break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt); |
| ... | @@ -4369,14 +4389,14 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, | ... | @@ -4369,14 +4389,14 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, |
| 4369 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); | 4389 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); |
| 4370 | } else unreachable; | 4390 | } else unreachable; |
| 4371 | const tmp = try self.intcast(lt, Type.u32, Type.u64); | 4391 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 4372 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); | 4392 | const tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64); |
| 4373 | | 4393 | |
| 4374 | const overflow_bit = if (is_signed) blk: { | 4394 | const overflow_bit = if (is_signed) blk: { |
| 4375 | const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor); | | |
| 4376 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); | 4395 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); |
| 4377 | const to_wrap = if (op == .add) wrap: { | 4396 | const to_wrap = if (op == .add) wrap: { |
| 4378 | break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); | 4397 | break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 4379 | } else xor_low; | 4398 | } else xor_low; |
| | 4399 | const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor); |
| 4380 | const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and"); | 4400 | const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and"); |
| 4381 | break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed | 4401 | break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed |
| 4382 | } else blk: { | 4402 | } else blk: { |
| ... | @@ -4422,7 +4442,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4422,7 +4442,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4422 | return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); | 4442 | return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 4423 | }; | 4443 | }; |
| 4424 | | 4444 | |
| 4425 | const shl = try self.binOp(lhs, rhs, lhs_ty, .shl); | 4445 | const shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty); |
| 4426 | const result = if (wasm_bits != int_info.bits) blk: { | 4446 | const result = if (wasm_bits != int_info.bits) blk: { |
| 4427 | break :blk try self.wrapOperand(shl, lhs_ty); | 4447 | break :blk try self.wrapOperand(shl, lhs_ty); |
| 4428 | } else shl; | 4448 | } else shl; |
| ... | @@ -4432,7 +4452,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4432,7 +4452,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4432 | const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr); | 4452 | const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr); |
| 4433 | break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq); | 4453 | break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq); |
| 4434 | } else blk: { | 4454 | } else blk: { |
| 4435 | const shr = try self.binOp(result, rhs, lhs_ty, .shr); | 4455 | const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty); |
| 4436 | break :blk try self.cmp(lhs, shr, lhs_ty, .neq); | 4456 | break :blk try self.cmp(lhs, shr, lhs_ty, .neq); |
| 4437 | }; | 4457 | }; |
| 4438 | | 4458 | |
| ... | @@ -4478,7 +4498,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4478,7 +4498,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4478 | const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64; | 4498 | const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64; |
| 4479 | const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty); | 4499 | const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty); |
| 4480 | const rhs_upcast = try self.intcast(rhs, lhs_ty, new_ty); | 4500 | const rhs_upcast = try self.intcast(rhs, lhs_ty, new_ty); |
| 4481 | const bin_op = try self.binOp(lhs_upcast, rhs_upcast, new_ty, .mul); | 4501 | const bin_op = try (try self.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(self, new_ty); |
| 4482 | if (int_info.signedness == .unsigned) { | 4502 | if (int_info.signedness == .unsigned) { |
| 4483 | const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); | 4503 | const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 4484 | const wrap = try self.intcast(shr, new_ty, lhs_ty); | 4504 | const wrap = try self.intcast(shr, new_ty, lhs_ty); |
| ... | @@ -4488,7 +4508,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4488,7 +4508,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4488 | break :blk try self.intcast(bin_op, new_ty, lhs_ty); | 4508 | break :blk try self.intcast(bin_op, new_ty, lhs_ty); |
| 4489 | } else { | 4509 | } else { |
| 4490 | const down_cast = try self.intcast(bin_op, new_ty, lhs_ty); | 4510 | const down_cast = try self.intcast(bin_op, new_ty, lhs_ty); |
| 4491 | const shr = try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr); | 4511 | const shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty); |
| 4492 | | 4512 | |
| 4493 | const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); | 4513 | const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 4494 | const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty); | 4514 | const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty); |
| ... | @@ -4500,14 +4520,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4500,14 +4520,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4500 | } else if (int_info.signedness == .signed) blk: { | 4520 | } else if (int_info.signedness == .signed) blk: { |
| 4501 | const lhs_abs = try self.signAbsValue(lhs, lhs_ty); | 4521 | const lhs_abs = try self.signAbsValue(lhs, lhs_ty); |
| 4502 | const rhs_abs = try self.signAbsValue(rhs, lhs_ty); | 4522 | const rhs_abs = try self.signAbsValue(rhs, lhs_ty); |
| 4503 | const bin_op = try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul); | 4523 | const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty); |
| 4504 | const mul_abs = try self.signAbsValue(bin_op, lhs_ty); | 4524 | const mul_abs = try self.signAbsValue(bin_op, lhs_ty); |
| 4505 | const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); | 4525 | const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 4506 | try self.emitWValue(cmp_op); | 4526 | try self.emitWValue(cmp_op); |
| 4507 | try self.addLabel(.local_set, overflow_bit.local); | 4527 | try self.addLabel(.local_set, overflow_bit.local); |
| 4508 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4528 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4509 | } else blk: { | 4529 | } else blk: { |
| 4510 | const bin_op = try self.binOp(lhs, rhs, lhs_ty, .mul); | 4530 | const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(self, lhs_ty); |
| 4511 | const shift_imm = if (wasm_bits == 32) | 4531 | const shift_imm = if (wasm_bits == 32) |
| 4512 | WValue{ .imm32 = int_info.bits } | 4532 | WValue{ .imm32 = int_info.bits } |
| 4513 | else | 4533 | else |
| ... | @@ -4587,7 +4607,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4587,7 +4607,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4587 | } | 4607 | } |
| 4588 | | 4608 | |
| 4589 | const mul_result = try self.binOp(lhs, rhs, ty, .mul); | 4609 | const mul_result = try self.binOp(lhs, rhs, ty, .mul); |
| 4590 | return self.binOp(mul_result, addend, ty, .add); | 4610 | return (try self.binOp(mul_result, addend, ty, .add)).toLocal(self, ty); |
| 4591 | } | 4611 | } |
| 4592 | | 4612 | |
| 4593 | fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4613 | fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4663,16 +4683,16 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4663,16 +4683,16 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4663 | 32 => { | 4683 | 32 => { |
| 4664 | if (wasm_bits != int_info.bits) { | 4684 | if (wasm_bits != int_info.bits) { |
| 4665 | const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits); | 4685 | const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits); |
| 4666 | const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or"); | 4686 | // leave value on the stack |
| 4667 | try self.emitWValue(bin_op); | 4687 | _ = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or"); |
| 4668 | } else try self.emitWValue(operand); | 4688 | } else try self.emitWValue(operand); |
| 4669 | try self.addTag(.i32_ctz); | 4689 | try self.addTag(.i32_ctz); |
| 4670 | }, | 4690 | }, |
| 4671 | 64 => { | 4691 | 64 => { |
| 4672 | if (wasm_bits != int_info.bits) { | 4692 | if (wasm_bits != int_info.bits) { |
| 4673 | const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits); | 4693 | const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits); |
| 4674 | const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or"); | 4694 | // leave value on the stack |
| 4675 | try self.emitWValue(bin_op); | 4695 | _ = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or"); |
| 4676 | } else try self.emitWValue(operand); | 4696 | } else try self.emitWValue(operand); |
| 4677 | try self.addTag(.i64_ctz); | 4697 | try self.addTag(.i64_ctz); |
| 4678 | try self.addTag(.i32_wrap_i64); | 4698 | try self.addTag(.i32_wrap_i64); |
| ... | @@ -4847,45 +4867,45 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4847,45 +4867,45 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4847 | switch (int_info.bits) { | 4867 | switch (int_info.bits) { |
| 4848 | 16 => { | 4868 | 16 => { |
| 4849 | const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); | 4869 | const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); |
| 4850 | const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and"); | 4870 | const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and")).toLocal(self, ty); |
| 4851 | const shr_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); | 4871 | const shr_res = try (try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty); |
| 4852 | const res = if (int_info.signedness == .signed) blk: { | 4872 | const res = if (int_info.signedness == .signed) blk: { |
| 4853 | break :blk try self.wrapOperand(shr_res, Type.u8); | 4873 | break :blk try self.wrapOperand(shr_res, Type.u8); |
| 4854 | } else shr_res; | 4874 | } else shr_res; |
| 4855 | return self.binOp(lhs, res, ty, .@"or"); | 4875 | return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty); |
| 4856 | }, | 4876 | }, |
| 4857 | 24 => { | 4877 | 24 => { |
| 4858 | const msb = try self.wrapOperand(operand, Type.u16); | 4878 | const msb = try self.wrapOperand(operand, Type.u16); |
| 4859 | const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); | 4879 | const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); |
| 4860 | | 4880 | |
| 4861 | const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); | 4881 | const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); |
| 4862 | const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and"); | 4882 | const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and")).toLocal(self, Type.u16); |
| 4863 | const shr_res = try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr); | 4883 | const shr_res = try (try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty); |
| 4864 | | 4884 | |
| 4865 | const res = if (int_info.signedness == .signed) blk: { | 4885 | const res = if (int_info.signedness == .signed) blk: { |
| 4866 | break :blk try self.wrapOperand(shr_res, Type.u8); | 4886 | break :blk try self.wrapOperand(shr_res, Type.u8); |
| 4867 | } else shr_res; | 4887 | } else shr_res; |
| 4868 | const lhs_tmp = try self.binOp(lhs, res, ty, .@"or"); | 4888 | const lhs_tmp = try self.binOp(lhs, res, ty, .@"or"); |
| 4869 | const lhs_result = try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr); | 4889 | const lhs_result = try (try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty); |
| 4870 | const rhs_wrap = try self.wrapOperand(msb, Type.u8); | 4890 | const rhs_wrap = try self.wrapOperand(msb, Type.u8); |
| 4871 | const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl); | 4891 | const rhs_result = try (try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl)).toLocal(self, ty); |
| 4872 | | 4892 | |
| 4873 | const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or"); | 4893 | const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or"); |
| 4874 | return self.binOp(tmp, lsb, ty, .@"or"); | 4894 | return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty); |
| 4875 | }, | 4895 | }, |
| 4876 | 32 => { | 4896 | 32 => { |
| 4877 | const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); | 4897 | const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); |
| 4878 | const lhs = try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and"); | 4898 | const lhs = try (try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and")).toLocal(self, ty); |
| 4879 | const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); | 4899 | const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); |
| 4880 | const rhs = try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and"); | 4900 | const rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty); |
| 4881 | const tmp_or = try self.binOp(lhs, rhs, ty, .@"or"); | 4901 | const tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty); |
| 4882 | | 4902 | |
| 4883 | const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); | 4903 | const shr = try (try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr)).toLocal(self, ty); |
| 4884 | const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr); | | |
| 4885 | const res = if (int_info.signedness == .signed) blk: { | 4904 | const res = if (int_info.signedness == .signed) blk: { |
| 4886 | break :blk try self.wrapOperand(shr, Type.u16); | 4905 | break :blk try self.wrapOperand(shr, Type.u16); |
| 4887 | } else shr; | 4906 | } else shr; |
| 4888 | return self.binOp(shl, res, ty, .@"or"); | 4907 | const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); |
| | 4908 | return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty); |
| 4889 | }, | 4909 | }, |
| 4890 | else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), | 4910 | else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), |
| 4891 | } | 4911 | } |
| ... | @@ -4902,7 +4922,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4902,7 +4922,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4902 | if (ty.isSignedInt()) { | 4922 | if (ty.isSignedInt()) { |
| 4903 | return self.divSigned(lhs, rhs, ty); | 4923 | return self.divSigned(lhs, rhs, ty); |
| 4904 | } | 4924 | } |
| 4905 | return self.binOp(lhs, rhs, ty, .div); | 4925 | return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty); |
| 4906 | } | 4926 | } |
| 4907 | | 4927 | |
| 4908 | fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4928 | fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4914,7 +4934,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4914,7 +4934,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4914 | const rhs = try self.resolveInst(bin_op.rhs); | 4934 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4915 | | 4935 | |
| 4916 | if (ty.isUnsignedInt()) { | 4936 | if (ty.isUnsignedInt()) { |
| 4917 | return self.binOp(lhs, rhs, ty, .div); | 4937 | return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty); |
| 4918 | } else if (ty.isSignedInt()) { | 4938 | } else if (ty.isSignedInt()) { |
| 4919 | const int_bits = ty.intInfo(self.target).bits; | 4939 | const int_bits = ty.intInfo(self.target).bits; |
| 4920 | const wasm_bits = toWasmBits(int_bits) orelse { | 4940 | const wasm_bits = toWasmBits(int_bits) orelse { |
| ... | @@ -4927,9 +4947,6 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4927,9 +4947,6 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4927 | break :blk try self.signAbsValue(rhs, ty); | 4947 | break :blk try self.signAbsValue(rhs, ty); |
| 4928 | } else rhs; | 4948 | } else rhs; |
| 4929 | | 4949 | |
| 4930 | const div_result = try self.binOp(lhs_res, rhs_res, ty, .div); | | |
| 4931 | const rem_result = try self.binOp(lhs_res, rhs_res, ty, .rem); | | |
| 4932 | | | |
| 4933 | const zero = switch (wasm_bits) { | 4950 | const zero = switch (wasm_bits) { |
| 4934 | 32 => WValue{ .imm32 = 0 }, | 4951 | 32 => WValue{ .imm32 = 0 }, |
| 4935 | 64 => WValue{ .imm64 = 0 }, | 4952 | 64 => WValue{ .imm64 = 0 }, |
| ... | @@ -4938,7 +4955,10 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4938,7 +4955,10 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4938 | const lhs_less_than_zero = try self.cmp(lhs_res, zero, ty, .lt); | 4955 | const lhs_less_than_zero = try self.cmp(lhs_res, zero, ty, .lt); |
| 4939 | const rhs_less_than_zero = try self.cmp(rhs_res, zero, ty, .lt); | 4956 | const rhs_less_than_zero = try self.cmp(rhs_res, zero, ty, .lt); |
| 4940 | | 4957 | |
| 4941 | try self.emitWValue(div_result); | 4958 | const div_result = try self.allocLocal(ty); |
| | 4959 | // leave on stack |
| | 4960 | _ = try self.binOp(lhs_res, rhs_res, ty, .div); |
| | 4961 | try self.addLabel(.local_tee, div_result.local); |
| 4942 | try self.emitWValue(lhs_less_than_zero); | 4962 | try self.emitWValue(lhs_less_than_zero); |
| 4943 | try self.emitWValue(rhs_less_than_zero); | 4963 | try self.emitWValue(rhs_less_than_zero); |
| 4944 | switch (wasm_bits) { | 4964 | switch (wasm_bits) { |
| ... | @@ -4953,7 +4973,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4953,7 +4973,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4953 | else => unreachable, | 4973 | else => unreachable, |
| 4954 | } | 4974 | } |
| 4955 | try self.emitWValue(div_result); | 4975 | try self.emitWValue(div_result); |
| 4956 | try self.emitWValue(rem_result); | 4976 | // leave value on the stack |
| | 4977 | _ = try self.binOp(lhs_res, rhs_res, ty, .rem); |
| 4957 | try self.addTag(.select); | 4978 | try self.addTag(.select); |
| 4958 | } else { | 4979 | } else { |
| 4959 | const float_bits = ty.floatBits(self.target); | 4980 | const float_bits = ty.floatBits(self.target); |
| ... | @@ -5110,7 +5131,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -5110,7 +5131,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 5110 | } | 5131 | } |
| 5111 | | 5132 | |
| 5112 | const wasm_bits = toWasmBits(int_info.bits).?; | 5133 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 5113 | const bin_result = try self.binOp(lhs, rhs, ty, op); | 5134 | const bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 5114 | if (wasm_bits != int_info.bits and op == .add) { | 5135 | if (wasm_bits != int_info.bits and op == .add) { |
| 5115 | const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1); | 5136 | const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1); |
| 5116 | const imm_val = switch (wasm_bits) { | 5137 | const imm_val = switch (wasm_bits) { |
| ... | @@ -5161,7 +5182,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op | ... | @@ -5161,7 +5182,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5161 | else => unreachable, | 5182 | else => unreachable, |
| 5162 | }; | 5183 | }; |
| 5163 | | 5184 | |
| 5164 | const bin_result = try self.binOp(lhs, rhs, ty, op); | 5185 | const bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 5165 | if (!is_wasm_bits) { | 5186 | if (!is_wasm_bits) { |
| 5166 | const cmp_result_lt = try self.cmp(bin_result, max_wvalue, ty, .lt); | 5187 | const cmp_result_lt = try self.cmp(bin_result, max_wvalue, ty, .lt); |
| 5167 | try self.emitWValue(bin_result); | 5188 | try self.emitWValue(bin_result); |
| ... | @@ -5185,14 +5206,14 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op | ... | @@ -5185,14 +5206,14 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5185 | }; | 5206 | }; |
| 5186 | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); | 5207 | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); |
| 5187 | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); | 5208 | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); |
| 5188 | const xor = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. | | |
| 5189 | const cmp_bin_zero_result = try self.cmp(bin_result, zero, ty, .lt); | 5209 | const cmp_bin_zero_result = try self.cmp(bin_result, zero, ty, .lt); |
| 5190 | try self.emitWValue(max_wvalue); | 5210 | try self.emitWValue(max_wvalue); |
| 5191 | try self.emitWValue(min_wvalue); | 5211 | try self.emitWValue(min_wvalue); |
| 5192 | try self.emitWValue(cmp_bin_zero_result); | 5212 | try self.emitWValue(cmp_bin_zero_result); |
| 5193 | try self.addTag(.select); | 5213 | try self.addTag(.select); |
| 5194 | try self.emitWValue(bin_result); | 5214 | try self.emitWValue(bin_result); |
| 5195 | try self.emitWValue(xor); | 5215 | // leave on stack |
| | 5216 | _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. |
| 5196 | try self.addTag(.select); | 5217 | try self.addTag(.select); |
| 5197 | try self.addLabel(.local_set, bin_result.local); // re-use local | 5218 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5198 | return bin_result; | 5219 | return bin_result; |
| ... | @@ -5216,8 +5237,8 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5216,8 +5237,8 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5216 | const result = try self.allocLocal(ty); | 5237 | const result = try self.allocLocal(ty); |
| 5217 | | 5238 | |
| 5218 | if (wasm_bits == int_info.bits) { | 5239 | if (wasm_bits == int_info.bits) { |
| 5219 | const shl = try self.binOp(lhs, rhs, ty, .shl); | 5240 | const shl = try (try self.binOp(lhs, rhs, ty, .shl)).toLocal(self, ty); |
| 5220 | const shr = try self.binOp(shl, rhs, ty, .shr); | 5241 | const shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty); |
| 5221 | const cmp_result = try self.cmp(lhs, shr, ty, .neq); | 5242 | const cmp_result = try self.cmp(lhs, shr, ty, .neq); |
| 5222 | | 5243 | |
| 5223 | switch (wasm_bits) { | 5244 | switch (wasm_bits) { |
| ... | @@ -5258,9 +5279,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5258,9 +5279,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5258 | else => unreachable, | 5279 | else => unreachable, |
| 5259 | }; | 5280 | }; |
| 5260 | | 5281 | |
| 5261 | const shl_res = try self.binOp(lhs, shift_value, ty, .shl); | 5282 | const shl_res = try (try self.binOp(lhs, shift_value, ty, .shl)).toLocal(self, ty); |
| 5262 | const shl = try self.binOp(shl_res, rhs, ty, .shl); | 5283 | const shl = try (try self.binOp(shl_res, rhs, ty, .shl)).toLocal(self, ty); |
| 5263 | const shr = try self.binOp(shl, rhs, ty, .shr); | 5284 | const shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty); |
| 5264 | const cmp_result = try self.cmp(shl_res, shr, ty, .neq); | 5285 | const cmp_result = try self.cmp(shl_res, shr, ty, .neq); |
| 5265 | | 5286 | |
| 5266 | switch (wasm_bits) { | 5287 | switch (wasm_bits) { |
| ... | @@ -5294,7 +5315,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5294,7 +5315,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5294 | try self.emitWValue(cmp_result); | 5315 | try self.emitWValue(cmp_result); |
| 5295 | try self.addTag(.select); | 5316 | try self.addTag(.select); |
| 5296 | try self.addLabel(.local_set, result.local); | 5317 | try self.addLabel(.local_set, result.local); |
| 5297 | const shift_result = try self.binOp(result, shift_value, ty, .shr); | 5318 | const shift_result = try (try self.binOp(result, shift_value, ty, .shr)).toLocal(self, ty); |
| 5298 | if (is_signed) { | 5319 | if (is_signed) { |
| 5299 | return self.wrapOperand(shift_result, ty); | 5320 | return self.wrapOperand(shift_result, ty); |
| 5300 | } | 5321 | } |