| ... | ... | @@ -1252,37 +1252,54 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1252 | 1252 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); |
| 1253 | 1253 | } |
| 1254 | 1254 | |
| 1255 | | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1256 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1257 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1258 | | const dst_ty = self.air.typeOfIndex(inst); |
| 1259 | | const tag = self.air.instructions.items(.tag)[inst]; |
| 1260 | | switch (tag) { |
| 1261 | | .div_exact => {}, |
| 1262 | | .div_trunc, .div_floor, .div_float => return self.fail("TODO implement {}", .{tag}), |
| 1263 | | else => unreachable, |
| 1264 | | } |
| 1255 | /// Perform signed and unsigned integer division. |
| 1256 | /// TODO it might be wise to split some functionality into integer and floating-point |
| 1257 | /// specialised functions. |
| 1258 | /// Supports AIR tag: |
| 1259 | /// .div_exact, .div_trunc, .div_floor, .mod, .rem |
| 1260 | fn genDivOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 1261 | const dst_ty = self.air.typeOfIndex(inst); |
| 1262 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1265 | 1263 | |
| 1266 | | if (dst_ty.zigTypeTag() != .Int) { |
| 1267 | | return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() }); |
| 1268 | | } |
| 1264 | switch (tag) { |
| 1265 | .div_exact, .div_trunc, .div_floor, .mod, .rem => {}, |
| 1266 | .div_float => return self.fail("TODO implement genDivOp for {}", .{tag}), |
| 1267 | else => unreachable, |
| 1268 | } |
| 1269 | |
| 1270 | if (dst_ty.zigTypeTag() != .Int) { |
| 1271 | return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() }); |
| 1272 | } |
| 1273 | if (dst_ty.abiSize(self.target.*) > 8) { |
| 1274 | return self.fail("TODO implement {} for ABI size larger than 8", .{tag}); |
| 1275 | } |
| 1269 | 1276 | |
| 1270 | | const signedness = dst_ty.intInfo(self.target.*).signedness; |
| 1271 | | const ty = if (signedness == .signed) Type.isize else dst_ty; |
| 1272 | | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 1277 | const signedness = dst_ty.intInfo(self.target.*).signedness; |
| 1278 | const tmp_ty = switch (signedness) { |
| 1279 | .signed => Type.isize, |
| 1280 | .unsigned => dst_ty, |
| 1281 | }; |
| 1282 | const abi_size = @intCast(u32, tmp_ty.abiSize(self.target.*)); |
| 1273 | 1283 | |
| 1274 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1275 | | blk: { |
| 1276 | | switch (lhs) { |
| 1277 | | .register => |reg| { |
| 1278 | | if (reg.to64() == .rax) break :blk; |
| 1279 | | }, |
| 1280 | | else => {}, |
| 1281 | | } |
| 1282 | | try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager |
| 1283 | | try self.genSetReg(ty, .rax, lhs); |
| 1284 | const lhs = try self.resolveInst(op_lhs); |
| 1285 | blk: { |
| 1286 | switch (lhs) { |
| 1287 | .register => |reg| { |
| 1288 | if (reg.to64() == .rax) break :blk; |
| 1289 | }, |
| 1290 | else => {}, |
| 1284 | 1291 | } |
| 1285 | | if (signedness == .signed) { |
| 1292 | try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager |
| 1293 | try self.genSetReg(tmp_ty, .rax, lhs); |
| 1294 | } |
| 1295 | |
| 1296 | try self.register_manager.getReg(.rdx, null); |
| 1297 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1298 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1299 | |
| 1300 | // Prep rdx for the op |
| 1301 | switch (signedness) { |
| 1302 | .signed => { |
| 1286 | 1303 | _ = try self.addInst(.{ |
| 1287 | 1304 | .tag = .cwd, |
| 1288 | 1305 | .ops = (Mir.Ops{ |
| ... | ... | @@ -1290,56 +1307,76 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1290 | 1307 | }).encode(), |
| 1291 | 1308 | .data = undefined, |
| 1292 | 1309 | }); |
| 1293 | | } |
| 1294 | | const dst_mcv = MCValue{ .register = registerAlias(.rax, abi_size) }; |
| 1295 | | |
| 1296 | | try self.register_manager.getReg(.rdx, null); |
| 1297 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1298 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1299 | | |
| 1300 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1301 | | const divisor = blk: { |
| 1302 | | switch (rhs) { |
| 1303 | | .register, .stack_offset => break :blk rhs, |
| 1304 | | else => { |
| 1305 | | const reg = try self.copyToTmpRegister(ty, rhs); |
| 1306 | | break :blk MCValue{ .register = reg }; |
| 1307 | | }, |
| 1308 | | } |
| 1309 | | }; |
| 1310 | }, |
| 1311 | .unsigned => { |
| 1312 | _ = try self.addInst(.{ |
| 1313 | .tag = .xor, |
| 1314 | .ops = (Mir.Ops{ |
| 1315 | .reg1 = .rdx, |
| 1316 | .reg2 = .rdx, |
| 1317 | }).encode(), |
| 1318 | .data = undefined, |
| 1319 | }); |
| 1320 | }, |
| 1321 | } |
| 1310 | 1322 | |
| 1311 | | switch (divisor) { |
| 1312 | | .register => |reg| { |
| 1313 | | _ = try self.addInst(.{ |
| 1314 | | .tag = .idiv, |
| 1315 | | .ops = (Mir.Ops{ |
| 1316 | | .reg1 = registerAlias(reg, abi_size), |
| 1317 | | }).encode(), |
| 1318 | | .data = undefined, |
| 1319 | | }); |
| 1320 | | }, |
| 1321 | | .stack_offset => |off| { |
| 1322 | | const flags: u2 = switch (abi_size) { |
| 1323 | | 1 => 0b00, |
| 1324 | | 2 => 0b01, |
| 1325 | | 4 => 0b10, |
| 1326 | | 8 => 0b11, |
| 1327 | | else => unreachable, |
| 1328 | | }; |
| 1329 | | _ = try self.addInst(.{ |
| 1330 | | .tag = .idiv, |
| 1331 | | .ops = (Mir.Ops{ |
| 1332 | | .reg2 = .rbp, |
| 1333 | | .flags = flags, |
| 1334 | | }).encode(), |
| 1335 | | .data = .{ .imm = @bitCast(u32, -off) }, |
| 1336 | | }); |
| 1323 | const rhs = try self.resolveInst(op_rhs); |
| 1324 | const divisor = blk: { |
| 1325 | switch (rhs) { |
| 1326 | .register, .stack_offset => break :blk rhs, |
| 1327 | else => { |
| 1328 | const reg = try self.copyToTmpRegister(tmp_ty, rhs); |
| 1329 | break :blk MCValue{ .register = reg }; |
| 1337 | 1330 | }, |
| 1338 | | else => unreachable, |
| 1339 | 1331 | } |
| 1332 | }; |
| 1333 | const op_tag: Mir.Inst.Tag = switch (signedness) { |
| 1334 | .signed => .idiv, |
| 1335 | .unsigned => .div, |
| 1336 | }; |
| 1340 | 1337 | |
| 1341 | | break :result dst_mcv; |
| 1338 | switch (divisor) { |
| 1339 | .register => |reg| { |
| 1340 | _ = try self.addInst(.{ |
| 1341 | .tag = op_tag, |
| 1342 | .ops = (Mir.Ops{ |
| 1343 | .reg1 = registerAlias(reg, abi_size), |
| 1344 | }).encode(), |
| 1345 | .data = undefined, |
| 1346 | }); |
| 1347 | }, |
| 1348 | .stack_offset => |off| { |
| 1349 | _ = try self.addInst(.{ |
| 1350 | .tag = op_tag, |
| 1351 | .ops = (Mir.Ops{ |
| 1352 | .reg2 = .rbp, |
| 1353 | .flags = switch (abi_size) { |
| 1354 | 1 => 0b00, |
| 1355 | 2 => 0b01, |
| 1356 | 4 => 0b10, |
| 1357 | 8 => 0b11, |
| 1358 | else => unreachable, |
| 1359 | }, |
| 1360 | }).encode(), |
| 1361 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 1362 | }); |
| 1363 | }, |
| 1364 | else => unreachable, |
| 1365 | } |
| 1366 | |
| 1367 | return switch (tag) { |
| 1368 | .mod, .div_exact, .div_trunc, .div_floor => MCValue{ .register = .rax }, |
| 1369 | .rem => MCValue{ .register = .rdx }, |
| 1370 | else => unreachable, |
| 1342 | 1371 | }; |
| 1372 | } |
| 1373 | |
| 1374 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1375 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1376 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1377 | .dead |
| 1378 | else |
| 1379 | try self.genDivOp(inst, bin_op.lhs, bin_op.rhs); |
| 1343 | 1380 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1344 | 1381 | } |
| 1345 | 1382 | |
| ... | ... | @@ -1348,7 +1385,7 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1348 | 1385 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1349 | 1386 | .dead |
| 1350 | 1387 | else |
| 1351 | | return self.fail("TODO implement rem for {}", .{self.target.cpu.arch}); |
| 1388 | try self.genDivOp(inst, bin_op.lhs, bin_op.rhs); |
| 1352 | 1389 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1353 | 1390 | } |
| 1354 | 1391 | |
| ... | ... | @@ -1357,7 +1394,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1357 | 1394 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1358 | 1395 | .dead |
| 1359 | 1396 | else |
| 1360 | | return self.fail("TODO implement mod for {}", .{self.target.cpu.arch}); |
| 1397 | try self.genDivOp(inst, bin_op.lhs, bin_op.rhs); |
| 1361 | 1398 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1362 | 1399 | } |
| 1363 | 1400 | |