| ... | ... | @@ -521,8 +521,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 521 | 521 | .sub_sat => try self.airSubSat(inst), |
| 522 | 522 | .mul_sat => try self.airMulSat(inst), |
| 523 | 523 | .shl_sat => try self.airShlSat(inst), |
| 524 | | .min => @panic("TODO try self.airMin(inst)"), |
| 525 | | .max => @panic("TODO try self.airMax(inst)"), |
| 524 | .min, .max => try self.airMinMax(inst), |
| 526 | 525 | .rem => try self.airRem(inst), |
| 527 | 526 | .mod => try self.airMod(inst), |
| 528 | 527 | .slice => try self.airSlice(inst), |
| ... | ... | @@ -1737,6 +1736,22 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void { |
| 1737 | 1736 | return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch}); |
| 1738 | 1737 | } |
| 1739 | 1738 | |
| 1739 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1740 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1741 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1742 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1743 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1744 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1745 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1746 | |
| 1747 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1748 | .dead |
| 1749 | else |
| 1750 | try self.minMax(tag, lhs, rhs, lhs_ty, rhs_ty); |
| 1751 | |
| 1752 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1753 | } |
| 1754 | |
| 1740 | 1755 | fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1741 | 1756 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1742 | 1757 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -4195,6 +4210,83 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne |
| 4195 | 4210 | } |
| 4196 | 4211 | } |
| 4197 | 4212 | |
| 4213 | fn minMax( |
| 4214 | self: *Self, |
| 4215 | tag: Air.Inst.Tag, |
| 4216 | lhs: MCValue, |
| 4217 | rhs: MCValue, |
| 4218 | lhs_ty: Type, |
| 4219 | rhs_ty: Type, |
| 4220 | ) InnerError!MCValue { |
| 4221 | const mod = self.bin_file.options.module.?; |
| 4222 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 4223 | switch (lhs_ty.zigTypeTag()) { |
| 4224 | .Float => return self.fail("TODO min/max on floats", .{}), |
| 4225 | .Vector => return self.fail("TODO min/max on vectors", .{}), |
| 4226 | .Int => { |
| 4227 | const int_info = lhs_ty.intInfo(self.target.*); |
| 4228 | if (int_info.bits <= 64) { |
| 4229 | // TODO skip register setting when one of the operands |
| 4230 | // is a small (fits in i13) immediate. |
| 4231 | const rhs_is_register = rhs == .register; |
| 4232 | const rhs_reg = if (rhs_is_register) |
| 4233 | rhs.register |
| 4234 | else |
| 4235 | try self.register_manager.allocReg(null, gp); |
| 4236 | const rhs_lock = self.register_manager.lockReg(rhs_reg); |
| 4237 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 4238 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| 4239 | |
| 4240 | const result_reg = try self.register_manager.allocReg(null, gp); |
| 4241 | const result_lock = self.register_manager.lockReg(result_reg); |
| 4242 | defer if (result_lock) |reg| self.register_manager.unlockReg(reg); |
| 4243 | try self.genSetReg(lhs_ty, result_reg, lhs); |
| 4244 | |
| 4245 | const cond_choose_rhs: Instruction.ICondition = switch (tag) { |
| 4246 | .max => switch (int_info.signedness) { |
| 4247 | .signed => Instruction.ICondition.gt, |
| 4248 | .unsigned => Instruction.ICondition.gu, |
| 4249 | }, |
| 4250 | .min => switch (int_info.signedness) { |
| 4251 | .signed => Instruction.ICondition.lt, |
| 4252 | .unsigned => Instruction.ICondition.cs, |
| 4253 | }, |
| 4254 | else => unreachable, |
| 4255 | }; |
| 4256 | |
| 4257 | _ = try self.addInst(.{ |
| 4258 | .tag = .cmp, |
| 4259 | .data = .{ |
| 4260 | .arithmetic_2op = .{ |
| 4261 | .is_imm = false, |
| 4262 | .rs1 = result_reg, |
| 4263 | .rs2_or_imm = .{ .rs2 = rhs_reg }, |
| 4264 | }, |
| 4265 | }, |
| 4266 | }); |
| 4267 | |
| 4268 | _ = try self.addInst(.{ |
| 4269 | .tag = .movcc, |
| 4270 | .data = .{ |
| 4271 | .conditional_move_int = .{ |
| 4272 | .is_imm = false, |
| 4273 | .ccr = .xcc, |
| 4274 | .cond = .{ .icond = cond_choose_rhs }, |
| 4275 | .rd = result_reg, |
| 4276 | .rs2_or_imm = .{ .rs2 = rhs_reg }, |
| 4277 | }, |
| 4278 | }, |
| 4279 | }); |
| 4280 | |
| 4281 | return MCValue{ .register = result_reg }; |
| 4282 | } else { |
| 4283 | return self.fail("TODO min/max on integers > u64/i64", .{}); |
| 4284 | } |
| 4285 | }, |
| 4286 | else => unreachable, |
| 4287 | } |
| 4288 | } |
| 4289 | |
| 4198 | 4290 | fn parseRegName(name: []const u8) ?Register { |
| 4199 | 4291 | if (@hasDecl(Register, "parseRegName")) { |
| 4200 | 4292 | return Register.parseRegName(name); |