authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2020-12-28 21:09:48+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-01-01 12:22:16+01:00
logc52ca0b1780c2865cb0c242cb2f1a397766e6ce8
tree2bb0956888cd3f1e9e08c9d49e0e6f3d53203ba2
parent85e1b47c40c023d8a3d75fadaeeb643a361bbc4d
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: implement genSetReg with compare_flags


2 files changed, 88 insertions(+), 19 deletions(-)

src/codegen.zig+22-19
......@@ -658,6 +658,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
658658
659659 const mcv = try self.genFuncInst(inst);
660660 if (!inst.isUnused()) {
661 log.debug("{*} => {}", .{ inst, mcv });
661662 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
662663 try branch.inst_table.putNoClobber(self.gpa, inst, mcv);
663664 }
......@@ -2039,27 +2040,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20392040 const condition: Condition = switch (cond) {
20402041 .compare_flags_signed => |cmp_op| blk: {
20412042 // Here we map to the opposite condition because the jump is to the false branch.
2042 const condition: Condition = switch (cmp_op) {
2043 .gte => .lt,
2044 .gt => .le,
2045 .neq => .eq,
2046 .lt => .ge,
2047 .lte => .gt,
2048 .eq => .ne,
2049 };
2050 break :blk condition;
2043 const condition = Condition.fromCompareOperatorSigned(cmp_op);
2044 break :blk condition.negate();
20512045 },
20522046 .compare_flags_unsigned => |cmp_op| blk: {
20532047 // Here we map to the opposite condition because the jump is to the false branch.
2054 const condition: Condition = switch (cmp_op) {
2055 .gte => .cc,
2056 .gt => .ls,
2057 .neq => .eq,
2058 .lt => .cs,
2059 .lte => .hi,
2060 .eq => .ne,
2061 };
2062 break :blk condition;
2048 const condition = Condition.fromCompareOperatorUnsigned(cmp_op);
2049 break :blk condition.negate();
20632050 },
20642051 .register => |reg| blk: {
20652052 // cmp reg, 1
......@@ -2239,7 +2226,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22392226 }
22402227 },
22412228 .arm, .armeb => {
2242 if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len))) |delta| {
2229 if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len + 8))) |delta| {
22432230 writeInt(u32, try self.code.addManyAsArray(4), Instruction.b(.al, delta).toU32());
22442231 } else |err| {
22452232 return self.fail(src, "TODO: enable larger branch offset", .{});
......@@ -2736,6 +2723,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27362723 // Write the debug undefined value.
27372724 return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa });
27382725 },
2726 .compare_flags_unsigned,
2727 .compare_flags_signed,
2728 => |op| {
2729 const condition = switch (mcv) {
2730 .compare_flags_unsigned => Condition.fromCompareOperatorUnsigned(op),
2731 .compare_flags_signed => Condition.fromCompareOperatorSigned(op),
2732 else => unreachable,
2733 };
2734
2735 // mov reg, 0
2736 // moveq reg, 1
2737 const zero = Instruction.Operand.imm(0, 0);
2738 const one = Instruction.Operand.imm(1, 0);
2739 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, zero).toU32());
2740 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(condition, reg, one).toU32());
2741 },
27392742 .immediate => |x| {
27402743 if (x > math.maxInt(u32)) return self.fail(src, "ARM registers are 32-bit wide", .{});
27412744
src/codegen/arm.zig+66
......@@ -35,8 +35,74 @@ pub const Condition = enum(u4) {
3535 le,
3636 /// always
3737 al,
38
39 /// Converts a std.math.CompareOperator into a condition flag,
40 /// i.e. returns the condition that is true iff the result of the
41 /// comparison is true. Assumes signed comparison
42 pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
43 return switch (op) {
44 .gte => .ge,
45 .gt => .gt,
46 .neq => .ne,
47 .lt => .lt,
48 .lte => .le,
49 .eq => .eq,
50 };
51 }
52
53 /// Converts a std.math.CompareOperator into a condition flag,
54 /// i.e. returns the condition that is true iff the result of the
55 /// comparison is true. Assumes unsigned comparison
56 pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
57 return switch (op) {
58 .gte => .cs,
59 .gt => .hi,
60 .neq => .ne,
61 .lt => .cc,
62 .lte => .ls,
63 .eq => .eq,
64 };
65 }
66
67 /// Returns the condition which is true iff the given condition is
68 /// false (if such a condition exists)
69 pub fn negate(cond: Condition) Condition {
70 return switch (cond) {
71 .eq => .ne,
72 .ne => .eq,
73 .cs => .cc,
74 .cc => .cs,
75 .mi => .pl,
76 .pl => .mi,
77 .vs => .vc,
78 .vc => .vs,
79 .hi => .ls,
80 .ls => .hi,
81 .ge => .lt,
82 .lt => .ge,
83 .gt => .le,
84 .le => .gt,
85 .al => unreachable,
86 };
87 }
3888};
3989
90test "condition from CompareOperator" {
91 testing.expectEqual(@as(Condition, .eq), Condition.fromCompareOperatorSigned(.eq));
92 testing.expectEqual(@as(Condition, .eq), Condition.fromCompareOperatorUnsigned(.eq));
93
94 testing.expectEqual(@as(Condition, .gt), Condition.fromCompareOperatorSigned(.gt));
95 testing.expectEqual(@as(Condition, .hi), Condition.fromCompareOperatorUnsigned(.gt));
96
97 testing.expectEqual(@as(Condition, .le), Condition.fromCompareOperatorSigned(.lte));
98 testing.expectEqual(@as(Condition, .ls), Condition.fromCompareOperatorUnsigned(.lte));
99}
100
101test "negate condition" {
102 testing.expectEqual(@as(Condition, .eq), Condition.ne.negate());
103 testing.expectEqual(@as(Condition, .ne), Condition.eq.negate());
104}
105
40106/// Represents a register in the ARM instruction set architecture
41107pub const Register = enum(u5) {
42108 r0,