| ... | @@ -2371,31 +2371,30 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2371,31 +2371,30 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2371 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); | 2371 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); |
| 2372 | } | 2372 | } |
| 2373 | | 2373 | |
| 2374 | fn isNull(self: *Self, operand: MCValue) !MCValue { | 2374 | fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2375 | _ = operand; | 2375 | try self.genBinMathOpMir(.cmp, ty, operand, MCValue{ .immediate = 0 }); |
| 2376 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2376 | return MCValue{ .compare_flags_unsigned = .eq }; |
| 2377 | // will call isNonNull and invert the result. | | |
| 2378 | return self.fail("TODO call isNonNull and invert the result", .{}); | | |
| 2379 | } | 2377 | } |
| 2380 | | 2378 | |
| 2381 | fn isNonNull(self: *Self, operand: MCValue) !MCValue { | 2379 | fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2382 | _ = operand; | 2380 | const is_null_res = try self.isNull(ty, operand); |
| 2383 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2381 | assert(is_null_res.compare_flags_unsigned == .eq); |
| 2384 | // will call isNull and invert the result. | 2382 | return MCValue{ .compare_flags_unsigned = .neq }; |
| 2385 | return self.fail("TODO call isNull and invert the result", .{}); | | |
| 2386 | } | 2383 | } |
| 2387 | | 2384 | |
| 2388 | fn isErr(self: *Self, operand: MCValue) !MCValue { | 2385 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| | 2386 | _ = ty; |
| 2389 | _ = operand; | 2387 | _ = operand; |
| 2390 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2388 | // Here you can specialize this instruction if it makes sense to, otherwise the default |
| 2391 | // will call isNonNull and invert the result. | 2389 | // will call isNonErr and invert the result. |
| 2392 | return self.fail("TODO call isNonErr and invert the result", .{}); | 2390 | return self.fail("TODO call isNonErr and invert the result", .{}); |
| 2393 | } | 2391 | } |
| 2394 | | 2392 | |
| 2395 | fn isNonErr(self: *Self, operand: MCValue) !MCValue { | 2393 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| | 2394 | _ = ty; |
| 2396 | _ = operand; | 2395 | _ = operand; |
| 2397 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2396 | // Here you can specialize this instruction if it makes sense to, otherwise the default |
| 2398 | // will call isNull and invert the result. | 2397 | // will call isErr and invert the result. |
| 2399 | return self.fail("TODO call isErr and invert the result", .{}); | 2398 | return self.fail("TODO call isErr and invert the result", .{}); |
| 2400 | } | 2399 | } |
| 2401 | | 2400 | |
| ... | @@ -2403,7 +2402,8 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2403,7 +2402,8 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 2403 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2402 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2404 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2403 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2405 | const operand = try self.resolveInst(un_op); | 2404 | const operand = try self.resolveInst(un_op); |
| 2406 | break :result try self.isNull(operand); | 2405 | const ty = self.air.typeOf(un_op); |
| | 2406 | break :result try self.isNull(ty, operand); |
| 2407 | }; | 2407 | }; |
| 2408 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2408 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2409 | } | 2409 | } |
| ... | @@ -2420,8 +2420,9 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2420,8 +2420,9 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2420 | break :blk try self.allocRegOrMem(inst, true); | 2420 | break :blk try self.allocRegOrMem(inst, true); |
| 2421 | } | 2421 | } |
| 2422 | }; | 2422 | }; |
| 2423 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2423 | const ptr_ty = self.air.typeOf(un_op); |
| 2424 | break :result try self.isNull(operand); | 2424 | try self.load(operand, operand_ptr, ptr_ty); |
| | 2425 | break :result try self.isNull(ptr_ty.elemType(), operand); |
| 2425 | }; | 2426 | }; |
| 2426 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2427 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2427 | } | 2428 | } |
| ... | @@ -2430,7 +2431,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2430,7 +2431,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 2430 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2431 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2431 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2432 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2432 | const operand = try self.resolveInst(un_op); | 2433 | const operand = try self.resolveInst(un_op); |
| 2433 | break :result try self.isNonNull(operand); | 2434 | const ty = self.air.typeOf(un_op); |
| | 2435 | break :result try self.isNonNull(ty, operand); |
| 2434 | }; | 2436 | }; |
| 2435 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2437 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2436 | } | 2438 | } |
| ... | @@ -2447,8 +2449,9 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2447,8 +2449,9 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2447 | break :blk try self.allocRegOrMem(inst, true); | 2449 | break :blk try self.allocRegOrMem(inst, true); |
| 2448 | } | 2450 | } |
| 2449 | }; | 2451 | }; |
| 2450 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2452 | const ptr_ty = self.air.typeOf(un_op); |
| 2451 | break :result try self.isNonNull(operand); | 2453 | try self.load(operand, operand_ptr, ptr_ty); |
| | 2454 | break :result try self.isNonNull(ptr_ty.elemType(), operand); |
| 2452 | }; | 2455 | }; |
| 2453 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2456 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2454 | } | 2457 | } |
| ... | @@ -2457,7 +2460,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2457,7 +2460,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2457 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2460 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2458 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2461 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2459 | const operand = try self.resolveInst(un_op); | 2462 | const operand = try self.resolveInst(un_op); |
| 2460 | break :result try self.isErr(operand); | 2463 | const ty = self.air.typeOf(un_op); |
| | 2464 | break :result try self.isErr(ty, operand); |
| 2461 | }; | 2465 | }; |
| 2462 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2466 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2463 | } | 2467 | } |
| ... | @@ -2474,8 +2478,9 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2474,8 +2478,9 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2474 | break :blk try self.allocRegOrMem(inst, true); | 2478 | break :blk try self.allocRegOrMem(inst, true); |
| 2475 | } | 2479 | } |
| 2476 | }; | 2480 | }; |
| 2477 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2481 | const ptr_ty = self.air.typeOf(un_op); |
| 2478 | break :result try self.isErr(operand); | 2482 | try self.load(operand, operand_ptr, ptr_ty); |
| | 2483 | break :result try self.isErr(ptr_ty.elemType(), operand); |
| 2479 | }; | 2484 | }; |
| 2480 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2485 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2481 | } | 2486 | } |
| ... | @@ -2484,7 +2489,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2484,7 +2489,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2484 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2489 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2485 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2490 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2486 | const operand = try self.resolveInst(un_op); | 2491 | const operand = try self.resolveInst(un_op); |
| 2487 | break :result try self.isNonErr(operand); | 2492 | const ty = self.air.typeOf(un_op); |
| | 2493 | break :result try self.isNonErr(ty, operand); |
| 2488 | }; | 2494 | }; |
| 2489 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2495 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2490 | } | 2496 | } |
| ... | @@ -2501,8 +2507,9 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2501,8 +2507,9 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2501 | break :blk try self.allocRegOrMem(inst, true); | 2507 | break :blk try self.allocRegOrMem(inst, true); |
| 2502 | } | 2508 | } |
| 2503 | }; | 2509 | }; |
| 2504 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2510 | const ptr_ty = self.air.typeOf(un_op); |
| 2505 | break :result try self.isNonErr(operand); | 2511 | try self.load(operand, operand_ptr, ptr_ty); |
| | 2512 | break :result try self.isNonErr(ptr_ty.elemType(), operand); |
| 2506 | }; | 2513 | }; |
| 2507 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2514 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2508 | } | 2515 | } |