| ... | @@ -31,6 +31,8 @@ const bits = @import("bits.zig"); | ... | @@ -31,6 +31,8 @@ const bits = @import("bits.zig"); |
| 31 | const abi = @import("abi.zig"); | 31 | const abi = @import("abi.zig"); |
| 32 | const Register = bits.Register; | 32 | const Register = bits.Register; |
| 33 | const callee_preserved_regs = abi.callee_preserved_regs; | 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 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; | 36 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 35 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 37 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 36 | | 38 | |
| ... | @@ -40,7 +42,7 @@ const InnerError = error{ | ... | @@ -40,7 +42,7 @@ const InnerError = error{ |
| 40 | OutOfRegisters, | 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 | gpa: Allocator, | 47 | gpa: Allocator, |
| 46 | air: Air, | 48 | air: Air, |
| ... | @@ -56,7 +58,6 @@ arg_index: u32, | ... | @@ -56,7 +58,6 @@ arg_index: u32, |
| 56 | src_loc: Module.SrcLoc, | 58 | src_loc: Module.SrcLoc, |
| 57 | stack_align: u32, | 59 | stack_align: u32, |
| 58 | | 60 | |
| 59 | ret_backpatches: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}, | | |
| 60 | compare_flags_inst: ?Air.Inst.Index = null, | 61 | compare_flags_inst: ?Air.Inst.Index = null, |
| 61 | | 62 | |
| 62 | /// MIR Instructions | 63 | /// MIR Instructions |
| ... | @@ -351,7 +352,6 @@ pub fn generate( | ... | @@ -351,7 +352,6 @@ pub fn generate( |
| 351 | std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator) | 352 | std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator) |
| 352 | else {}, | 353 | else {}, |
| 353 | }; | 354 | }; |
| 354 | defer function.ret_backpatches.deinit(bin_file.allocator); | | |
| 355 | defer function.stack.deinit(bin_file.allocator); | 355 | defer function.stack.deinit(bin_file.allocator); |
| 356 | defer function.blocks.deinit(bin_file.allocator); | 356 | defer function.blocks.deinit(bin_file.allocator); |
| 357 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); | 357 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| ... | @@ -480,6 +480,21 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -480,6 +480,21 @@ fn gen(self: *Self) InnerError!void { |
| 480 | .data = undefined, | 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 | _ = try self.addInst(.{ | 498 | _ = try self.addInst(.{ |
| 484 | .tag = .dbg_prologue_end, | 499 | .tag = .dbg_prologue_end, |
| 485 | .ops = undefined, | 500 | .ops = undefined, |
| ... | @@ -517,23 +532,6 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -517,23 +532,6 @@ fn gen(self: *Self) InnerError!void { |
| 517 | var disp = data.disp + 8; | 532 | var disp = data.disp + 8; |
| 518 | inline for (callee_preserved_regs) |reg, i| { | 533 | inline for (callee_preserved_regs) |reg, i| { |
| 519 | if (self.register_manager.isRegAllocated(reg)) { | 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 | data.regs |= 1 << @intCast(u5, i); | 535 | data.regs |= 1 << @intCast(u5, i); |
| 538 | self.max_end_stack += 8; | 536 | self.max_end_stack += 8; |
| 539 | disp += 8; | 537 | disp += 8; |
| ... | @@ -912,8 +910,7 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u | ... | @@ -912,8 +910,7 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 912 | // TODO find a free slot instead of always appending | 910 | // TODO find a free slot instead of always appending |
| 913 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); | 911 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); |
| 914 | self.next_stack_offset = offset; | 912 | self.next_stack_offset = offset; |
| 915 | if (self.next_stack_offset > self.max_end_stack) | 913 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 916 | self.max_end_stack = self.next_stack_offset; | | |
| 917 | try self.stack.putNoClobber(self.gpa, offset, .{ | 914 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 918 | .inst = inst, | 915 | .inst = inst, |
| 919 | .size = abi_size, | 916 | .size = abi_size, |
| ... | @@ -1256,7 +1253,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r | ... | @@ -1256,7 +1253,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1256 | offset_mcv.freezeIfRegister(&self.register_manager); | 1253 | offset_mcv.freezeIfRegister(&self.register_manager); |
| 1257 | defer offset_mcv.unfreezeIfRegister(&self.register_manager); | 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 | const tag = self.air.instructions.items(.tag)[inst]; | 1258 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1262 | switch (tag) { | 1259 | switch (tag) { |
| ... | @@ -1398,10 +1395,29 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1398,10 +1395,29 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1398 | | 1395 | |
| 1399 | fn airMul(self: *Self, inst: Air.Inst.Index) !void { | 1396 | fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 1400 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1397 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1401 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1398 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1402 | .dead | 1399 | const ty = self.air.typeOfIndex(inst); |
| 1403 | else | 1400 | |
| 1404 | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,23 +1492,33 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1476 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1492 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1477 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1493 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1478 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 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)) { | 1504 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1481 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 1505 | try self.register_manager.getReg(.rax, inst); |
| 1482 | } | 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); | 1510 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1485 | const signedness: std.builtin.Signedness = blk: { | 1511 | const rhs = try self.resolveInst(bin_op.rhs); |
| 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 | }; | | |
| 1491 | | 1512 | |
| 1492 | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); | 1513 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1493 | const result: MCValue = switch (signedness) { | 1514 | .signed => .imul, |
| 1494 | .signed => .{ .register_overflow_signed = partial.register }, | 1515 | .unsigned => .mul, |
| 1495 | .unsigned => .{ .register_overflow_unsigned = partial.register }, | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,11 +1529,12 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1503 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); | 1529 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); |
| 1504 | } | 1530 | } |
| 1505 | | 1531 | |
| 1506 | /// Generates signed or unsigned integer division. | 1532 | /// Generates signed or unsigned integer multiplication/division. |
| 1507 | /// Requires use of .rax and .rdx registers. Spills them if necessary. | 1533 | /// Clobbers .rax and .rdx registers. |
| 1508 | /// Quotient is saved in .rax and remainder in .rdx. | 1534 | /// Quotient is saved in .rax and remainder in .rdx. |
| 1509 | fn genIntDivOpMir( | 1535 | fn genIntMulDivOpMir( |
| 1510 | self: *Self, | 1536 | self: *Self, |
| | 1537 | tag: Mir.Inst.Tag, |
| 1511 | ty: Type, | 1538 | ty: Type, |
| 1512 | signedness: std.builtin.Signedness, | 1539 | signedness: std.builtin.Signedness, |
| 1513 | lhs: MCValue, | 1540 | lhs: MCValue, |
| ... | @@ -1515,25 +1542,10 @@ fn genIntDivOpMir( | ... | @@ -1515,25 +1542,10 @@ fn genIntDivOpMir( |
| 1515 | ) !void { | 1542 | ) !void { |
| 1516 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 1543 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 1517 | if (abi_size > 8) { | 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); | 1548 | try self.genSetReg(ty, .rax, lhs); |
| 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}); | | |
| 1537 | | 1549 | |
| 1538 | switch (signedness) { | 1550 | switch (signedness) { |
| 1539 | .signed => { | 1551 | .signed => { |
| ... | @@ -1557,22 +1569,19 @@ fn genIntDivOpMir( | ... | @@ -1557,22 +1569,19 @@ fn genIntDivOpMir( |
| 1557 | }, | 1569 | }, |
| 1558 | } | 1570 | } |
| 1559 | | 1571 | |
| 1560 | const divisor = switch (rhs) { | 1572 | const factor = switch (rhs) { |
| 1561 | .register => rhs, | 1573 | .register => rhs, |
| | 1574 | .stack_offset => rhs, |
| 1562 | else => blk: { | 1575 | else => blk: { |
| 1563 | const reg = try self.copyToTmpRegister(ty, rhs); | 1576 | const reg = try self.copyToTmpRegister(ty, rhs); |
| 1564 | break :blk MCValue{ .register = reg }; | 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 | .register => |reg| { | 1582 | .register => |reg| { |
| 1574 | _ = try self.addInst(.{ | 1583 | _ = try self.addInst(.{ |
| 1575 | .tag = op_tag, | 1584 | .tag = tag, |
| 1576 | .ops = (Mir.Ops{ | 1585 | .ops = (Mir.Ops{ |
| 1577 | .reg1 = reg, | 1586 | .reg1 = reg, |
| 1578 | }).encode(), | 1587 | }).encode(), |
| ... | @@ -1581,7 +1590,7 @@ fn genIntDivOpMir( | ... | @@ -1581,7 +1590,7 @@ fn genIntDivOpMir( |
| 1581 | }, | 1590 | }, |
| 1582 | .stack_offset => |off| { | 1591 | .stack_offset => |off| { |
| 1583 | _ = try self.addInst(.{ | 1592 | _ = try self.addInst(.{ |
| 1584 | .tag = op_tag, | 1593 | .tag = tag, |
| 1585 | .ops = (Mir.Ops{ | 1594 | .ops = (Mir.Ops{ |
| 1586 | .reg2 = .rbp, | 1595 | .reg2 = .rbp, |
| 1587 | .flags = switch (abi_size) { | 1596 | .flags = switch (abi_size) { |
| ... | @@ -1599,6 +1608,7 @@ fn genIntDivOpMir( | ... | @@ -1599,6 +1608,7 @@ fn genIntDivOpMir( |
| 1599 | } | 1608 | } |
| 1600 | } | 1609 | } |
| 1601 | | 1610 | |
| | 1611 | /// Clobbers .rax and .rdx registers. |
| 1602 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { | 1612 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 1603 | const signedness = ty.intInfo(self.target.*).signedness; | 1613 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1604 | const dividend = switch (lhs) { | 1614 | const dividend = switch (lhs) { |
| ... | @@ -1614,7 +1624,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -1614,7 +1624,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1614 | self.register_manager.freezeRegs(&.{divisor}); | 1624 | self.register_manager.freezeRegs(&.{divisor}); |
| 1615 | defer self.register_manager.unfreezeRegs(&.{ dividend, divisor }); | 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 | _ = try self.addInst(.{ | 1632 | _ = try self.addInst(.{ |
| 1620 | .tag = .xor, | 1633 | .tag = .xor, |
| ... | @@ -1666,22 +1679,53 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1666,22 +1679,53 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1666 | return self.fail("TODO implement {}", .{tag}); | 1679 | return self.fail("TODO implement {}", .{tag}); |
| 1667 | } | 1680 | } |
| 1668 | | 1681 | |
| | 1682 | const signedness = ty.intInfo(self.target.*).signedness; |
| | 1683 | |
| 1669 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | 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 | try self.register_manager.getReg(.rdx, null); | 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 | const lhs = try self.resolveInst(bin_op.lhs); | 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 | if (signedness == .unsigned) { | 1718 | if (signedness == .unsigned) { |
| 1678 | try self.genIntDivOpMir(ty, signedness, lhs, rhs); | 1719 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); |
| 1679 | break :result MCValue{ .register = .rax }; | 1720 | break :result MCValue{ .register = .rax }; |
| 1680 | } | 1721 | } |
| 1681 | | 1722 | |
| 1682 | switch (tag) { | 1723 | switch (tag) { |
| 1683 | .div_exact, .div_trunc => { | 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 | break :result MCValue{ .register = .rax }; | 1729 | break :result MCValue{ .register = .rax }; |
| 1686 | }, | 1730 | }, |
| 1687 | .div_floor => { | 1731 | .div_floor => { |
| ... | @@ -1702,11 +1746,18 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1702,11 +1746,18 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1702 | } | 1746 | } |
| 1703 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | 1747 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1704 | try self.register_manager.getReg(.rax, null); | 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 | const lhs = try self.resolveInst(bin_op.lhs); | 1753 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1707 | const rhs = try self.resolveInst(bin_op.rhs); | 1754 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1755 | |
| 1708 | const signedness = ty.intInfo(self.target.*).signedness; | 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 | break :result MCValue{ .register = .rdx }; | 1761 | break :result MCValue{ .register = .rdx }; |
| 1711 | }; | 1762 | }; |
| 1712 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,25 +1770,33 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1719 | if (ty.zigTypeTag() != .Int) { | 1770 | if (ty.zigTypeTag() != .Int) { |
| 1720 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); | 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 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | 1775 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1723 | try self.register_manager.getReg(.rax, null); | 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 | const lhs = try self.resolveInst(bin_op.lhs); | 1781 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1726 | const rhs = try self.resolveInst(bin_op.rhs); | 1782 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1727 | const signedness = ty.intInfo(self.target.*).signedness; | 1783 | |
| 1728 | switch (signedness) { | 1784 | switch (signedness) { |
| 1729 | .unsigned => { | 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 | break :result MCValue{ .register = .rdx }; | 1790 | break :result MCValue{ .register = .rdx }; |
| 1732 | }, | 1791 | }, |
| 1733 | .signed => { | 1792 | .signed => { |
| 1734 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); | 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); | 1796 | const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); |
| 1738 | try self.genBinMathOpMir(.sub, ty, .{ .register = reg }, div_floor); | 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,7 +2193,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2134 | | 2193 | |
| 2135 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { | 2194 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 2136 | const reg = try self.copyToTmpRegister(index_ty, index); | 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 | return reg; | 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,7 +3157,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3098 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), | 3157 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 3099 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), | 3158 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| 3100 | .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv), | 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 | else => unreachable, | 3160 | else => unreachable, |
| 3103 | } | 3161 | } |
| 3104 | return dst_mcv; | 3162 | return dst_mcv; |
| ... | @@ -3254,8 +3312,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -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. | 3315 | /// Performs multi-operand 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 { | 3316 | /// Does not support byte-size operands. |
| | 3317 | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3259 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 3318 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3260 | switch (dst_mcv) { | 3319 | switch (dst_mcv) { |
| 3261 | .none => unreachable, | 3320 | .none => unreachable, |
| ... | @@ -3301,7 +3360,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -3301,7 +3360,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 3301 | } else { | 3360 | } else { |
| 3302 | // TODO verify we don't spill and assign to the same register as dst_mcv | 3361 | // TODO verify we don't spill and assign to the same register as dst_mcv |
| 3303 | const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv); | 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 | .stack_offset => |off| { | 3366 | .stack_offset => |off| { |
| ... | @@ -3458,15 +3517,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3458,15 +3517,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3458 | | 3517 | |
| 3459 | try self.spillCompareFlagsIfOccupied(); | 3518 | try self.spillCompareFlagsIfOccupied(); |
| 3460 | | 3519 | |
| | 3520 | for (caller_preserved_regs) |reg| { |
| | 3521 | try self.register_manager.getReg(reg, null); |
| | 3522 | } |
| | 3523 | |
| 3461 | if (info.return_value == .stack_offset) { | 3524 | if (info.return_value == .stack_offset) { |
| 3462 | const ret_ty = fn_ty.fnReturnType(); | 3525 | const ret_ty = fn_ty.fnReturnType(); |
| 3463 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 3526 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3464 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | 3527 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3465 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); | 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 | try self.register_manager.getReg(.rdi, null); | 3531 | try self.register_manager.getReg(.rdi, null); |
| 3468 | self.register_manager.freezeRegs(&.{.rdi}); | | |
| 3469 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); | 3532 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| | 3533 | self.register_manager.freezeRegs(&.{.rdi}); |
| 3470 | | 3534 | |
| 3471 | info.return_value.stack_offset = stack_offset; | 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,15 +3717,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3653 | | 3717 | |
| 3654 | const result: MCValue = result: { | 3718 | const result: MCValue = result: { |
| 3655 | switch (info.return_value) { | 3719 | switch (info.return_value) { |
| 3656 | .register => |reg| { | 3720 | .register => { |
| 3657 | if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) { | 3721 | // Save function return value in a new register |
| 3658 | // Save function return value in a callee saved register | 3722 | break :result try self.copyToRegisterWithInstTracking( |
| 3659 | break :result try self.copyToRegisterWithInstTracking( | 3723 | inst, |
| 3660 | inst, | 3724 | self.air.typeOfIndex(inst), |
| 3661 | self.air.typeOfIndex(inst), | 3725 | info.return_value, |
| 3662 | info.return_value, | 3726 | ); |
| 3663 | ); | | |
| 3664 | } | | |
| 3665 | }, | 3727 | }, |
| 3666 | else => {}, | 3728 | else => {}, |
| 3667 | } | 3729 | } |
| ... | @@ -3688,19 +3750,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3688,19 +3750,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 3688 | const ret_ty = self.fn_type.fnReturnType(); | 3750 | const ret_ty = self.fn_type.fnReturnType(); |
| 3689 | switch (self.ret_mcv) { | 3751 | switch (self.ret_mcv) { |
| 3690 | .stack_offset => { | 3752 | .stack_offset => { |
| 3691 | // TODO audit register allocation! | 3753 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3692 | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); | 3754 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3693 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); | 3755 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3694 | const reg = try self.register_manager.allocReg(null); | 3756 | self.register_manager.freezeRegs(&.{reg}); |
| 3695 | const backpatch = try self.addInst(.{ | 3757 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 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); | | |
| 3704 | try self.genSetStack(ret_ty, 0, operand, .{ | 3758 | try self.genSetStack(ret_ty, 0, operand, .{ |
| 3705 | .source_stack_base = .rbp, | 3759 | .source_stack_base = .rbp, |
| 3706 | .dest_stack_base = reg, | 3760 | .dest_stack_base = reg, |
| ... | @@ -3731,19 +3785,11 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3731,19 +3785,11 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3731 | const elem_ty = ptr_ty.elemType(); | 3785 | const elem_ty = ptr_ty.elemType(); |
| 3732 | switch (self.ret_mcv) { | 3786 | switch (self.ret_mcv) { |
| 3733 | .stack_offset => { | 3787 | .stack_offset => { |
| 3734 | // TODO audit register allocation! | 3788 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3735 | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); | 3789 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3736 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); | 3790 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3737 | const reg = try self.register_manager.allocReg(null); | 3791 | self.register_manager.freezeRegs(&.{reg}); |
| 3738 | const backpatch = try self.addInst(.{ | 3792 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 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); | | |
| 3747 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, ptr, .{ .immediate = elem_ty.abiSize(self.target.*) }, .{ | 3793 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, ptr, .{ .immediate = elem_ty.abiSize(self.target.*) }, .{ |
| 3748 | .source_stack_base = .rbp, | 3794 | .source_stack_base = .rbp, |
| 3749 | .dest_stack_base = reg, | 3795 | .dest_stack_base = reg, |
| ... | @@ -5033,6 +5079,7 @@ const InlineMemcpyOpts = struct { | ... | @@ -5033,6 +5079,7 @@ const InlineMemcpyOpts = struct { |
| 5033 | dest_stack_base: ?Register = null, | 5079 | dest_stack_base: ?Register = null, |
| 5034 | }; | 5080 | }; |
| 5035 | | 5081 | |
| | 5082 | /// Spills .rax and .rcx. |
| 5036 | fn genInlineMemcpy( | 5083 | fn genInlineMemcpy( |
| 5037 | self: *Self, | 5084 | self: *Self, |
| 5038 | dst_ptr: MCValue, | 5085 | dst_ptr: MCValue, |
| ... | @@ -5040,13 +5087,7 @@ fn genInlineMemcpy( | ... | @@ -5040,13 +5087,7 @@ fn genInlineMemcpy( |
| 5040 | len: MCValue, | 5087 | len: MCValue, |
| 5041 | opts: InlineMemcpyOpts, | 5088 | opts: InlineMemcpyOpts, |
| 5042 | ) InnerError!void { | 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 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); | 5090 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 5049 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); | | |
| 5050 | | 5091 | |
| 5051 | if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); | 5092 | if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 5052 | defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); | 5093 | defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| ... | @@ -5086,7 +5127,6 @@ fn genInlineMemcpy( | ... | @@ -5086,7 +5127,6 @@ fn genInlineMemcpy( |
| 5086 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); | 5127 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| 5087 | }, | 5128 | }, |
| 5088 | } | 5129 | } |
| 5089 | | | |
| 5090 | self.register_manager.freezeRegs(&.{dst_addr_reg}); | 5130 | self.register_manager.freezeRegs(&.{dst_addr_reg}); |
| 5091 | defer self.register_manager.unfreezeRegs(&.{dst_addr_reg}); | 5131 | defer self.register_manager.unfreezeRegs(&.{dst_addr_reg}); |
| 5092 | | 5132 | |
| ... | @@ -5122,7 +5162,6 @@ fn genInlineMemcpy( | ... | @@ -5122,7 +5162,6 @@ fn genInlineMemcpy( |
| 5122 | return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr}); | 5162 | return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr}); |
| 5123 | }, | 5163 | }, |
| 5124 | } | 5164 | } |
| 5125 | | | |
| 5126 | self.register_manager.freezeRegs(&.{src_addr_reg}); | 5165 | self.register_manager.freezeRegs(&.{src_addr_reg}); |
| 5127 | defer self.register_manager.unfreezeRegs(&.{src_addr_reg}); | 5166 | defer self.register_manager.unfreezeRegs(&.{src_addr_reg}); |
| 5128 | | 5167 | |
| ... | @@ -5130,6 +5169,11 @@ fn genInlineMemcpy( | ... | @@ -5130,6 +5169,11 @@ fn genInlineMemcpy( |
| 5130 | const count_reg = regs[0].to64(); | 5169 | const count_reg = regs[0].to64(); |
| 5131 | const tmp_reg = regs[1].to8(); | 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 | try self.genSetReg(Type.usize, count_reg, len); | 5177 | try self.genSetReg(Type.usize, count_reg, len); |
| 5134 | | 5178 | |
| 5135 | // mov rcx, 0 | 5179 | // mov rcx, 0 |
| ... | @@ -5225,6 +5269,7 @@ fn genInlineMemcpy( | ... | @@ -5225,6 +5269,7 @@ fn genInlineMemcpy( |
| 5225 | try self.performReloc(loop_reloc); | 5269 | try self.performReloc(loop_reloc); |
| 5226 | } | 5270 | } |
| 5227 | | 5271 | |
| | 5272 | /// Spills .rax register. |
| 5228 | fn genInlineMemset( | 5273 | fn genInlineMemset( |
| 5229 | self: *Self, | 5274 | self: *Self, |
| 5230 | dst_ptr: MCValue, | 5275 | dst_ptr: MCValue, |
| ... | @@ -5232,9 +5277,7 @@ fn genInlineMemset( | ... | @@ -5232,9 +5277,7 @@ fn genInlineMemset( |
| 5232 | len: MCValue, | 5277 | len: MCValue, |
| 5233 | opts: InlineMemcpyOpts, | 5278 | opts: InlineMemcpyOpts, |
| 5234 | ) InnerError!void { | 5279 | ) InnerError!void { |
| 5235 | try self.register_manager.getReg(.rax, null); | | |
| 5236 | self.register_manager.freezeRegs(&.{.rax}); | 5280 | self.register_manager.freezeRegs(&.{.rax}); |
| 5237 | defer self.register_manager.unfreezeRegs(&.{.rax}); | | |
| 5238 | | 5281 | |
| 5239 | const addr_reg = try self.register_manager.allocReg(null); | 5282 | const addr_reg = try self.register_manager.allocReg(null); |
| 5240 | switch (dst_ptr) { | 5283 | switch (dst_ptr) { |
| ... | @@ -5271,6 +5314,9 @@ fn genInlineMemset( | ... | @@ -5271,6 +5314,9 @@ fn genInlineMemset( |
| 5271 | self.register_manager.freezeRegs(&.{addr_reg}); | 5314 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 5272 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | 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 | try self.genSetReg(Type.usize, .rax, len); | 5320 | try self.genSetReg(Type.usize, .rax, len); |
| 5275 | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); | 5321 | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| 5276 | | 5322 | |