| ... | ... | @@ -31,6 +31,8 @@ const bits = @import("bits.zig"); |
| 31 | 31 | const abi = @import("abi.zig"); |
| 32 | 32 | const Register = bits.Register; |
| 33 | 33 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 34 | const caller_preserved_regs = abi.caller_preserved_regs; |
| 35 | const allocatable_registers = abi.allocatable_registers; |
| 34 | 36 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 35 | 37 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 36 | 38 | |
| ... | ... | @@ -40,7 +42,7 @@ const InnerError = error{ |
| 40 | 42 | OutOfRegisters, |
| 41 | 43 | }; |
| 42 | 44 | |
| 43 | | const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); |
| 45 | const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); |
| 44 | 46 | |
| 45 | 47 | gpa: Allocator, |
| 46 | 48 | air: Air, |
| ... | ... | @@ -56,7 +58,6 @@ arg_index: u32, |
| 56 | 58 | src_loc: Module.SrcLoc, |
| 57 | 59 | stack_align: u32, |
| 58 | 60 | |
| 59 | | ret_backpatches: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}, |
| 60 | 61 | compare_flags_inst: ?Air.Inst.Index = null, |
| 61 | 62 | |
| 62 | 63 | /// MIR Instructions |
| ... | ... | @@ -351,7 +352,6 @@ pub fn generate( |
| 351 | 352 | std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator) |
| 352 | 353 | else {}, |
| 353 | 354 | }; |
| 354 | | defer function.ret_backpatches.deinit(bin_file.allocator); |
| 355 | 355 | defer function.stack.deinit(bin_file.allocator); |
| 356 | 356 | defer function.blocks.deinit(bin_file.allocator); |
| 357 | 357 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| ... | ... | @@ -480,6 +480,21 @@ fn gen(self: *Self) InnerError!void { |
| 480 | 480 | .data = undefined, |
| 481 | 481 | }); |
| 482 | 482 | |
| 483 | if (self.ret_mcv == .stack_offset) { |
| 484 | // The address where to store the return value for the caller is in `.rdi` |
| 485 | // register which the callee is free to clobber. Therefore, we purposely |
| 486 | // spill it to stack immediately. |
| 487 | const ptr_ty = Type.usize; |
| 488 | const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*)); |
| 489 | const abi_align = ptr_ty.abiAlignment(self.target.*); |
| 490 | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); |
| 491 | self.next_stack_offset = stack_offset; |
| 492 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 493 | try self.genSetStack(ptr_ty, @intCast(i32, stack_offset), MCValue{ .register = .rdi }, .{}); |
| 494 | self.ret_mcv = MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 495 | log.debug("gen: spilling .rdi to stack at offset {}", .{stack_offset}); |
| 496 | } |
| 497 | |
| 483 | 498 | _ = try self.addInst(.{ |
| 484 | 499 | .tag = .dbg_prologue_end, |
| 485 | 500 | .ops = undefined, |
| ... | ... | @@ -517,23 +532,6 @@ fn gen(self: *Self) InnerError!void { |
| 517 | 532 | var disp = data.disp + 8; |
| 518 | 533 | inline for (callee_preserved_regs) |reg, i| { |
| 519 | 534 | if (self.register_manager.isRegAllocated(reg)) { |
| 520 | | if (reg.to64() == .rdi) { |
| 521 | | for (self.ret_backpatches.items) |inst| { |
| 522 | | log.debug(".rdi was spilled, backpatching with mov from stack at offset {}", .{ |
| 523 | | -@intCast(i32, disp), |
| 524 | | }); |
| 525 | | const ops = Mir.Ops.decode(self.mir_instructions.items(.ops)[inst]); |
| 526 | | self.mir_instructions.set(inst, Mir.Inst{ |
| 527 | | .tag = .mov, |
| 528 | | .ops = (Mir.Ops{ |
| 529 | | .reg1 = ops.reg1, |
| 530 | | .reg2 = .rbp, |
| 531 | | .flags = 0b01, |
| 532 | | }).encode(), |
| 533 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, disp)) }, |
| 534 | | }); |
| 535 | | } |
| 536 | | } |
| 537 | 535 | data.regs |= 1 << @intCast(u5, i); |
| 538 | 536 | self.max_end_stack += 8; |
| 539 | 537 | disp += 8; |
| ... | ... | @@ -912,8 +910,7 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 912 | 910 | // TODO find a free slot instead of always appending |
| 913 | 911 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); |
| 914 | 912 | self.next_stack_offset = offset; |
| 915 | | if (self.next_stack_offset > self.max_end_stack) |
| 916 | | self.max_end_stack = self.next_stack_offset; |
| 913 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 917 | 914 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 918 | 915 | .inst = inst, |
| 919 | 916 | .size = abi_size, |
| ... | ... | @@ -1256,7 +1253,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1256 | 1253 | offset_mcv.freezeIfRegister(&self.register_manager); |
| 1257 | 1254 | defer offset_mcv.unfreezeIfRegister(&self.register_manager); |
| 1258 | 1255 | |
| 1259 | | try self.genIMulOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); |
| 1256 | try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); |
| 1260 | 1257 | |
| 1261 | 1258 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1262 | 1259 | switch (tag) { |
| ... | ... | @@ -1398,10 +1395,29 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1398 | 1395 | |
| 1399 | 1396 | fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 1400 | 1397 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1401 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1402 | | .dead |
| 1403 | | else |
| 1404 | | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1398 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1399 | const ty = self.air.typeOfIndex(inst); |
| 1400 | |
| 1401 | if (ty.zigTypeTag() != .Int) { |
| 1402 | return self.fail("TODO implement 'mul' for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1403 | } |
| 1404 | |
| 1405 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1406 | try self.register_manager.getReg(.rax, inst); |
| 1407 | try self.register_manager.getReg(.rdx, null); |
| 1408 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1409 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1410 | |
| 1411 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1412 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1413 | |
| 1414 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1415 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1416 | .signed => .imul, |
| 1417 | .unsigned => .mul, |
| 1418 | }, ty, signedness, lhs, rhs); |
| 1419 | break :result MCValue{ .register = .rax }; |
| 1420 | }; |
| 1405 | 1421 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1406 | 1422 | } |
| 1407 | 1423 | |
| ... | ... | @@ -1476,23 +1492,33 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1476 | 1492 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1477 | 1493 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1478 | 1494 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1495 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1496 | const ty = self.air.typeOf(bin_op.lhs); |
| 1497 | const signedness: std.builtin.Signedness = blk: { |
| 1498 | if (ty.zigTypeTag() != .Int) { |
| 1499 | return self.fail("TODO implement airMulWithOverflow for type {}", .{ty.fmtDebug()}); |
| 1500 | } |
| 1501 | break :blk ty.intInfo(self.target.*).signedness; |
| 1502 | }; |
| 1479 | 1503 | |
| 1480 | | if (self.liveness.isUnused(inst)) { |
| 1481 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1482 | | } |
| 1504 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1505 | try self.register_manager.getReg(.rax, inst); |
| 1506 | try self.register_manager.getReg(.rdx, null); |
| 1507 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1508 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1483 | 1509 | |
| 1484 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1485 | | const signedness: std.builtin.Signedness = blk: { |
| 1486 | | if (ty.zigTypeTag() != .Int) { |
| 1487 | | return self.fail("TODO implement airMulWithOverflow for type {}", .{ty.fmtDebug()}); |
| 1488 | | } |
| 1489 | | break :blk ty.intInfo(self.target.*).signedness; |
| 1490 | | }; |
| 1510 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1511 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1491 | 1512 | |
| 1492 | | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1493 | | const result: MCValue = switch (signedness) { |
| 1494 | | .signed => .{ .register_overflow_signed = partial.register }, |
| 1495 | | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| 1513 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1514 | .signed => .imul, |
| 1515 | .unsigned => .mul, |
| 1516 | }, ty, signedness, lhs, rhs); |
| 1517 | |
| 1518 | switch (signedness) { |
| 1519 | .signed => break :result MCValue{ .register_overflow_signed = .rax }, |
| 1520 | .unsigned => break :result MCValue{ .register_overflow_unsigned = .rax }, |
| 1521 | } |
| 1496 | 1522 | }; |
| 1497 | 1523 | |
| 1498 | 1524 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1503,11 +1529,12 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1503 | 1529 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); |
| 1504 | 1530 | } |
| 1505 | 1531 | |
| 1506 | | /// Generates signed or unsigned integer division. |
| 1507 | | /// Requires use of .rax and .rdx registers. Spills them if necessary. |
| 1532 | /// Generates signed or unsigned integer multiplication/division. |
| 1533 | /// Clobbers .rax and .rdx registers. |
| 1508 | 1534 | /// Quotient is saved in .rax and remainder in .rdx. |
| 1509 | | fn genIntDivOpMir( |
| 1535 | fn genIntMulDivOpMir( |
| 1510 | 1536 | self: *Self, |
| 1537 | tag: Mir.Inst.Tag, |
| 1511 | 1538 | ty: Type, |
| 1512 | 1539 | signedness: std.builtin.Signedness, |
| 1513 | 1540 | lhs: MCValue, |
| ... | ... | @@ -1515,25 +1542,10 @@ fn genIntDivOpMir( |
| 1515 | 1542 | ) !void { |
| 1516 | 1543 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 1517 | 1544 | if (abi_size > 8) { |
| 1518 | | return self.fail("TODO implement genIntDivOpMir for ABI size larger than 8", .{}); |
| 1545 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); |
| 1519 | 1546 | } |
| 1520 | 1547 | |
| 1521 | | try self.register_manager.getReg(.rax, null); |
| 1522 | | try self.register_manager.getReg(.rdx, null); |
| 1523 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1524 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1525 | | |
| 1526 | | const dividend = switch (lhs) { |
| 1527 | | .register => lhs, |
| 1528 | | else => blk: { |
| 1529 | | const reg = try self.copyToTmpRegister(ty, lhs); |
| 1530 | | break :blk MCValue{ .register = reg }; |
| 1531 | | }, |
| 1532 | | }; |
| 1533 | | try self.genSetReg(ty, .rax, dividend); |
| 1534 | | |
| 1535 | | self.register_manager.freezeRegs(&.{dividend.register}); |
| 1536 | | defer self.register_manager.unfreezeRegs(&.{dividend.register}); |
| 1548 | try self.genSetReg(ty, .rax, lhs); |
| 1537 | 1549 | |
| 1538 | 1550 | switch (signedness) { |
| 1539 | 1551 | .signed => { |
| ... | ... | @@ -1557,22 +1569,19 @@ fn genIntDivOpMir( |
| 1557 | 1569 | }, |
| 1558 | 1570 | } |
| 1559 | 1571 | |
| 1560 | | const divisor = switch (rhs) { |
| 1572 | const factor = switch (rhs) { |
| 1561 | 1573 | .register => rhs, |
| 1574 | .stack_offset => rhs, |
| 1562 | 1575 | else => blk: { |
| 1563 | 1576 | const reg = try self.copyToTmpRegister(ty, rhs); |
| 1564 | 1577 | break :blk MCValue{ .register = reg }; |
| 1565 | 1578 | }, |
| 1566 | 1579 | }; |
| 1567 | | const op_tag: Mir.Inst.Tag = switch (signedness) { |
| 1568 | | .signed => .idiv, |
| 1569 | | .unsigned => .div, |
| 1570 | | }; |
| 1571 | 1580 | |
| 1572 | | switch (divisor) { |
| 1581 | switch (factor) { |
| 1573 | 1582 | .register => |reg| { |
| 1574 | 1583 | _ = try self.addInst(.{ |
| 1575 | | .tag = op_tag, |
| 1584 | .tag = tag, |
| 1576 | 1585 | .ops = (Mir.Ops{ |
| 1577 | 1586 | .reg1 = reg, |
| 1578 | 1587 | }).encode(), |
| ... | ... | @@ -1581,7 +1590,7 @@ fn genIntDivOpMir( |
| 1581 | 1590 | }, |
| 1582 | 1591 | .stack_offset => |off| { |
| 1583 | 1592 | _ = try self.addInst(.{ |
| 1584 | | .tag = op_tag, |
| 1593 | .tag = tag, |
| 1585 | 1594 | .ops = (Mir.Ops{ |
| 1586 | 1595 | .reg2 = .rbp, |
| 1587 | 1596 | .flags = switch (abi_size) { |
| ... | ... | @@ -1599,6 +1608,7 @@ fn genIntDivOpMir( |
| 1599 | 1608 | } |
| 1600 | 1609 | } |
| 1601 | 1610 | |
| 1611 | /// Clobbers .rax and .rdx registers. |
| 1602 | 1612 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 1603 | 1613 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1604 | 1614 | const dividend = switch (lhs) { |
| ... | ... | @@ -1614,7 +1624,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1614 | 1624 | self.register_manager.freezeRegs(&.{divisor}); |
| 1615 | 1625 | defer self.register_manager.unfreezeRegs(&.{ dividend, divisor }); |
| 1616 | 1626 | |
| 1617 | | try self.genIntDivOpMir(Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor }); |
| 1627 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1628 | .signed => .idiv, |
| 1629 | .unsigned => .div, |
| 1630 | }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor }); |
| 1618 | 1631 | |
| 1619 | 1632 | _ = try self.addInst(.{ |
| 1620 | 1633 | .tag = .xor, |
| ... | ... | @@ -1666,22 +1679,53 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1666 | 1679 | return self.fail("TODO implement {}", .{tag}); |
| 1667 | 1680 | } |
| 1668 | 1681 | |
| 1682 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1683 | |
| 1669 | 1684 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1670 | | try self.register_manager.getReg(.rax, null); |
| 1685 | const track_rax: ?Air.Inst.Index = blk: { |
| 1686 | if (signedness == .unsigned) break :blk inst; |
| 1687 | switch (tag) { |
| 1688 | .div_exact, .div_trunc => break :blk inst, |
| 1689 | else => break :blk null, |
| 1690 | } |
| 1691 | }; |
| 1692 | try self.register_manager.getReg(.rax, track_rax); |
| 1671 | 1693 | try self.register_manager.getReg(.rdx, null); |
| 1694 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1695 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1672 | 1696 | |
| 1673 | 1697 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1674 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1698 | lhs.freezeIfRegister(&self.register_manager); |
| 1699 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 1700 | |
| 1701 | const rhs = blk: { |
| 1702 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1703 | if (signedness == .signed) { |
| 1704 | switch (tag) { |
| 1705 | .div_floor => { |
| 1706 | rhs.freezeIfRegister(&self.register_manager); |
| 1707 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1708 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| 1709 | }, |
| 1710 | else => {}, |
| 1711 | } |
| 1712 | } |
| 1713 | break :blk rhs; |
| 1714 | }; |
| 1715 | rhs.freezeIfRegister(&self.register_manager); |
| 1716 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1675 | 1717 | |
| 1676 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1677 | 1718 | if (signedness == .unsigned) { |
| 1678 | | try self.genIntDivOpMir(ty, signedness, lhs, rhs); |
| 1719 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); |
| 1679 | 1720 | break :result MCValue{ .register = .rax }; |
| 1680 | 1721 | } |
| 1681 | 1722 | |
| 1682 | 1723 | switch (tag) { |
| 1683 | 1724 | .div_exact, .div_trunc => { |
| 1684 | | try self.genIntDivOpMir(ty, signedness, lhs, rhs); |
| 1725 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1726 | .signed => .idiv, |
| 1727 | .unsigned => .div, |
| 1728 | }, ty, signedness, lhs, rhs); |
| 1685 | 1729 | break :result MCValue{ .register = .rax }; |
| 1686 | 1730 | }, |
| 1687 | 1731 | .div_floor => { |
| ... | ... | @@ -1702,11 +1746,18 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1702 | 1746 | } |
| 1703 | 1747 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1704 | 1748 | try self.register_manager.getReg(.rax, null); |
| 1705 | | try self.register_manager.getReg(.rdx, null); |
| 1749 | try self.register_manager.getReg(.rdx, inst); |
| 1750 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1751 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1752 | |
| 1706 | 1753 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1707 | 1754 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1755 | |
| 1708 | 1756 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1709 | | try self.genIntDivOpMir(ty, signedness, lhs, rhs); |
| 1757 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1758 | .signed => .idiv, |
| 1759 | .unsigned => .div, |
| 1760 | }, ty, signedness, lhs, rhs); |
| 1710 | 1761 | break :result MCValue{ .register = .rdx }; |
| 1711 | 1762 | }; |
| 1712 | 1763 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1719,25 +1770,33 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1719 | 1770 | if (ty.zigTypeTag() != .Int) { |
| 1720 | 1771 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1721 | 1772 | } |
| 1773 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1774 | |
| 1722 | 1775 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1723 | 1776 | try self.register_manager.getReg(.rax, null); |
| 1724 | | try self.register_manager.getReg(.rdx, null); |
| 1777 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); |
| 1778 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1779 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1780 | |
| 1725 | 1781 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1726 | 1782 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1727 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1783 | |
| 1728 | 1784 | switch (signedness) { |
| 1729 | 1785 | .unsigned => { |
| 1730 | | try self.genIntDivOpMir(ty, signedness, lhs, rhs); |
| 1786 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1787 | .signed => .idiv, |
| 1788 | .unsigned => .div, |
| 1789 | }, ty, signedness, lhs, rhs); |
| 1731 | 1790 | break :result MCValue{ .register = .rdx }; |
| 1732 | 1791 | }, |
| 1733 | 1792 | .signed => { |
| 1734 | 1793 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); |
| 1735 | | try self.genIMulOpMir(ty, div_floor, rhs); |
| 1794 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 1736 | 1795 | |
| 1737 | | const reg = try self.copyToTmpRegister(ty, lhs); |
| 1738 | | try self.genBinMathOpMir(.sub, ty, .{ .register = reg }, div_floor); |
| 1796 | const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); |
| 1797 | try self.genBinMathOpMir(.sub, ty, result, div_floor); |
| 1739 | 1798 | |
| 1740 | | break :result MCValue{ .register = reg }; |
| 1799 | break :result result; |
| 1741 | 1800 | }, |
| 1742 | 1801 | } |
| 1743 | 1802 | }; |
| ... | ... | @@ -2134,7 +2193,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2134 | 2193 | |
| 2135 | 2194 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 2136 | 2195 | const reg = try self.copyToTmpRegister(index_ty, index); |
| 2137 | | try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 2196 | try self.genIntMulComplexOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 2138 | 2197 | return reg; |
| 2139 | 2198 | } |
| 2140 | 2199 | |
| ... | ... | @@ -3098,7 +3157,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3098 | 3157 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 3099 | 3158 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| 3100 | 3159 | .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv), |
| 3101 | | .mul, .mulwrap, .mul_with_overflow => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv), |
| 3102 | 3160 | else => unreachable, |
| 3103 | 3161 | } |
| 3104 | 3162 | return dst_mcv; |
| ... | ... | @@ -3254,8 +3312,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3254 | 3312 | } |
| 3255 | 3313 | } |
| 3256 | 3314 | |
| 3257 | | // Performs integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 3258 | | fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3315 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 3316 | /// Does not support byte-size operands. |
| 3317 | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3259 | 3318 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3260 | 3319 | switch (dst_mcv) { |
| 3261 | 3320 | .none => unreachable, |
| ... | ... | @@ -3301,7 +3360,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 3301 | 3360 | } else { |
| 3302 | 3361 | // TODO verify we don't spill and assign to the same register as dst_mcv |
| 3303 | 3362 | const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3304 | | return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg }); |
| 3363 | return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg }); |
| 3305 | 3364 | } |
| 3306 | 3365 | }, |
| 3307 | 3366 | .stack_offset => |off| { |
| ... | ... | @@ -3458,15 +3517,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3458 | 3517 | |
| 3459 | 3518 | try self.spillCompareFlagsIfOccupied(); |
| 3460 | 3519 | |
| 3520 | for (caller_preserved_regs) |reg| { |
| 3521 | try self.register_manager.getReg(reg, null); |
| 3522 | } |
| 3523 | |
| 3461 | 3524 | if (info.return_value == .stack_offset) { |
| 3462 | 3525 | const ret_ty = fn_ty.fnReturnType(); |
| 3463 | 3526 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3464 | 3527 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3465 | 3528 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); |
| 3529 | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); |
| 3466 | 3530 | |
| 3467 | 3531 | try self.register_manager.getReg(.rdi, null); |
| 3468 | | self.register_manager.freezeRegs(&.{.rdi}); |
| 3469 | 3532 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| 3533 | self.register_manager.freezeRegs(&.{.rdi}); |
| 3470 | 3534 | |
| 3471 | 3535 | info.return_value.stack_offset = stack_offset; |
| 3472 | 3536 | } |
| ... | ... | @@ -3653,15 +3717,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3653 | 3717 | |
| 3654 | 3718 | const result: MCValue = result: { |
| 3655 | 3719 | switch (info.return_value) { |
| 3656 | | .register => |reg| { |
| 3657 | | if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) { |
| 3658 | | // Save function return value in a callee saved register |
| 3659 | | break :result try self.copyToRegisterWithInstTracking( |
| 3660 | | inst, |
| 3661 | | self.air.typeOfIndex(inst), |
| 3662 | | info.return_value, |
| 3663 | | ); |
| 3664 | | } |
| 3720 | .register => { |
| 3721 | // Save function return value in a new register |
| 3722 | break :result try self.copyToRegisterWithInstTracking( |
| 3723 | inst, |
| 3724 | self.air.typeOfIndex(inst), |
| 3725 | info.return_value, |
| 3726 | ); |
| 3665 | 3727 | }, |
| 3666 | 3728 | else => {}, |
| 3667 | 3729 | } |
| ... | ... | @@ -3688,19 +3750,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 3688 | 3750 | const ret_ty = self.fn_type.fnReturnType(); |
| 3689 | 3751 | switch (self.ret_mcv) { |
| 3690 | 3752 | .stack_offset => { |
| 3691 | | // TODO audit register allocation! |
| 3692 | | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3693 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3694 | | const reg = try self.register_manager.allocReg(null); |
| 3695 | | const backpatch = try self.addInst(.{ |
| 3696 | | .tag = .mov, |
| 3697 | | .ops = (Mir.Ops{ |
| 3698 | | .reg1 = reg, |
| 3699 | | .reg2 = .rdi, |
| 3700 | | }).encode(), |
| 3701 | | .data = undefined, |
| 3702 | | }); |
| 3703 | | try self.ret_backpatches.append(self.gpa, backpatch); |
| 3753 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3754 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3755 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3756 | self.register_manager.freezeRegs(&.{reg}); |
| 3757 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 3704 | 3758 | try self.genSetStack(ret_ty, 0, operand, .{ |
| 3705 | 3759 | .source_stack_base = .rbp, |
| 3706 | 3760 | .dest_stack_base = reg, |
| ... | ... | @@ -3731,19 +3785,11 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3731 | 3785 | const elem_ty = ptr_ty.elemType(); |
| 3732 | 3786 | switch (self.ret_mcv) { |
| 3733 | 3787 | .stack_offset => { |
| 3734 | | // TODO audit register allocation! |
| 3735 | | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3736 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3737 | | const reg = try self.register_manager.allocReg(null); |
| 3738 | | const backpatch = try self.addInst(.{ |
| 3739 | | .tag = .mov, |
| 3740 | | .ops = (Mir.Ops{ |
| 3741 | | .reg1 = reg, |
| 3742 | | .reg2 = .rdi, |
| 3743 | | }).encode(), |
| 3744 | | .data = undefined, |
| 3745 | | }); |
| 3746 | | try self.ret_backpatches.append(self.gpa, backpatch); |
| 3788 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3789 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3790 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3791 | self.register_manager.freezeRegs(&.{reg}); |
| 3792 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 3747 | 3793 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, ptr, .{ .immediate = elem_ty.abiSize(self.target.*) }, .{ |
| 3748 | 3794 | .source_stack_base = .rbp, |
| 3749 | 3795 | .dest_stack_base = reg, |
| ... | ... | @@ -5033,6 +5079,7 @@ const InlineMemcpyOpts = struct { |
| 5033 | 5079 | dest_stack_base: ?Register = null, |
| 5034 | 5080 | }; |
| 5035 | 5081 | |
| 5082 | /// Spills .rax and .rcx. |
| 5036 | 5083 | fn genInlineMemcpy( |
| 5037 | 5084 | self: *Self, |
| 5038 | 5085 | dst_ptr: MCValue, |
| ... | ... | @@ -5040,13 +5087,7 @@ fn genInlineMemcpy( |
| 5040 | 5087 | len: MCValue, |
| 5041 | 5088 | opts: InlineMemcpyOpts, |
| 5042 | 5089 | ) InnerError!void { |
| 5043 | | // TODO this is wrong. We should check first if any of the operands is in `.rax` or `.rcx` before |
| 5044 | | // spilling. Consolidate with other TODOs regarding register allocation mechanics. |
| 5045 | | try self.register_manager.getReg(.rax, null); |
| 5046 | | try self.register_manager.getReg(.rcx, null); |
| 5047 | | |
| 5048 | 5090 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 5049 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 5050 | 5091 | |
| 5051 | 5092 | if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 5052 | 5093 | defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| ... | ... | @@ -5086,7 +5127,6 @@ fn genInlineMemcpy( |
| 5086 | 5127 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| 5087 | 5128 | }, |
| 5088 | 5129 | } |
| 5089 | | |
| 5090 | 5130 | self.register_manager.freezeRegs(&.{dst_addr_reg}); |
| 5091 | 5131 | defer self.register_manager.unfreezeRegs(&.{dst_addr_reg}); |
| 5092 | 5132 | |
| ... | ... | @@ -5122,7 +5162,6 @@ fn genInlineMemcpy( |
| 5122 | 5162 | return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr}); |
| 5123 | 5163 | }, |
| 5124 | 5164 | } |
| 5125 | | |
| 5126 | 5165 | self.register_manager.freezeRegs(&.{src_addr_reg}); |
| 5127 | 5166 | defer self.register_manager.unfreezeRegs(&.{src_addr_reg}); |
| 5128 | 5167 | |
| ... | ... | @@ -5130,6 +5169,11 @@ fn genInlineMemcpy( |
| 5130 | 5169 | const count_reg = regs[0].to64(); |
| 5131 | 5170 | const tmp_reg = regs[1].to8(); |
| 5132 | 5171 | |
| 5172 | self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 5173 | |
| 5174 | try self.register_manager.getReg(.rax, null); |
| 5175 | try self.register_manager.getReg(.rcx, null); |
| 5176 | |
| 5133 | 5177 | try self.genSetReg(Type.usize, count_reg, len); |
| 5134 | 5178 | |
| 5135 | 5179 | // mov rcx, 0 |
| ... | ... | @@ -5225,6 +5269,7 @@ fn genInlineMemcpy( |
| 5225 | 5269 | try self.performReloc(loop_reloc); |
| 5226 | 5270 | } |
| 5227 | 5271 | |
| 5272 | /// Spills .rax register. |
| 5228 | 5273 | fn genInlineMemset( |
| 5229 | 5274 | self: *Self, |
| 5230 | 5275 | dst_ptr: MCValue, |
| ... | ... | @@ -5232,9 +5277,7 @@ fn genInlineMemset( |
| 5232 | 5277 | len: MCValue, |
| 5233 | 5278 | opts: InlineMemcpyOpts, |
| 5234 | 5279 | ) InnerError!void { |
| 5235 | | try self.register_manager.getReg(.rax, null); |
| 5236 | 5280 | self.register_manager.freezeRegs(&.{.rax}); |
| 5237 | | defer self.register_manager.unfreezeRegs(&.{.rax}); |
| 5238 | 5281 | |
| 5239 | 5282 | const addr_reg = try self.register_manager.allocReg(null); |
| 5240 | 5283 | switch (dst_ptr) { |
| ... | ... | @@ -5271,6 +5314,9 @@ fn genInlineMemset( |
| 5271 | 5314 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 5272 | 5315 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 5273 | 5316 | |
| 5317 | self.register_manager.unfreezeRegs(&.{.rax}); |
| 5318 | try self.register_manager.getReg(.rax, null); |
| 5319 | |
| 5274 | 5320 | try self.genSetReg(Type.usize, .rax, len); |
| 5275 | 5321 | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| 5276 | 5322 | |