mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
stage2 AArch64: implement min/max
This commit is contained in:
parent
0d192ee9ef
commit
d2a5a36cab
@ -539,8 +539,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
|
||||
.ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
|
||||
|
||||
.min => try self.airMin(inst),
|
||||
.max => try self.airMax(inst),
|
||||
.min => try self.airMinMax(inst),
|
||||
.max => try self.airMinMax(inst),
|
||||
|
||||
.add_sat => try self.airAddSat(inst),
|
||||
.sub_sat => try self.airSubSat(inst),
|
||||
@ -1234,15 +1234,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airMin(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
fn minMax(
|
||||
self: *Self,
|
||||
tag: Air.Inst.Tag,
|
||||
lhs_bind: ReadArg.Bind,
|
||||
rhs_bind: ReadArg.Bind,
|
||||
lhs_ty: Type,
|
||||
rhs_ty: Type,
|
||||
maybe_inst: ?Air.Inst.Index,
|
||||
) !MCValue {
|
||||
switch (lhs_ty.zigTypeTag()) {
|
||||
.Float => return self.fail("TODO ARM min/max on floats", .{}),
|
||||
.Vector => return self.fail("TODO ARM min/max on vectors", .{}),
|
||||
.Int => {
|
||||
const mod = self.bin_file.options.module.?;
|
||||
assert(lhs_ty.eql(rhs_ty, mod));
|
||||
const int_info = lhs_ty.intInfo(self.target.*);
|
||||
if (int_info.bits <= 64) {
|
||||
var lhs_reg: Register = undefined;
|
||||
var rhs_reg: Register = undefined;
|
||||
var dest_reg: Register = undefined;
|
||||
|
||||
const read_args = [_]ReadArg{
|
||||
.{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
|
||||
.{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
|
||||
};
|
||||
const write_args = [_]WriteArg{
|
||||
.{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
|
||||
};
|
||||
try self.allocRegs(
|
||||
&read_args,
|
||||
&write_args,
|
||||
if (maybe_inst) |inst| .{
|
||||
.corresponding_inst = inst,
|
||||
.operand_mapping = &.{ 0, 1 },
|
||||
} else null,
|
||||
);
|
||||
|
||||
// lhs == reg should have been checked by airMinMax
|
||||
assert(lhs_reg != rhs_reg); // see note above
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = .cmp_shifted_register,
|
||||
.data = .{ .rr_imm6_shift = .{
|
||||
.rn = lhs_reg,
|
||||
.rm = rhs_reg,
|
||||
.imm6 = 0,
|
||||
.shift = .lsl,
|
||||
} },
|
||||
});
|
||||
|
||||
const cond_choose_lhs: Condition = switch (tag) {
|
||||
.max => switch (int_info.signedness) {
|
||||
.signed => Condition.gt,
|
||||
.unsigned => Condition.hi,
|
||||
},
|
||||
.min => switch (int_info.signedness) {
|
||||
.signed => Condition.lt,
|
||||
.unsigned => Condition.cc,
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = .csel,
|
||||
.data = .{ .rrr_cond = .{
|
||||
.rd = dest_reg,
|
||||
.rn = lhs_reg,
|
||||
.rm = rhs_reg,
|
||||
.cond = cond_choose_lhs,
|
||||
} },
|
||||
});
|
||||
|
||||
return MCValue{ .register = dest_reg };
|
||||
} else {
|
||||
return self.fail("TODO ARM min/max on integers > u32/i32", .{});
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn airMax(self: *Self, inst: Air.Inst.Index) !void {
|
||||
fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const tag = self.air.instructions.items(.tag)[inst];
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch});
|
||||
const lhs_ty = self.air.typeOf(bin_op.lhs);
|
||||
const rhs_ty = self.air.typeOf(bin_op.rhs);
|
||||
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
|
||||
const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
|
||||
const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
|
||||
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
if (bin_op.lhs == bin_op.rhs) break :result lhs;
|
||||
|
||||
break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
|
||||
};
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
|
||||
@ -131,6 +131,7 @@ pub fn emitMir(
|
||||
.subs_extended_register => try emit.mirAddSubtractExtendedRegister(inst),
|
||||
.cmp_extended_register => try emit.mirAddSubtractExtendedRegister(inst),
|
||||
|
||||
.csel => try emit.mirConditionalSelect(inst),
|
||||
.cset => try emit.mirConditionalSelect(inst),
|
||||
|
||||
.dbg_line => try emit.mirDbgLine(inst),
|
||||
@ -804,6 +805,14 @@ fn mirAddSubtractExtendedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
switch (tag) {
|
||||
.csel => {
|
||||
const rrr_cond = emit.mir.instructions.items(.data)[inst].rrr_cond;
|
||||
const rd = rrr_cond.rd;
|
||||
const rn = rrr_cond.rn;
|
||||
const rm = rrr_cond.rm;
|
||||
const cond = rrr_cond.cond;
|
||||
try emit.writeInstruction(Instruction.csel(rd, rn, rm, cond));
|
||||
},
|
||||
.cset => {
|
||||
const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;
|
||||
const zr: Register = switch (r_cond.rd.size()) {
|
||||
|
||||
@ -62,6 +62,8 @@ pub const Inst = struct {
|
||||
cmp_shifted_register,
|
||||
/// Compare (extended register)
|
||||
cmp_extended_register,
|
||||
/// Conditional Select
|
||||
csel,
|
||||
/// Conditional set
|
||||
cset,
|
||||
/// Pseudo-instruction: End of prologue
|
||||
@ -387,6 +389,15 @@ pub const Inst = struct {
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
},
|
||||
/// Three registers and a condition
|
||||
///
|
||||
/// Used by e.g. csel
|
||||
rrr_cond: struct {
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
cond: bits.Instruction.Condition,
|
||||
},
|
||||
/// Three registers and a shift (shift type and 6-bit amount)
|
||||
///
|
||||
/// Used by e.g. add_shifted_register
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user