Commit 23150de9c4

Koakuma <koachan@protonmail.com>
2022-06-01 14:13:43
stage2: sparc64: Implement airNot
1 parent 9ad74b6
Changed files (3)
src/arch/sparc64/CodeGen.zig
@@ -586,7 +586,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .is_err_ptr      => @panic("TODO try self.airIsErrPtr(inst)"),
             .load            => try self.airLoad(inst),
             .loop            => try self.airLoop(inst),
-            .not             => @panic("TODO try self.airNot(inst)"),
+            .not             => try self.airNot(inst),
             .ptrtoint        => @panic("TODO try self.airPtrToInt(inst)"),
             .ret             => try self.airRet(inst),
             .ret_load        => try self.airRetLoad(inst),
@@ -1507,6 +1507,126 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAirBookkeeping();
 }
 
+fn airNot(self: *Self, inst: Air.Inst.Index) !void {
+    const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+        const operand = try self.resolveInst(ty_op.operand);
+        const operand_ty = self.air.typeOf(ty_op.operand);
+        switch (operand) {
+            .dead => unreachable,
+            .unreach => unreachable,
+            .compare_flags_unsigned => |op| {
+                const r = MCValue{
+                    .compare_flags_unsigned = .{
+                        .cmp = switch (op.cmp) {
+                            .gte => .lt,
+                            .gt => .lte,
+                            .neq => .eq,
+                            .lt => .gte,
+                            .lte => .gt,
+                            .eq => .neq,
+                        },
+                        .ccr = op.ccr,
+                    },
+                };
+                break :result r;
+            },
+            .compare_flags_signed => |op| {
+                const r = MCValue{
+                    .compare_flags_signed = .{
+                        .cmp = switch (op.cmp) {
+                            .gte => .lt,
+                            .gt => .lte,
+                            .neq => .eq,
+                            .lt => .gte,
+                            .lte => .gt,
+                            .eq => .neq,
+                        },
+                        .ccr = op.ccr,
+                    },
+                };
+                break :result r;
+            },
+            else => {
+                switch (operand_ty.zigTypeTag()) {
+                    .Bool => {
+                        // TODO convert this to mvn + and
+                        const op_reg = switch (operand) {
+                            .register => |r| r,
+                            else => try self.copyToTmpRegister(operand_ty, operand),
+                        };
+                        const reg_lock = self.register_manager.lockRegAssumeUnused(op_reg);
+                        defer self.register_manager.unlockReg(reg_lock);
+
+                        const dest_reg = blk: {
+                            if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
+                                break :blk op_reg;
+                            }
+
+                            const reg = try self.register_manager.allocReg(null, gp);
+                            break :blk reg;
+                        };
+
+                        _ = try self.addInst(.{
+                            .tag = .xor,
+                            .data = .{
+                                .arithmetic_3op = .{
+                                    .is_imm = true,
+                                    .rd = dest_reg,
+                                    .rs1 = op_reg,
+                                    .rs2_or_imm = .{ .imm = 1 },
+                                },
+                            },
+                        });
+
+                        break :result MCValue{ .register = dest_reg };
+                    },
+                    .Vector => return self.fail("TODO bitwise not for vectors", .{}),
+                    .Int => {
+                        const int_info = operand_ty.intInfo(self.target.*);
+                        if (int_info.bits <= 64) {
+                            const op_reg = switch (operand) {
+                                .register => |r| r,
+                                else => try self.copyToTmpRegister(operand_ty, operand),
+                            };
+                            const reg_lock = self.register_manager.lockRegAssumeUnused(op_reg);
+                            defer self.register_manager.unlockReg(reg_lock);
+
+                            const dest_reg = blk: {
+                                if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
+                                    break :blk op_reg;
+                                }
+
+                                const reg = try self.register_manager.allocReg(null, gp);
+                                break :blk reg;
+                            };
+
+                            _ = try self.addInst(.{
+                                .tag = .not,
+                                .data = .{
+                                    .arithmetic_2op = .{
+                                        .is_imm = false,
+                                        .rs1 = dest_reg,
+                                        .rs2_or_imm = .{ .rs2 = op_reg },
+                                    },
+                                },
+                            });
+
+                            try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
+
+                            break :result MCValue{ .register = dest_reg };
+                        } else {
+                            return self.fail("TODO AArch64 not on integers > u64/i64", .{});
+                        }
+                    },
+                    else => unreachable,
+                }
+            },
+        }
+    };
+    return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
+}
+
 fn airRet(self: *Self, inst: Air.Inst.Index) !void {
     const un_op = self.air.instructions.items(.data)[inst].un_op;
     const operand = try self.resolveInst(un_op);
src/arch/sparc64/Emit.zig
@@ -94,6 +94,8 @@ pub fn emitMir(
             .ldx => try emit.mirArithmetic3Op(inst),
 
             .@"or" => try emit.mirArithmetic3Op(inst),
+            .xor => @panic("TODO implement sparc64 xor"),
+            .xnor => @panic("TODO implement sparc64 xnor"),
 
             .movcc => try emit.mirConditionalMove(inst),
 
@@ -128,6 +130,8 @@ pub fn emitMir(
             .cmp => try emit.mirArithmetic2Op(inst),
 
             .mov => try emit.mirArithmetic2Op(inst),
+
+            .not => @panic("TODO implement sparc64 not"),
         }
     }
 }
src/arch/sparc64/Mir.zig
@@ -74,6 +74,8 @@ pub const Inst = struct {
         /// This uses the arithmetic_3op field.
         // TODO add other operations.
         @"or",
+        xor,
+        xnor,
 
         /// A.35 Move Integer Register on Condition (MOVcc)
         /// This uses the conditional_move field.
@@ -147,6 +149,13 @@ pub const Inst = struct {
         /// being the *destination* register.
         // TODO is it okay to abuse rs1 in this way?
         mov, // mov rs2/imm, rs1 -> or %g0, rs2/imm, rs1
+
+        /// Bitwise negation
+        /// This uses the arithmetic_2op field, with rs1
+        /// being the *destination* register.
+        // TODO is it okay to abuse rs1 in this way?
+        // TODO this differs from official encoding for convenience, fix it later
+        not, // not rs2/imm, rs1 -> xnor %g0, rs2/imm, rs1
     };
 
     /// The position of an MIR instruction within the `Mir` instructions array.