authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-12-21 18:50:01+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-12-21 23:13:30+01:00
logedcebe701339453bf49379d865a8049c5b22a49e
tree87206ce289098b1cbad17f42101e3fdd6b731b95
parent8b6ea9ffe78480f9c73e9dee24edc5975c7f064e
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: implement is_null and is_non_null for ptr-like optionals


2 files changed, 54 insertions(+), 16 deletions(-)

src/arch/arm/CodeGen.zig+34-16
...@@ -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}
23362336
2337fn isNull(self: *Self, operand: MCValue) !MCValue {2337fn 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 default2339 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}
23432353
2344fn isNonNull(self: *Self, operand: MCValue) !MCValue {2354fn 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 default2356 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}
23502360
2351fn isErr(self: *Self, operand: MCValue) !MCValue {2361fn 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 {
23642374
2365fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {2375fn 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}
test/stage2/arm.zig+20
...@@ -568,4 +568,24 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -568,4 +568,24 @@ pub fn addCases(ctx: *TestContext) !void {
568 "",568 "",
569 );569 );
570 }570 }
571
572 {
573 var case = ctx.exe("optionals", linux_arm);
574 case.addCompareOutput(
575 \\var x: u32 = 42;
576 \\
577 \\pub fn main() void {
578 \\ var p: ?*u32 = null;
579 \\ assert(p == null);
580 \\ p = &x;
581 \\ assert(p != null);
582 \\}
583 \\
584 \\fn assert(ok: bool) void {
585 \\ if (!ok) unreachable;
586 \\}
587 ,
588 "",
589 );
590 }
571}591}