Commit c52ca0b178

joachimschmidt557 <joachim.schmidt557@outlook.com>
2020-12-28 21:09:48
stage2 ARM: implement genSetReg with compare_flags
1 parent 85e1b47
Changed files (2)
src
src/codegen/arm.zig
@@ -35,8 +35,74 @@ pub const Condition = enum(u4) {
     le,
     /// always
     al,
+
+    /// Converts a std.math.CompareOperator into a condition flag,
+    /// i.e. returns the condition that is true iff the result of the
+    /// comparison is true. Assumes signed comparison
+    pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
+        return switch (op) {
+            .gte => .ge,
+            .gt => .gt,
+            .neq => .ne,
+            .lt => .lt,
+            .lte => .le,
+            .eq => .eq,
+        };
+    }
+
+    /// Converts a std.math.CompareOperator into a condition flag,
+    /// i.e. returns the condition that is true iff the result of the
+    /// comparison is true. Assumes unsigned comparison
+    pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
+        return switch (op) {
+            .gte => .cs,
+            .gt => .hi,
+            .neq => .ne,
+            .lt => .cc,
+            .lte => .ls,
+            .eq => .eq,
+        };
+    }
+
+    /// Returns the condition which is true iff the given condition is
+    /// false (if such a condition exists)
+    pub fn negate(cond: Condition) Condition {
+        return switch (cond) {
+            .eq => .ne,
+            .ne => .eq,
+            .cs => .cc,
+            .cc => .cs,
+            .mi => .pl,
+            .pl => .mi,
+            .vs => .vc,
+            .vc => .vs,
+            .hi => .ls,
+            .ls => .hi,
+            .ge => .lt,
+            .lt => .ge,
+            .gt => .le,
+            .le => .gt,
+            .al => unreachable,
+        };
+    }
 };
 
+test "condition from CompareOperator" {
+    testing.expectEqual(@as(Condition, .eq), Condition.fromCompareOperatorSigned(.eq));
+    testing.expectEqual(@as(Condition, .eq), Condition.fromCompareOperatorUnsigned(.eq));
+
+    testing.expectEqual(@as(Condition, .gt), Condition.fromCompareOperatorSigned(.gt));
+    testing.expectEqual(@as(Condition, .hi), Condition.fromCompareOperatorUnsigned(.gt));
+
+    testing.expectEqual(@as(Condition, .le), Condition.fromCompareOperatorSigned(.lte));
+    testing.expectEqual(@as(Condition, .ls), Condition.fromCompareOperatorUnsigned(.lte));
+}
+
+test "negate condition" {
+    testing.expectEqual(@as(Condition, .eq), Condition.ne.negate());
+    testing.expectEqual(@as(Condition, .ne), Condition.eq.negate());
+}
+
 /// Represents a register in the ARM instruction set architecture
 pub const Register = enum(u5) {
     r0,
src/codegen.zig
@@ -658,6 +658,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
 
                 const mcv = try self.genFuncInst(inst);
                 if (!inst.isUnused()) {
+                    log.debug("{*} => {}", .{ inst, mcv });
                     const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
                     try branch.inst_table.putNoClobber(self.gpa, inst, mcv);
                 }
@@ -2039,27 +2040,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                     const condition: Condition = switch (cond) {
                         .compare_flags_signed => |cmp_op| blk: {
                             // Here we map to the opposite condition because the jump is to the false branch.
-                            const condition: Condition = switch (cmp_op) {
-                                .gte => .lt,
-                                .gt => .le,
-                                .neq => .eq,
-                                .lt => .ge,
-                                .lte => .gt,
-                                .eq => .ne,
-                            };
-                            break :blk condition;
+                            const condition = Condition.fromCompareOperatorSigned(cmp_op);
+                            break :blk condition.negate();
                         },
                         .compare_flags_unsigned => |cmp_op| blk: {
                             // Here we map to the opposite condition because the jump is to the false branch.
-                            const condition: Condition = switch (cmp_op) {
-                                .gte => .cc,
-                                .gt => .ls,
-                                .neq => .eq,
-                                .lt => .cs,
-                                .lte => .hi,
-                                .eq => .ne,
-                            };
-                            break :blk condition;
+                            const condition = Condition.fromCompareOperatorUnsigned(cmp_op);
+                            break :blk condition.negate();
                         },
                         .register => |reg| blk: {
                             // cmp reg, 1
@@ -2239,7 +2226,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                     }
                 },
                 .arm, .armeb => {
-                    if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len))) |delta| {
+                    if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len + 8))) |delta| {
                         writeInt(u32, try self.code.addManyAsArray(4), Instruction.b(.al, delta).toU32());
                     } else |err| {
                         return self.fail(src, "TODO: enable larger branch offset", .{});
@@ -2736,6 +2723,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                         // Write the debug undefined value.
                         return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa });
                     },
+                    .compare_flags_unsigned,
+                    .compare_flags_signed,
+                    => |op| {
+                        const condition = switch (mcv) {
+                            .compare_flags_unsigned => Condition.fromCompareOperatorUnsigned(op),
+                            .compare_flags_signed => Condition.fromCompareOperatorSigned(op),
+                            else => unreachable,
+                        };
+
+                        // mov reg, 0
+                        // moveq reg, 1
+                        const zero = Instruction.Operand.imm(0, 0);
+                        const one = Instruction.Operand.imm(1, 0);
+                        writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, zero).toU32());
+                        writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(condition, reg, one).toU32());
+                    },
                     .immediate => |x| {
                         if (x > math.maxInt(u32)) return self.fail(src, "ARM registers are 32-bit wide", .{});