mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
stage2: sparc64: Implement airNot
This commit is contained in:
parent
9ad74b6087
commit
23150de9c4
@ -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);
|
||||
|
||||
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user