| ... | @@ -539,8 +539,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -539,8 +539,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 539 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), | 539 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), |
| 540 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), | 540 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), |
| 541 | | 541 | |
| 542 | .min => try self.airMin(inst), | 542 | .min => try self.airMinMax(inst), |
| 543 | .max => try self.airMax(inst), | 543 | .max => try self.airMinMax(inst), |
| 544 | | 544 | |
| 545 | .add_sat => try self.airAddSat(inst), | 545 | .add_sat => try self.airAddSat(inst), |
| 546 | .sub_sat => try self.airSubSat(inst), | 546 | .sub_sat => try self.airSubSat(inst), |
| ... | @@ -1234,15 +1234,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1234,15 +1234,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1234 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 { | 1237 | fn minMax( |
| 1238 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1238 | self: *Self, |
| 1239 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch}); | 1239 | tag: Air.Inst.Tag, |
| 1240 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1333 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1247 | } | 1334 | } |
| 1248 | | 1335 | |