Commit d2a5a36cab
Changed files (3)
src
arch
aarch64
src/arch/aarch64/CodeGen.zig
@@ -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 });
}
src/arch/aarch64/Emit.zig
@@ -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()) {
src/arch/aarch64/Mir.zig
@@ -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