authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-15 19:32:16+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-15 19:32:16+01:00
log3af4e28dda7e4537255516fd1d575c2a34d904e7
tree526e491b538bdbff894ae27050f01de8f23be2f8
parent6315bcb32aa48858c43373542d9c50a366913f7c

stage2: implement signed compare


3 files changed, 54 insertions(+), 36 deletions(-)

src/arch/x86_64/CodeGen.zig+20-16
......@@ -1821,11 +1821,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
18211821 const dst_ty = self.air.typeOfIndex(inst);
18221822 const air_tags = self.air.instructions.items(.tag);
18231823 switch (air_tags[inst]) {
1824 .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
1825 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
1826 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
1827 .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv),
1828 .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv),
1824 .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, .unsigned, dst_mcv, src_mcv),
1825 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, .unsigned, dst_mcv, src_mcv),
1826 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, .unsigned, dst_mcv, src_mcv),
1827 .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, .unsigned, dst_mcv, src_mcv),
1828 .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, .unsigned, dst_mcv, src_mcv),
18291829 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
18301830 else => unreachable,
18311831 }
......@@ -1837,6 +1837,7 @@ fn genBinMathOpMir(
18371837 self: *Self,
18381838 mir_tag: Mir.Inst.Tag,
18391839 dst_ty: Type,
1840 signedness: std.builtin.Signedness,
18401841 dst_mcv: MCValue,
18411842 src_mcv: MCValue,
18421843) !void {
......@@ -1856,11 +1857,16 @@ fn genBinMathOpMir(
18561857 .ptr_stack_offset => unreachable,
18571858 .ptr_embedded_in_code => unreachable,
18581859 .register => |src_reg| {
1860 // TODO think more carefully about this: is this actually correct?
1861 const reg_size = if (mir_tag == .cmp and signedness == .signed)
1862 @divExact(dst_reg.size(), 8)
1863 else
1864 @divExact(src_reg.size(), 8);
18591865 _ = try self.addInst(.{
18601866 .tag = mir_tag,
18611867 .ops = (Mir.Ops{
1862 .reg1 = registerAlias(dst_reg, @divExact(src_reg.size(), 8)),
1863 .reg2 = src_reg,
1868 .reg1 = registerAlias(dst_reg, reg_size),
1869 .reg2 = registerAlias(src_reg, reg_size),
18641870 }).encode(),
18651871 .data = undefined,
18661872 });
......@@ -2446,7 +2452,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
24462452 // This instruction supports only signed 32-bit immediates at most.
24472453 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
24482454
2449 try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv);
2455 try self.genBinMathOpMir(.cmp, ty, signedness, dst_mcv, src_mcv);
24502456 break :result switch (signedness) {
24512457 .signed => MCValue{ .compare_flags_signed = op },
24522458 .unsigned => MCValue{ .compare_flags_unsigned = op },
......@@ -2669,7 +2675,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
26692675}
26702676
26712677fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
2672 try self.genBinMathOpMir(.cmp, ty, operand, MCValue{ .immediate = 0 });
2678 try self.genBinMathOpMir(.cmp, ty, .unsigned, operand, MCValue{ .immediate = 0 });
26732679 return MCValue{ .compare_flags_unsigned = .eq };
26742680}
26752681
......@@ -2686,7 +2692,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
26862692 return MCValue{ .immediate = 0 }; // always false
26872693 } else if (!payload_type.hasCodeGenBits()) {
26882694 if (err_type.abiSize(self.target.*) <= 8) {
2689 try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
2695 try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });
26902696 return MCValue{ .compare_flags_unsigned = .gt };
26912697 } else {
26922698 return self.fail("TODO isErr for errors with size larger than register size", .{});
......@@ -3378,7 +3384,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
33783384 else => unreachable,
33793385 }
33803386 },
3381 .compare_flags_unsigned => |op| {
3387 .compare_flags_unsigned,
3388 .compare_flags_signed,
3389 => |op| {
33823390 const tag: Mir.Inst.Tag = switch (op) {
33833391 .gte, .gt, .lt, .lte => .cond_set_byte_above_below,
33843392 .eq, .neq => .cond_set_byte_eq_ne,
......@@ -3400,10 +3408,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
34003408 .data = undefined,
34013409 });
34023410 },
3403 .compare_flags_signed => |op| {
3404 _ = op;
3405 return self.fail("TODO set register with compare flags value (signed)", .{});
3406 },
34073411 .immediate => |x| {
34083412 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
34093413 // register is the fastest way to zero a register.
......@@ -3441,7 +3445,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
34413445 _ = try self.addInst(.{
34423446 .tag = .movabs,
34433447 .ops = (Mir.Ops{
3444 .reg1 = reg,
3448 .reg1 = reg.to64(),
34453449 }).encode(),
34463450 .data = .{ .payload = payload },
34473451 });
src/arch/x86_64/Emit.zig-20
......@@ -492,20 +492,6 @@ inline fn immOpSize(u_imm: u32) u8 {
492492 return 32;
493493}
494494
495inline fn imm64OpSize(u_imm: u64) u8 {
496 const imm = @bitCast(i64, u_imm);
497 if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
498 return 8;
499 }
500 if (math.minInt(i16) <= imm and imm <= math.maxInt(i16)) {
501 return 16;
502 }
503 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
504 return 32;
505 }
506 return 64;
507}
508
509495fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
510496 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
511497 const scale = ops.flags;
......@@ -1485,9 +1471,6 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),
14851471 if (reg.lowId() != Register.rax.lowId()) {
14861472 return error.RaxOperandExpected;
14871473 }
1488 if (reg.size() != imm64OpSize(moffs)) {
1489 return error.OperandSizeMismatch;
1490 }
14911474 const opc = if (td)
14921475 getOpCode(tag, .td, reg.size() == 8).?
14931476 else
......@@ -1510,9 +1493,6 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),
15101493}
15111494
15121495fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) LoweringError!void {
1513 if (reg.size() != imm64OpSize(imm)) {
1514 return error.OperandSizeMismatch;
1515 }
15161496 const opc = getOpCode(tag, .oi, reg.size() == 8).?;
15171497 const encoder = try Encoder.init(code, 10);
15181498 if (reg.size() == 16) {
test/stage2/x86_64.zig+34
......@@ -1767,6 +1767,40 @@ pub fn addCases(ctx: *TestContext) !void {
17671767 \\ if (!ok) unreachable;
17681768 \\}
17691769 , "");
1770 case.addCompareOutput(
1771 \\pub fn main() void {
1772 \\ var x: u8 = undefined;
1773 \\ const maybe_x = byPtr(&x);
1774 \\ assert(maybe_x != null);
1775 \\ maybe_x.?.* = 255;
1776 \\ assert(x == 255);
1777 \\}
1778 \\
1779 \\fn byPtr(x: *u8) ?*u8 {
1780 \\ return x;
1781 \\}
1782 \\
1783 \\fn assert(ok: bool) void {
1784 \\ if (!ok) unreachable;
1785 \\}
1786 , "");
1787 case.addCompareOutput(
1788 \\pub fn main() void {
1789 \\ var x: i8 = undefined;
1790 \\ const maybe_x = byPtr(&x);
1791 \\ assert(maybe_x != null);
1792 \\ maybe_x.?.* = -1;
1793 \\ assert(x == -1);
1794 \\}
1795 \\
1796 \\fn byPtr(x: *i8) ?*i8 {
1797 \\ return x;
1798 \\}
1799 \\
1800 \\fn assert(ok: bool) void {
1801 \\ if (!ok) unreachable;
1802 \\}
1803 , "");
17701804 }
17711805
17721806 {