| ... | ... | @@ -539,8 +539,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 539 | 539 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), |
| 540 | 540 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), |
| 541 | 541 | |
| 542 | | .min => try self.airMin(inst), |
| 543 | | .max => try self.airMax(inst), |
| 542 | .min => try self.airMinMax(inst), |
| 543 | .max => try self.airMinMax(inst), |
| 544 | 544 | |
| 545 | 545 | .add_sat => try self.airAddSat(inst), |
| 546 | 546 | .sub_sat => try self.airSubSat(inst), |
| ... | ... | @@ -1234,15 +1234,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1234 | 1234 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1235 | 1235 | } |
| 1236 | 1236 | |
| 1237 | | fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1238 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1239 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch}); |
| 1240 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1237 | fn minMax( |
| 1238 | self: *Self, |
| 1239 | tag: Air.Inst.Tag, |
| 1240 | lhs_bind: ReadArg.Bind, |
| 1241 | rhs_bind: ReadArg.Bind, |
| 1242 | lhs_ty: Type, |
| 1243 | rhs_ty: Type, |
| 1244 | maybe_inst: ?Air.Inst.Index, |
| 1245 | ) !MCValue { |
| 1246 | switch (lhs_ty.zigTypeTag()) { |
| 1247 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| 1248 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), |
| 1249 | .Int => { |
| 1250 | const mod = self.bin_file.options.module.?; |
| 1251 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1252 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1253 | if (int_info.bits <= 64) { |
| 1254 | var lhs_reg: Register = undefined; |
| 1255 | var rhs_reg: Register = undefined; |
| 1256 | var dest_reg: Register = undefined; |
| 1257 | |
| 1258 | const read_args = [_]ReadArg{ |
| 1259 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 1260 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| 1261 | }; |
| 1262 | const write_args = [_]WriteArg{ |
| 1263 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1264 | }; |
| 1265 | try self.allocRegs( |
| 1266 | &read_args, |
| 1267 | &write_args, |
| 1268 | if (maybe_inst) |inst| .{ |
| 1269 | .corresponding_inst = inst, |
| 1270 | .operand_mapping = &.{ 0, 1 }, |
| 1271 | } else null, |
| 1272 | ); |
| 1273 | |
| 1274 | // lhs == reg should have been checked by airMinMax |
| 1275 | assert(lhs_reg != rhs_reg); // see note above |
| 1276 | |
| 1277 | _ = try self.addInst(.{ |
| 1278 | .tag = .cmp_shifted_register, |
| 1279 | .data = .{ .rr_imm6_shift = .{ |
| 1280 | .rn = lhs_reg, |
| 1281 | .rm = rhs_reg, |
| 1282 | .imm6 = 0, |
| 1283 | .shift = .lsl, |
| 1284 | } }, |
| 1285 | }); |
| 1286 | |
| 1287 | const cond_choose_lhs: Condition = switch (tag) { |
| 1288 | .max => switch (int_info.signedness) { |
| 1289 | .signed => Condition.gt, |
| 1290 | .unsigned => Condition.hi, |
| 1291 | }, |
| 1292 | .min => switch (int_info.signedness) { |
| 1293 | .signed => Condition.lt, |
| 1294 | .unsigned => Condition.cc, |
| 1295 | }, |
| 1296 | else => unreachable, |
| 1297 | }; |
| 1298 | |
| 1299 | _ = try self.addInst(.{ |
| 1300 | .tag = .csel, |
| 1301 | .data = .{ .rrr_cond = .{ |
| 1302 | .rd = dest_reg, |
| 1303 | .rn = lhs_reg, |
| 1304 | .rm = rhs_reg, |
| 1305 | .cond = cond_choose_lhs, |
| 1306 | } }, |
| 1307 | }); |
| 1308 | |
| 1309 | return MCValue{ .register = dest_reg }; |
| 1310 | } else { |
| 1311 | return self.fail("TODO ARM min/max on integers > u32/i32", .{}); |
| 1312 | } |
| 1313 | }, |
| 1314 | else => unreachable, |
| 1315 | } |
| 1241 | 1316 | } |
| 1242 | 1317 | |
| 1243 | | fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1318 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1319 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1244 | 1320 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1245 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch}); |
| 1321 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1322 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1323 | |
| 1324 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1325 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 1326 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 1327 | |
| 1328 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1329 | if (bin_op.lhs == bin_op.rhs) break :result lhs; |
| 1330 | |
| 1331 | break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst); |
| 1332 | }; |
| 1246 | 1333 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1247 | 1334 | } |
| 1248 | 1335 | |