stage2: sparc64: Implement airNot

This commit is contained in:
Koakuma 2022-06-01 19:13:43 +07:00
parent 9ad74b6087
commit 23150de9c4
3 changed files with 134 additions and 1 deletions

View File

@ -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);

View File

@ -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"),
}
}
}

View File

@ -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.