| ... | @@ -2334,18 +2334,28 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2334,18 +2334,28 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2334 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | 2334 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| 2335 | } | 2335 | } |
| 2336 | | 2336 | |
| 2337 | fn isNull(self: *Self, operand: MCValue) !MCValue { | 2337 | fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2338 | _ = operand; | 2338 | if (ty.isPtrLikeOptional()) { |
| 2339 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2339 | assert(ty.abiSize(self.target.*) == 4); |
| 2340 | // will call isNonNull and invert the result. | 2340 | |
| 2341 | return self.fail("TODO call isNonNull and invert the result", .{}); | 2341 | const reg_mcv: MCValue = switch (operand) { |
| | 2342 | .register => operand, |
| | 2343 | else => .{ .register = try self.copyToTmpRegister(ty, operand) }, |
| | 2344 | }; |
| | 2345 | |
| | 2346 | try self.genArmBinOpCode(undefined, reg_mcv, .{ .immediate = 0 }, false, .cmp_eq, undefined); |
| | 2347 | |
| | 2348 | return MCValue{ .compare_flags_unsigned = .eq }; |
| | 2349 | } else { |
| | 2350 | return self.fail("TODO implement non-pointer optionals", .{}); |
| | 2351 | } |
| 2342 | } | 2352 | } |
| 2343 | | 2353 | |
| 2344 | fn isNonNull(self: *Self, operand: MCValue) !MCValue { | 2354 | fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2345 | _ = operand; | 2355 | const is_null_result = try self.isNull(ty, operand); |
| 2346 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2356 | assert(is_null_result.compare_flags_unsigned == .eq); |
| 2347 | // will call isNull and invert the result. | 2357 | |
| 2348 | return self.fail("TODO call isNull and invert the result", .{}); | 2358 | return MCValue{ .compare_flags_unsigned = .neq }; |
| 2349 | } | 2359 | } |
| 2350 | | 2360 | |
| 2351 | fn isErr(self: *Self, operand: MCValue) !MCValue { | 2361 | fn isErr(self: *Self, operand: MCValue) !MCValue { |
| ... | @@ -2364,9 +2374,14 @@ fn isNonErr(self: *Self, operand: MCValue) !MCValue { | ... | @@ -2364,9 +2374,14 @@ fn isNonErr(self: *Self, operand: MCValue) !MCValue { |
| 2364 | | 2374 | |
| 2365 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | 2375 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 2366 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2376 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 2377 | |
| | 2378 | try self.spillCompareFlagsIfOccupied(); |
| | 2379 | self.compare_flags_inst = inst; |
| | 2380 | |
| 2367 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2381 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2368 | const operand = try self.resolveInst(un_op); | 2382 | const operand = try self.resolveInst(un_op); |
| 2369 | break :result try self.isNull(operand); | 2383 | const ty = self.air.typeOf(un_op); |
| | 2384 | break :result try self.isNull(ty, operand); |
| 2370 | }; | 2385 | }; |
| 2371 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2386 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2372 | } | 2387 | } |
| ... | @@ -2375,6 +2390,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2375,6 +2390,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2375 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2390 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2376 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2391 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2377 | const operand_ptr = try self.resolveInst(un_op); | 2392 | const operand_ptr = try self.resolveInst(un_op); |
| | 2393 | const ptr_ty = self.air.typeOf(un_op); |
| 2378 | const operand: MCValue = blk: { | 2394 | const operand: MCValue = blk: { |
| 2379 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2395 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2380 | // The MCValue that holds the pointer can be re-used as the value. | 2396 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2383,8 +2399,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2383,8 +2399,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2383 | break :blk try self.allocRegOrMem(inst, true); | 2399 | break :blk try self.allocRegOrMem(inst, true); |
| 2384 | } | 2400 | } |
| 2385 | }; | 2401 | }; |
| 2386 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2402 | try self.load(operand, operand_ptr, ptr_ty); |
| 2387 | break :result try self.isNull(operand); | 2403 | break :result try self.isNull(ptr_ty.elemType(), operand); |
| 2388 | }; | 2404 | }; |
| 2389 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2405 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2390 | } | 2406 | } |
| ... | @@ -2393,7 +2409,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2393,7 +2409,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 2393 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2409 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2394 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2410 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2395 | const operand = try self.resolveInst(un_op); | 2411 | const operand = try self.resolveInst(un_op); |
| 2396 | break :result try self.isNonNull(operand); | 2412 | const ty = self.air.typeOf(un_op); |
| | 2413 | break :result try self.isNonNull(ty, operand); |
| 2397 | }; | 2414 | }; |
| 2398 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2415 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2399 | } | 2416 | } |
| ... | @@ -2402,6 +2419,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2402,6 +2419,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2402 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2419 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2403 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2420 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2404 | const operand_ptr = try self.resolveInst(un_op); | 2421 | const operand_ptr = try self.resolveInst(un_op); |
| | 2422 | const ptr_ty = self.air.typeOf(un_op); |
| 2405 | const operand: MCValue = blk: { | 2423 | const operand: MCValue = blk: { |
| 2406 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2424 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2407 | // The MCValue that holds the pointer can be re-used as the value. | 2425 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2410,8 +2428,8 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2410,8 +2428,8 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2410 | break :blk try self.allocRegOrMem(inst, true); | 2428 | break :blk try self.allocRegOrMem(inst, true); |
| 2411 | } | 2429 | } |
| 2412 | }; | 2430 | }; |
| 2413 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2431 | try self.load(operand, operand_ptr, ptr_ty); |
| 2414 | break :result try self.isNonNull(operand); | 2432 | break :result try self.isNonNull(ptr_ty.elemType(), operand); |
| 2415 | }; | 2433 | }; |
| 2416 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2434 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2417 | } | 2435 | } |