| ... | @@ -1252,37 +1252,54 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1252,37 +1252,54 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1252 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); | 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 { | 1255 | /// Perform signed and unsigned integer division. |
| 1256 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1256 | /// TODO it might be wise to split some functionality into integer and floating-point |
| 1257 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1257 | /// specialised functions. |
| 1258 | const dst_ty = self.air.typeOfIndex(inst); | 1258 | /// Supports AIR tag: |
| 1259 | const tag = self.air.instructions.items(.tag)[inst]; | 1259 | /// .div_exact, .div_trunc, .div_floor, .mod, .rem |
| 1260 | switch (tag) { | 1260 | fn genDivOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 1261 | .div_exact => {}, | 1261 | const dst_ty = self.air.typeOfIndex(inst); |
| 1262 | .div_trunc, .div_floor, .div_float => return self.fail("TODO implement {}", .{tag}), | 1262 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1263 | else => unreachable, | | |
| 1264 | } | | |
| 1265 | | 1263 | |
| 1266 | if (dst_ty.zigTypeTag() != .Int) { | 1264 | switch (tag) { |
| 1267 | return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() }); | 1265 | .div_exact, .div_trunc, .div_floor, .mod, .rem => {}, |
| 1268 | } | 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; | 1277 | const signedness = dst_ty.intInfo(self.target.*).signedness; |
| 1271 | const ty = if (signedness == .signed) Type.isize else dst_ty; | 1278 | const tmp_ty = switch (signedness) { |
| 1272 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 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); | 1284 | const lhs = try self.resolveInst(op_lhs); |
| 1275 | blk: { | 1285 | blk: { |
| 1276 | switch (lhs) { | 1286 | switch (lhs) { |
| 1277 | .register => |reg| { | 1287 | .register => |reg| { |
| 1278 | if (reg.to64() == .rax) break :blk; | 1288 | if (reg.to64() == .rax) break :blk; |
| 1279 | }, | 1289 | }, |
| 1280 | else => {}, | 1290 | else => {}, |
| 1281 | } | | |
| 1282 | try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager | | |
| 1283 | try self.genSetReg(ty, .rax, lhs); | | |
| 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 | _ = try self.addInst(.{ | 1303 | _ = try self.addInst(.{ |
| 1287 | .tag = .cwd, | 1304 | .tag = .cwd, |
| 1288 | .ops = (Mir.Ops{ | 1305 | .ops = (Mir.Ops{ |
| ... | @@ -1290,56 +1307,76 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1290,56 +1307,76 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1290 | }).encode(), | 1307 | }).encode(), |
| 1291 | .data = undefined, | 1308 | .data = undefined, |
| 1292 | }); | 1309 | }); |
| 1293 | } | 1310 | }, |
| 1294 | const dst_mcv = MCValue{ .register = registerAlias(.rax, abi_size) }; | 1311 | .unsigned => { |
| 1295 | | 1312 | _ = try self.addInst(.{ |
| 1296 | try self.register_manager.getReg(.rdx, null); | 1313 | .tag = .xor, |
| 1297 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); | 1314 | .ops = (Mir.Ops{ |
| 1298 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); | 1315 | .reg1 = .rdx, |
| 1299 | | 1316 | .reg2 = .rdx, |
| 1300 | const rhs = try self.resolveInst(bin_op.rhs); | 1317 | }).encode(), |
| 1301 | const divisor = blk: { | 1318 | .data = undefined, |
| 1302 | switch (rhs) { | 1319 | }); |
| 1303 | .register, .stack_offset => break :blk rhs, | 1320 | }, |
| 1304 | else => { | 1321 | } |
| 1305 | const reg = try self.copyToTmpRegister(ty, rhs); | | |
| 1306 | break :blk MCValue{ .register = reg }; | | |
| 1307 | }, | | |
| 1308 | } | | |
| 1309 | }; | | |
| 1310 | | 1322 | |
| 1311 | switch (divisor) { | 1323 | const rhs = try self.resolveInst(op_rhs); |
| 1312 | .register => |reg| { | 1324 | const divisor = blk: { |
| 1313 | _ = try self.addInst(.{ | 1325 | switch (rhs) { |
| 1314 | .tag = .idiv, | 1326 | .register, .stack_offset => break :blk rhs, |
| 1315 | .ops = (Mir.Ops{ | 1327 | else => { |
| 1316 | .reg1 = registerAlias(reg, abi_size), | 1328 | const reg = try self.copyToTmpRegister(tmp_ty, rhs); |
| 1317 | }).encode(), | 1329 | break :blk MCValue{ .register = reg }; |
| 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 | }); | | |
| 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,7 +1385,7 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1348 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1385 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1349 | .dead | 1386 | .dead |
| 1350 | else | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,7 +1394,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1357 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1394 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1358 | .dead | 1395 | .dead |
| 1359 | else | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1398 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1362 | } | 1399 | } |
| 1363 | | 1400 | |