aboutsummaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorKoakuma <koachan@protonmail.com>2022-11-24 19:35:28 +0700
committerKoakuma <koachan@protonmail.com>2022-12-10 21:32:00 +0700
commit644593ab18a2150a5b412d586fde2fcfbb1461ea (patch)
tree5cd0bd25342bc345ea1c5f954659edf0e708e9a2 /src/arch
parentb4b7a404cfa0cfdc212fa66351789a199acb6e0c (diff)
downloadzig-644593ab18a2150a5b412d586fde2fcfbb1461ea.tar.gz
zig-644593ab18a2150a5b412d586fde2fcfbb1461ea.zip
stage2: sparc64: Implement airMinMax
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/sparc64/CodeGen.zig96
1 files changed, 94 insertions, 2 deletions
diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig
index 00e08a0964..604fd3e69f 100644
--- a/src/arch/sparc64/CodeGen.zig
+++ b/src/arch/sparc64/CodeGen.zig
@@ -521,8 +521,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.sub_sat => try self.airSubSat(inst),
.mul_sat => try self.airMulSat(inst),
.shl_sat => try self.airShlSat(inst),
- .min => @panic("TODO try self.airMin(inst)"),
- .max => @panic("TODO try self.airMax(inst)"),
+ .min, .max => try self.airMinMax(inst),
.rem => try self.airRem(inst),
.mod => try self.airMod(inst),
.slice => try self.airSlice(inst),
@@ -1737,6 +1736,22 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch});
}
+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 lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ 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
+ try self.minMax(tag, lhs, rhs, lhs_ty, rhs_ty);
+
+ return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
+}
+
fn airMod(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
@@ -4195,6 +4210,83 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
}
}
+fn minMax(
+ self: *Self,
+ tag: Air.Inst.Tag,
+ lhs: MCValue,
+ rhs: MCValue,
+ lhs_ty: Type,
+ rhs_ty: Type,
+) InnerError!MCValue {
+ const mod = self.bin_file.options.module.?;
+ assert(lhs_ty.eql(rhs_ty, mod));
+ switch (lhs_ty.zigTypeTag()) {
+ .Float => return self.fail("TODO min/max on floats", .{}),
+ .Vector => return self.fail("TODO min/max on vectors", .{}),
+ .Int => {
+ const int_info = lhs_ty.intInfo(self.target.*);
+ if (int_info.bits <= 64) {
+ // TODO skip register setting when one of the operands
+ // is a small (fits in i13) immediate.
+ const rhs_is_register = rhs == .register;
+ const rhs_reg = if (rhs_is_register)
+ rhs.register
+ else
+ try self.register_manager.allocReg(null, gp);
+ const rhs_lock = self.register_manager.lockReg(rhs_reg);
+ defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
+ if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
+
+ const result_reg = try self.register_manager.allocReg(null, gp);
+ const result_lock = self.register_manager.lockReg(result_reg);
+ defer if (result_lock) |reg| self.register_manager.unlockReg(reg);
+ try self.genSetReg(lhs_ty, result_reg, lhs);
+
+ const cond_choose_rhs: Instruction.ICondition = switch (tag) {
+ .max => switch (int_info.signedness) {
+ .signed => Instruction.ICondition.gt,
+ .unsigned => Instruction.ICondition.gu,
+ },
+ .min => switch (int_info.signedness) {
+ .signed => Instruction.ICondition.lt,
+ .unsigned => Instruction.ICondition.cs,
+ },
+ else => unreachable,
+ };
+
+ _ = try self.addInst(.{
+ .tag = .cmp,
+ .data = .{
+ .arithmetic_2op = .{
+ .is_imm = false,
+ .rs1 = result_reg,
+ .rs2_or_imm = .{ .rs2 = rhs_reg },
+ },
+ },
+ });
+
+ _ = try self.addInst(.{
+ .tag = .movcc,
+ .data = .{
+ .conditional_move_int = .{
+ .is_imm = false,
+ .ccr = .xcc,
+ .cond = .{ .icond = cond_choose_rhs },
+ .rd = result_reg,
+ .rs2_or_imm = .{ .rs2 = rhs_reg },
+ },
+ },
+ });
+
+ return MCValue{ .register = result_reg };
+ } else {
+ return self.fail("TODO min/max on integers > u64/i64", .{});
+ }
+ },
+ else => unreachable,
+ }
+}
+
fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name);