From 23150de9c41330351bc5f7b62418617d5714203d Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 1 Jun 2022 19:13:43 +0700 Subject: [PATCH] stage2: sparc64: Implement airNot --- src/arch/sparc64/CodeGen.zig | 122 ++++++++++++++++++++++++++++++++++- src/arch/sparc64/Emit.zig | 4 ++ src/arch/sparc64/Mir.zig | 9 +++ 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 5af1e856c8..8e1e3678a9 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/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); diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index 44c14752e4..2fcb593585 100644 --- a/src/arch/sparc64/Emit.zig +++ b/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"), } } } diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index 36849eb48a..14867dde30 100644 --- a/src/arch/sparc64/Mir.zig +++ b/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.