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:...@@ -1821,11 +1821,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1821 const dst_ty = self.air.typeOfIndex(inst);1821 const dst_ty = self.air.typeOfIndex(inst);
1822 const air_tags = self.air.instructions.items(.tag);1822 const air_tags = self.air.instructions.items(.tag);
1823 switch (air_tags[inst]) {1823 switch (air_tags[inst]) {
1824 .add, .addwrap => try self.genBinMathOpMir(.add, 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, 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, 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, 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, dst_mcv, src_mcv),1828 .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, .unsigned, dst_mcv, src_mcv),
1829 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),1829 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
1830 else => unreachable,1830 else => unreachable,
1831 }1831 }
...@@ -1837,6 +1837,7 @@ fn genBinMathOpMir(...@@ -1837,6 +1837,7 @@ fn genBinMathOpMir(
1837 self: *Self,1837 self: *Self,
1838 mir_tag: Mir.Inst.Tag,1838 mir_tag: Mir.Inst.Tag,
1839 dst_ty: Type,1839 dst_ty: Type,
1840 signedness: std.builtin.Signedness,
1840 dst_mcv: MCValue,1841 dst_mcv: MCValue,
1841 src_mcv: MCValue,1842 src_mcv: MCValue,
1842) !void {1843) !void {
...@@ -1856,11 +1857,16 @@ fn genBinMathOpMir(...@@ -1856,11 +1857,16 @@ fn genBinMathOpMir(
1856 .ptr_stack_offset => unreachable,1857 .ptr_stack_offset => unreachable,
1857 .ptr_embedded_in_code => unreachable,1858 .ptr_embedded_in_code => unreachable,
1858 .register => |src_reg| {1859 .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);
1859 _ = try self.addInst(.{1865 _ = try self.addInst(.{
1860 .tag = mir_tag,1866 .tag = mir_tag,
1861 .ops = (Mir.Ops{1867 .ops = (Mir.Ops{
1862 .reg1 = registerAlias(dst_reg, @divExact(src_reg.size(), 8)),1868 .reg1 = registerAlias(dst_reg, reg_size),
1863 .reg2 = src_reg,1869 .reg2 = registerAlias(src_reg, reg_size),
1864 }).encode(),1870 }).encode(),
1865 .data = undefined,1871 .data = undefined,
1866 });1872 });
...@@ -2446,7 +2452,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2446,7 +2452,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2446 // This instruction supports only signed 32-bit immediates at most.2452 // This instruction supports only signed 32-bit immediates at most.
2447 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);2453 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);
2450 break :result switch (signedness) {2456 break :result switch (signedness) {
2451 .signed => MCValue{ .compare_flags_signed = op },2457 .signed => MCValue{ .compare_flags_signed = op },
2452 .unsigned => MCValue{ .compare_flags_unsigned = op },2458 .unsigned => MCValue{ .compare_flags_unsigned = op },
...@@ -2669,7 +2675,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2669,7 +2675,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2669}2675}
26702676
2671fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {2677fn 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 });
2673 return MCValue{ .compare_flags_unsigned = .eq };2679 return MCValue{ .compare_flags_unsigned = .eq };
2674}2680}
26752681
...@@ -2686,7 +2692,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2686,7 +2692,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2686 return MCValue{ .immediate = 0 }; // always false2692 return MCValue{ .immediate = 0 }; // always false
2687 } else if (!payload_type.hasCodeGenBits()) {2693 } else if (!payload_type.hasCodeGenBits()) {
2688 if (err_type.abiSize(self.target.*) <= 8) {2694 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 });
2690 return MCValue{ .compare_flags_unsigned = .gt };2696 return MCValue{ .compare_flags_unsigned = .gt };
2691 } else {2697 } else {
2692 return self.fail("TODO isErr for errors with size larger than register size", .{});2698 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...@@ -3378,7 +3384,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3378 else => unreachable,3384 else => unreachable,
3379 }3385 }
3380 },3386 },
3381 .compare_flags_unsigned => |op| {3387 .compare_flags_unsigned,
3388 .compare_flags_signed,
3389 => |op| {
3382 const tag: Mir.Inst.Tag = switch (op) {3390 const tag: Mir.Inst.Tag = switch (op) {
3383 .gte, .gt, .lt, .lte => .cond_set_byte_above_below,3391 .gte, .gt, .lt, .lte => .cond_set_byte_above_below,
3384 .eq, .neq => .cond_set_byte_eq_ne,3392 .eq, .neq => .cond_set_byte_eq_ne,
...@@ -3400,10 +3408,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3400,10 +3408,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3400 .data = undefined,3408 .data = undefined,
3401 });3409 });
3402 },3410 },
3403 .compare_flags_signed => |op| {
3404 _ = op;
3405 return self.fail("TODO set register with compare flags value (signed)", .{});
3406 },
3407 .immediate => |x| {3411 .immediate => |x| {
3408 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit3412 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
3409 // register is the fastest way to zero a register.3413 // 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...@@ -3441,7 +3445,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3441 _ = try self.addInst(.{3445 _ = try self.addInst(.{
3442 .tag = .movabs,3446 .tag = .movabs,
3443 .ops = (Mir.Ops{3447 .ops = (Mir.Ops{
3444 .reg1 = reg,3448 .reg1 = reg.to64(),
3445 }).encode(),3449 }).encode(),
3446 .data = .{ .payload = payload },3450 .data = .{ .payload = payload },
3447 });3451 });
src/arch/x86_64/Emit.zig-20
...@@ -492,20 +492,6 @@ inline fn immOpSize(u_imm: u32) u8 {...@@ -492,20 +492,6 @@ inline fn immOpSize(u_imm: u32) u8 {
492 return 32;492 return 32;
493}493}
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
509fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {495fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
510 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);496 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
511 const scale = ops.flags;497 const scale = ops.flags;
...@@ -1485,9 +1471,6 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),...@@ -1485,9 +1471,6 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),
1485 if (reg.lowId() != Register.rax.lowId()) {1471 if (reg.lowId() != Register.rax.lowId()) {
1486 return error.RaxOperandExpected;1472 return error.RaxOperandExpected;
1487 }1473 }
1488 if (reg.size() != imm64OpSize(moffs)) {
1489 return error.OperandSizeMismatch;
1490 }
1491 const opc = if (td)1474 const opc = if (td)
1492 getOpCode(tag, .td, reg.size() == 8).?1475 getOpCode(tag, .td, reg.size() == 8).?
1493 else1476 else
...@@ -1510,9 +1493,6 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),...@@ -1510,9 +1493,6 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),
1510}1493}
15111494
1512fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) LoweringError!void {1495fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) LoweringError!void {
1513 if (reg.size() != imm64OpSize(imm)) {
1514 return error.OperandSizeMismatch;
1515 }
1516 const opc = getOpCode(tag, .oi, reg.size() == 8).?;1496 const opc = getOpCode(tag, .oi, reg.size() == 8).?;
1517 const encoder = try Encoder.init(code, 10);1497 const encoder = try Encoder.init(code, 10);
1518 if (reg.size() == 16) {1498 if (reg.size() == 16) {
test/stage2/x86_64.zig+34
...@@ -1767,6 +1767,40 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1767,6 +1767,40 @@ pub fn addCases(ctx: *TestContext) !void {
1767 \\ if (!ok) unreachable;1767 \\ if (!ok) unreachable;
1768 \\}1768 \\}
1769 , "");1769 , "");
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 , "");
1770 }1804 }
17711805
1772 {1806 {