stage2 AArch64: implement min/max

This commit is contained in:
joachimschmidt557 2022-10-23 16:18:10 +02:00
parent 0d192ee9ef
commit d2a5a36cab
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
3 changed files with 115 additions and 8 deletions

View File

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

View File

@ -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()) {

View File

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