| ... | @@ -4154,7 +4154,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4154,7 +4154,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4154 | return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); | 4154 | return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); |
| 4155 | }; | 4155 | }; |
| 4156 | | 4156 | |
| 4157 | if (wasm_bits == 64) { | 4157 | if (wasm_bits > 32) { |
| 4158 | return self.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); | 4158 | return self.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); |
| 4159 | } | 4159 | } |
| 4160 | | 4160 | |
| ... | @@ -4236,32 +4236,26 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro | ... | @@ -4236,32 +4236,26 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro |
| 4236 | return self.fail("TODO: `@maximum` and `@minimum` for vectors", .{}); | 4236 | return self.fail("TODO: `@maximum` and `@minimum` for vectors", .{}); |
| 4237 | } | 4237 | } |
| 4238 | | 4238 | |
| 4239 | if (ty.abiSize(self.target) > 8) { | 4239 | if (ty.abiSize(self.target) > 16) { |
| 4240 | return self.fail("TODO: `@maximum` and `@minimum` for types larger than 8 bytes", .{}); | 4240 | return self.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{}); |
| 4241 | } | 4241 | } |
| 4242 | | 4242 | |
| 4243 | const lhs = try self.resolveInst(bin_op.lhs); | 4243 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4244 | const rhs = try self.resolveInst(bin_op.rhs); | 4244 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4245 | | 4245 | |
| 4246 | // operands to select from | 4246 | const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt); |
| 4247 | try self.emitWValue(lhs); | | |
| 4248 | try self.emitWValue(rhs); | | |
| 4249 | | 4247 | |
| 4250 | // operands to compare | 4248 | // operands to select from |
| 4251 | try self.emitWValue(lhs); | 4249 | try self.lowerToStack(lhs); |
| 4252 | try self.emitWValue(rhs); | 4250 | try self.lowerToStack(rhs); |
| 4253 | const opcode = buildOpcode(.{ | 4251 | try self.emitWValue(cmp_result); |
| 4254 | .op = if (op == .max) .gt else .lt, | | |
| 4255 | .signedness = if (ty.isSignedInt()) .signed else .unsigned, | | |
| 4256 | .valtype1 = typeToValtype(ty, self.target), | | |
| 4257 | }); | | |
| 4258 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | | |
| 4259 | | 4252 | |
| 4260 | // based on the result from comparison, return operand 0 or 1. | 4253 | // based on the result from comparison, return operand 0 or 1. |
| 4261 | try self.addTag(.select); | 4254 | try self.addTag(.select); |
| 4262 | | 4255 | |
| 4263 | // store result in local | 4256 | // store result in local |
| 4264 | const result = try self.allocLocal(ty); | 4257 | const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty; |
| | 4258 | const result = try self.allocLocal(result_ty); |
| 4265 | try self.addLabel(.local_set, result.local); | 4259 | try self.addLabel(.local_set, result.local); |
| 4266 | return result; | 4260 | return result; |
| 4267 | } | 4261 | } |
| ... | @@ -4302,31 +4296,39 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4302,31 +4296,39 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4302 | return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); | 4296 | return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); |
| 4303 | }; | 4297 | }; |
| 4304 | | 4298 | |
| 4305 | try self.emitWValue(operand); | | |
| 4306 | switch (wasm_bits) { | 4299 | switch (wasm_bits) { |
| 4307 | 32 => { | 4300 | 32 => { |
| | 4301 | try self.emitWValue(operand); |
| 4308 | try self.addTag(.i32_clz); | 4302 | try self.addTag(.i32_clz); |
| 4309 | | | |
| 4310 | if (wasm_bits != int_info.bits) { | | |
| 4311 | const tmp = try self.allocLocal(ty); | | |
| 4312 | try self.addLabel(.local_set, tmp.local); | | |
| 4313 | const val: i32 = -@intCast(i32, wasm_bits - int_info.bits); | | |
| 4314 | return self.wrapBinOp(tmp, .{ .imm32 = @bitCast(u32, val) }, ty, .add); | | |
| 4315 | } | | |
| 4316 | }, | 4303 | }, |
| 4317 | 64 => { | 4304 | 64 => { |
| | 4305 | try self.emitWValue(operand); |
| 4318 | try self.addTag(.i64_clz); | 4306 | try self.addTag(.i64_clz); |
| | 4307 | try self.addTag(.i32_wrap_i64); |
| | 4308 | }, |
| | 4309 | 128 => { |
| | 4310 | const msb = try self.load(operand, Type.u64, 0); |
| | 4311 | const lsb = try self.load(operand, Type.u64, 8); |
| | 4312 | const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4319 | | 4313 | |
| 4320 | if (wasm_bits != int_info.bits) { | 4314 | try self.emitWValue(lsb); |
| 4321 | const tmp = try self.allocLocal(ty); | 4315 | try self.addTag(.i64_clz); |
| 4322 | try self.addLabel(.local_set, tmp.local); | 4316 | try self.emitWValue(msb); |
| 4323 | const val: i64 = -@intCast(i64, wasm_bits - int_info.bits); | 4317 | try self.addTag(.i64_clz); |
| 4324 | return self.wrapBinOp(tmp, .{ .imm64 = @bitCast(u64, val) }, ty, .add); | 4318 | try self.emitWValue(.{ .imm64 = 64 }); |
| 4325 | } | 4319 | try self.addTag(.i64_add); |
| | 4320 | try self.emitWValue(neq); |
| | 4321 | try self.addTag(.select); |
| | 4322 | try self.addTag(.i32_wrap_i64); |
| 4326 | }, | 4323 | }, |
| 4327 | else => unreachable, | 4324 | else => unreachable, |
| 4328 | } | 4325 | } |
| 4329 | | 4326 | |
| | 4327 | if (wasm_bits != int_info.bits) { |
| | 4328 | try self.emitWValue(.{ .imm32 = wasm_bits - int_info.bits }); |
| | 4329 | try self.addTag(.i32_sub); |
| | 4330 | } |
| | 4331 | |
| 4330 | const result = try self.allocLocal(result_ty); | 4332 | const result = try self.allocLocal(result_ty); |
| 4331 | try self.addLabel(.local_set, result.local); | 4333 | try self.addLabel(.local_set, result.local); |
| 4332 | return result; | 4334 | return result; |
| ... | @@ -4365,12 +4367,34 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4365,12 +4367,34 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4365 | } else try self.emitWValue(operand); | 4367 | } else try self.emitWValue(operand); |
| 4366 | try self.addTag(.i64_ctz); | 4368 | try self.addTag(.i64_ctz); |
| 4367 | }, | 4369 | }, |
| | 4370 | 128 => { |
| | 4371 | const msb = try self.load(operand, Type.u64, 0); |
| | 4372 | const lsb = try self.load(operand, Type.u64, 8); |
| | 4373 | const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); |
| | 4374 | |
| | 4375 | try self.emitWValue(msb); |
| | 4376 | try self.addTag(.i64_ctz); |
| | 4377 | try self.emitWValue(lsb); |
| | 4378 | if (wasm_bits != int_info.bits) { |
| | 4379 | try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64)); |
| | 4380 | try self.addTag(.i64_or); |
| | 4381 | } |
| | 4382 | try self.addTag(.i64_ctz); |
| | 4383 | try self.addImm64(64); |
| | 4384 | if (wasm_bits != int_info.bits) { |
| | 4385 | try self.addTag(.i64_or); |
| | 4386 | } else { |
| | 4387 | try self.addTag(.i64_add); |
| | 4388 | } |
| | 4389 | try self.emitWValue(neq); |
| | 4390 | try self.addTag(.select); |
| | 4391 | }, |
| 4368 | else => unreachable, | 4392 | else => unreachable, |
| 4369 | } | 4393 | } |
| 4370 | | 4394 | |
| 4371 | const result = try self.allocLocal(result_ty); | 4395 | const result = try self.allocLocal(ty); |
| 4372 | try self.addLabel(.local_set, result.local); | 4396 | try self.addLabel(.local_set, result.local); |
| 4373 | return result; | 4397 | return self.intcast(result, ty, result_ty); |
| 4374 | } | 4398 | } |
| 4375 | | 4399 | |
| 4376 | fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !WValue { | 4400 | fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !WValue { |