| ... | ... | @@ -34,7 +34,10 @@ const Register = bits.Register; |
| 34 | 34 | const RegisterManager = abi.RegisterManager; |
| 35 | 35 | const RegisterLock = RegisterManager.RegisterLock; |
| 36 | 36 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 37 | /// General Purpose |
| 37 | 38 | const gp = abi.RegisterClass.gp; |
| 39 | /// Function Args |
| 40 | const fa = abi.RegisterClass.fa; |
| 38 | 41 | |
| 39 | 42 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 40 | 43 | |
| ... | ... | @@ -297,6 +300,7 @@ pub fn generate( |
| 297 | 300 | .prev_di_pc = 0, |
| 298 | 301 | .prev_di_line = func.lbrace_line, |
| 299 | 302 | .prev_di_column = func.lbrace_column, |
| 303 | .stack_size = @max(32, function.max_end_stack), |
| 300 | 304 | }; |
| 301 | 305 | defer emit.deinit(); |
| 302 | 306 | |
| ... | ... | @@ -349,14 +353,9 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 349 | 353 | } |
| 350 | 354 | |
| 351 | 355 | fn gen(self: *Self) !void { |
| 352 | | const mod = self.bin_file.comp.module.?; |
| 353 | | const cc = self.fn_type.fnCallingConvention(mod); |
| 354 | | |
| 355 | | if (cc == .Naked) return self.fail("TODO: gen support callconv(.{s})", .{@tagName(cc)}); |
| 356 | | |
| 357 | 356 | _ = try self.addInst(.{ |
| 358 | 357 | .tag = .psuedo_prologue, |
| 359 | | .data = .{ .imm12 = 0 }, // Backpatched later. |
| 358 | .data = .{ .nop = {} }, // Backpatched later. |
| 360 | 359 | }); |
| 361 | 360 | |
| 362 | 361 | _ = try self.addInst(.{ |
| ... | ... | @@ -366,32 +365,6 @@ fn gen(self: *Self) !void { |
| 366 | 365 | |
| 367 | 366 | try self.genBody(self.air.getMainBody()); |
| 368 | 367 | |
| 369 | | // Backpatch prologue stack size |
| 370 | | if (math.cast(i12, self.max_end_stack)) |casted_stack_size| { |
| 371 | | self.mir_instructions.items(.data)[0].imm12 = casted_stack_size; |
| 372 | | } else return self.fail("TODO support larger stack sizes, got {}", .{self.max_end_stack}); |
| 373 | | |
| 374 | | _ = try self.addInst(.{ |
| 375 | | .tag = .dbg_epilogue_begin, |
| 376 | | .data = .{ .nop = {} }, |
| 377 | | }); |
| 378 | | |
| 379 | | // exitlude jumps |
| 380 | | if (self.exitlude_jump_relocs.items.len > 0 and |
| 381 | | self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2) |
| 382 | | { |
| 383 | | // If the last Mir instruction (apart from the |
| 384 | | // dbg_epilogue_begin) is the last exitlude jump |
| 385 | | // relocation (which would just jump one instruction |
| 386 | | // further), it can be safely removed |
| 387 | | self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop()); |
| 388 | | } |
| 389 | | |
| 390 | | for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 391 | | _ = jmp_reloc; |
| 392 | | return self.fail("TODO add branches in RISCV64", .{}); |
| 393 | | } |
| 394 | | |
| 395 | 368 | // Drop them off at the rbrace. |
| 396 | 369 | _ = try self.addInst(.{ |
| 397 | 370 | .tag = .dbg_line, |
| ... | ... | @@ -501,7 +474,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 501 | 474 | .fpext => try self.airFpext(inst), |
| 502 | 475 | .intcast => try self.airIntCast(inst), |
| 503 | 476 | .trunc => try self.airTrunc(inst), |
| 504 | | .int_from_bool => try self.airIntFromBool(inst), |
| 477 | .int_from_bool => try self.airIntFromBool(inst), |
| 505 | 478 | .is_non_null => try self.airIsNonNull(inst), |
| 506 | 479 | .is_non_null_ptr => try self.airIsNonNullPtr(inst), |
| 507 | 480 | .is_null => try self.airIsNull(inst), |
| ... | ... | @@ -513,17 +486,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 513 | 486 | .load => try self.airLoad(inst), |
| 514 | 487 | .loop => try self.airLoop(inst), |
| 515 | 488 | .not => try self.airNot(inst), |
| 516 | | .int_from_ptr => try self.airIntFromPtr(inst), |
| 517 | | .ret => try self.airRet(inst), |
| 518 | | .ret_safe => try self.airRet(inst), // TODO |
| 489 | .int_from_ptr => try self.airIntFromPtr(inst), |
| 490 | .ret => try self.airRet(inst, false), |
| 491 | .ret_safe => try self.airRet(inst, true), |
| 519 | 492 | .ret_load => try self.airRetLoad(inst), |
| 520 | 493 | .store => try self.airStore(inst, false), |
| 521 | 494 | .store_safe => try self.airStore(inst, true), |
| 522 | 495 | .struct_field_ptr=> try self.airStructFieldPtr(inst), |
| 523 | 496 | .struct_field_val=> try self.airStructFieldVal(inst), |
| 524 | 497 | .array_to_slice => try self.airArrayToSlice(inst), |
| 525 | | .float_from_int => try self.airFloatFromInt(inst), |
| 526 | | .int_from_float => try self.airIntFromFloat(inst), |
| 498 | .float_from_int => try self.airFloatFromInt(inst), |
| 499 | .int_from_float => try self.airIntFromFloat(inst), |
| 527 | 500 | .cmpxchg_strong => try self.airCmpxchg(inst), |
| 528 | 501 | .cmpxchg_weak => try self.airCmpxchg(inst), |
| 529 | 502 | .atomic_rmw => try self.airAtomicRmw(inst), |
| ... | ... | @@ -792,6 +765,7 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa |
| 792 | 765 | |
| 793 | 766 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 794 | 767 | const stack_offset = try self.allocMemPtr(inst); |
| 768 | log.debug("airAlloc offset: {}", .{stack_offset}); |
| 795 | 769 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); |
| 796 | 770 | } |
| 797 | 771 | |
| ... | ... | @@ -1468,30 +1442,30 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind |
| 1468 | 1442 | return true; |
| 1469 | 1443 | } |
| 1470 | 1444 | |
| 1471 | | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 1445 | fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 1472 | 1446 | const mod = self.bin_file.comp.module.?; |
| 1473 | 1447 | const elem_ty = ptr_ty.childType(mod); |
| 1474 | 1448 | |
| 1475 | | switch (ptr) { |
| 1449 | switch (src_ptr) { |
| 1476 | 1450 | .none => unreachable, |
| 1477 | 1451 | .undef => unreachable, |
| 1478 | 1452 | .unreach => unreachable, |
| 1479 | 1453 | .dead => unreachable, |
| 1480 | | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1481 | | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1482 | | .register => |src_reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = src_reg }), |
| 1454 | .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1455 | .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1456 | .register => try self.setValue(elem_ty, dst_mcv, src_ptr), |
| 1483 | 1457 | .memory, |
| 1484 | 1458 | .stack_offset, |
| 1485 | 1459 | => { |
| 1486 | 1460 | const reg = try self.register_manager.allocReg(null, gp); |
| 1487 | 1461 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 1488 | | defer self.register_manager.unlockReg(reg_lock); |
| 1462 | errdefer self.register_manager.unlockReg(reg_lock); |
| 1489 | 1463 | |
| 1490 | | try self.genSetReg(ptr_ty, reg, ptr); |
| 1464 | try self.genSetReg(ptr_ty, reg, src_ptr); |
| 1491 | 1465 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 1492 | 1466 | }, |
| 1493 | 1467 | .load_symbol => { |
| 1494 | | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 1468 | const reg = try self.copyToTmpRegister(ptr_ty, src_ptr); |
| 1495 | 1469 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 1496 | 1470 | }, |
| 1497 | 1471 | } |
| ... | ... | @@ -1524,34 +1498,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1524 | 1498 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1525 | 1499 | } |
| 1526 | 1500 | |
| 1527 | | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void { |
| 1501 | fn store(self: *Self, dst_ptr: MCValue, src_val: MCValue, ptr_ty: Type, value_ty: Type) !void { |
| 1528 | 1502 | _ = ptr_ty; |
| 1529 | 1503 | |
| 1530 | | log.debug("storing {s}", .{@tagName(ptr)}); |
| 1504 | log.debug("storing {s}", .{@tagName(dst_ptr)}); |
| 1531 | 1505 | |
| 1532 | | switch (ptr) { |
| 1506 | switch (dst_ptr) { |
| 1533 | 1507 | .none => unreachable, |
| 1534 | 1508 | .undef => unreachable, |
| 1535 | 1509 | .unreach => unreachable, |
| 1536 | 1510 | .dead => unreachable, |
| 1537 | | .immediate => |imm| { |
| 1538 | | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 1539 | | }, |
| 1540 | | .ptr_stack_offset => |off| { |
| 1541 | | try self.genSetStack(value_ty, off, value); |
| 1542 | | }, |
| 1543 | | .register => { |
| 1544 | | return self.fail("TODO implement storing to MCValue.register", .{}); |
| 1545 | | }, |
| 1546 | | .memory => { |
| 1547 | | return self.fail("TODO implement storing to MCValue.memory", .{}); |
| 1548 | | }, |
| 1549 | | .stack_offset => { |
| 1550 | | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); |
| 1551 | | }, |
| 1552 | | .load_symbol => { |
| 1553 | | return self.fail("TODO implement storing to MCValue.load_symbol", .{}); |
| 1554 | | }, |
| 1511 | .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, src_val), |
| 1512 | else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(dst_ptr)}), |
| 1555 | 1513 | } |
| 1556 | 1514 | } |
| 1557 | 1515 | |
| ... | ... | @@ -1629,29 +1587,32 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { |
| 1629 | 1587 | } |
| 1630 | 1588 | |
| 1631 | 1589 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1632 | | const arg_index = self.arg_index; |
| 1633 | | self.arg_index += 1; |
| 1590 | var arg_index = self.arg_index; |
| 1634 | 1591 | |
| 1635 | | const ty = self.typeOfIndex(inst); |
| 1636 | | _ = ty; |
| 1592 | // we skip over args that have no bits |
| 1593 | while (self.args[arg_index] == .none) arg_index += 1; |
| 1594 | self.arg_index = arg_index + 1; |
| 1637 | 1595 | |
| 1638 | | const result = self.args[arg_index]; |
| 1639 | | // TODO support stack-only arguments |
| 1640 | | // TODO Copy registers to the stack |
| 1641 | | const mcv = result; |
| 1642 | | try self.genArgDbgInfo(inst, mcv); |
| 1596 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1597 | const arg_ty = self.typeOfIndex(inst); |
| 1598 | _ = arg_ty; |
| 1599 | const src_mcv = self.args[arg_index]; |
| 1643 | 1600 | |
| 1644 | | if (self.liveness.isUnused(inst)) |
| 1645 | | return self.finishAirBookkeeping(); |
| 1601 | const dst_mcv = switch (src_mcv) { |
| 1602 | .register => |src_reg| dst: { |
| 1603 | self.register_manager.getRegAssumeFree(src_reg, inst); |
| 1604 | break :dst src_mcv; |
| 1605 | }, |
| 1606 | // don't need to allocate anything, can just be used immediately. |
| 1607 | .stack_offset => src_mcv, |
| 1608 | else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}), |
| 1609 | }; |
| 1646 | 1610 | |
| 1647 | | switch (mcv) { |
| 1648 | | .register => |reg| { |
| 1649 | | self.register_manager.getRegAssumeFree(reg, inst); |
| 1650 | | }, |
| 1651 | | else => {}, |
| 1652 | | } |
| 1611 | try self.genArgDbgInfo(inst, src_mcv); |
| 1612 | break :result dst_mcv; |
| 1613 | }; |
| 1653 | 1614 | |
| 1654 | | return self.finishAir(inst, mcv, .{ .none, .none, .none }); |
| 1615 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 1655 | 1616 | } |
| 1656 | 1617 | |
| 1657 | 1618 | fn airTrap(self: *Self) !void { |
| ... | ... | @@ -1704,26 +1665,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1704 | 1665 | const arg = args[arg_i]; |
| 1705 | 1666 | const arg_ty = self.typeOf(arg); |
| 1706 | 1667 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 1707 | | |
| 1708 | | switch (mc_arg) { |
| 1709 | | .none => continue, |
| 1710 | | .undef => unreachable, |
| 1711 | | .immediate => unreachable, |
| 1712 | | .unreach => unreachable, |
| 1713 | | .dead => unreachable, |
| 1714 | | .memory => unreachable, |
| 1715 | | .register => |reg| { |
| 1716 | | try self.register_manager.getReg(reg, null); |
| 1717 | | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 1718 | | }, |
| 1719 | | .stack_offset => |off| try self.genSetStack(arg_ty, off, arg_mcv), |
| 1720 | | .ptr_stack_offset => { |
| 1721 | | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 1722 | | }, |
| 1723 | | .load_symbol => { |
| 1724 | | return self.fail("TODO implement calling with MCValue.load_symbol", .{}); |
| 1725 | | }, |
| 1726 | | } |
| 1668 | try self.setValue(arg_ty, mc_arg, arg_mcv); |
| 1727 | 1669 | } |
| 1728 | 1670 | |
| 1729 | 1671 | if (try self.air.value(callee, mod)) |func_value| { |
| ... | ... | @@ -1791,19 +1733,39 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1791 | 1733 | fn ret(self: *Self, mcv: MCValue) !void { |
| 1792 | 1734 | const mod = self.bin_file.comp.module.?; |
| 1793 | 1735 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 1794 | | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1736 | try self.setValue(ret_ty, self.ret_mcv, mcv); |
| 1737 | |
| 1795 | 1738 | // Just add space for an instruction, patch this later |
| 1796 | 1739 | const index = try self.addInst(.{ |
| 1797 | | .tag = .nop, |
| 1740 | .tag = .ret, |
| 1798 | 1741 | .data = .{ .nop = {} }, |
| 1799 | 1742 | }); |
| 1743 | |
| 1800 | 1744 | try self.exitlude_jump_relocs.append(self.gpa, index); |
| 1801 | 1745 | } |
| 1802 | 1746 | |
| 1803 | | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 1747 | fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 1748 | if (safety) { |
| 1749 | // safe |
| 1750 | } else { |
| 1751 | // not safe |
| 1752 | } |
| 1753 | |
| 1804 | 1754 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 1805 | 1755 | const operand = try self.resolveInst(un_op); |
| 1756 | |
| 1757 | _ = try self.addInst(.{ |
| 1758 | .tag = .dbg_epilogue_begin, |
| 1759 | .data = .{ .nop = {} }, |
| 1760 | }); |
| 1761 | |
| 1762 | _ = try self.addInst(.{ |
| 1763 | .tag = .psuedo_epilogue, |
| 1764 | .data = .{ .nop = {} }, |
| 1765 | }); |
| 1766 | |
| 1806 | 1767 | try self.ret(operand); |
| 1768 | |
| 1807 | 1769 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 1808 | 1770 | } |
| 1809 | 1771 | |
| ... | ... | @@ -1983,7 +1945,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1983 | 1945 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 1984 | 1946 | // TODO make sure the destination stack offset / register does not already have something |
| 1985 | 1947 | // going on there. |
| 1986 | | try self.setRegOrMem(self.typeOfIndex(else_key), canon_mcv, else_value); |
| 1948 | try self.setValue(self.typeOfIndex(else_key), canon_mcv, else_value); |
| 1987 | 1949 | // TODO track the new register / stack allocation |
| 1988 | 1950 | } |
| 1989 | 1951 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); |
| ... | ... | @@ -2010,7 +1972,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2010 | 1972 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 2011 | 1973 | // TODO make sure the destination stack offset / register does not already have something |
| 2012 | 1974 | // going on there. |
| 2013 | | try self.setRegOrMem(self.typeOfIndex(then_key), parent_mcv, then_value); |
| 1975 | try self.setValue(self.typeOfIndex(then_key), parent_mcv, then_value); |
| 2014 | 1976 | // TODO track the new register / stack allocation |
| 2015 | 1977 | } |
| 2016 | 1978 | |
| ... | ... | @@ -2195,7 +2157,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 2195 | 2157 | /// Send control flow to the `index` of `self.code`. |
| 2196 | 2158 | fn jump(self: *Self, index: Mir.Inst.Index) !void { |
| 2197 | 2159 | _ = try self.addInst(.{ |
| 2198 | | .tag = .psuedo_jump, |
| 2160 | .tag = .j, |
| 2199 | 2161 | .data = .{ |
| 2200 | 2162 | .inst = index, |
| 2201 | 2163 | }, |
| ... | ... | @@ -2270,7 +2232,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 2270 | 2232 | if (block_mcv == .none) { |
| 2271 | 2233 | block_data.mcv = operand_mcv; |
| 2272 | 2234 | } else { |
| 2273 | | try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv); |
| 2235 | try self.setValue(self.typeOfIndex(block), block_mcv, operand_mcv); |
| 2274 | 2236 | } |
| 2275 | 2237 | } |
| 2276 | 2238 | return self.brVoid(block); |
| ... | ... | @@ -2415,28 +2377,32 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT |
| 2415 | 2377 | } |
| 2416 | 2378 | |
| 2417 | 2379 | /// Sets the value without any modifications to register allocation metadata or stack allocation metadata. |
| 2418 | | fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| 2419 | | if (!loc.isMutable()) { |
| 2420 | | return std.debug.panic("tried to setRegOrMem immutable: {s}", .{@tagName(loc)}); |
| 2380 | fn setValue(self: *Self, ty: Type, dst_val: MCValue, src_val: MCValue) !void { |
| 2381 | // There isn't anything to store |
| 2382 | if (dst_val == .none) return; |
| 2383 | |
| 2384 | if (!dst_val.isMutable()) { |
| 2385 | return std.debug.panic("tried to setValue immutable: {s}", .{@tagName(dst_val)}); |
| 2421 | 2386 | } |
| 2422 | 2387 | |
| 2423 | | switch (loc) { |
| 2424 | | .none => return, |
| 2425 | | .register => |reg| return self.genSetReg(ty, reg, val), |
| 2426 | | .stack_offset => |off| return self.genSetStack(ty, off, val), |
| 2427 | | else => return self.fail("TODO: setRegOrMem {s}", .{@tagName(loc)}), |
| 2388 | switch (dst_val) { |
| 2389 | .register => |reg| return self.genSetReg(ty, reg, src_val), |
| 2390 | .stack_offset => |off| return self.genSetStack(ty, off, src_val), |
| 2391 | .memory => |addr| return self.genSetMem(ty, addr, src_val), |
| 2392 | else => return self.fail("TODO: setValue {s}", .{@tagName(dst_val)}), |
| 2428 | 2393 | } |
| 2429 | 2394 | } |
| 2430 | 2395 | |
| 2431 | | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 2396 | /// Sets the value of `src_val` into stack memory at `stack_offset`. |
| 2397 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) InnerError!void { |
| 2432 | 2398 | const mod = self.bin_file.comp.module.?; |
| 2433 | 2399 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 2434 | 2400 | |
| 2435 | | switch (mcv) { |
| 2401 | switch (src_val) { |
| 2436 | 2402 | .none => return, |
| 2437 | 2403 | .dead => unreachable, |
| 2438 | 2404 | .immediate => { |
| 2439 | | const reg = try self.copyToTmpRegister(ty, mcv); |
| 2405 | const reg = try self.copyToTmpRegister(ty, src_val); |
| 2440 | 2406 | return self.genSetStack(ty, stack_offset, .{ .register = reg }); |
| 2441 | 2407 | }, |
| 2442 | 2408 | .register => |reg| { |
| ... | ... | @@ -2456,8 +2422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2456 | 2422 | .tag = tag, |
| 2457 | 2423 | .data = .{ .i_type = .{ |
| 2458 | 2424 | .rd = reg, |
| 2459 | | .rs1 = .sp, |
| 2460 | | .imm12 = @intCast(stack_offset), |
| 2425 | .rs1 = .s0, |
| 2426 | .imm12 = math.cast(i12, stack_offset) orelse { |
| 2427 | return self.fail("TODO: genSetStack bigger stack values", .{}); |
| 2428 | }, |
| 2461 | 2429 | } }, |
| 2462 | 2430 | }); |
| 2463 | 2431 | }, |
| ... | ... | @@ -2466,7 +2434,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2466 | 2434 | }, |
| 2467 | 2435 | .stack_offset, .load_symbol => { |
| 2468 | 2436 | if (abi_size <= 8) { |
| 2469 | | const reg = try self.copyToTmpRegister(ty, mcv); |
| 2437 | const reg = try self.copyToTmpRegister(ty, src_val); |
| 2470 | 2438 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 2471 | 2439 | } |
| 2472 | 2440 | |
| ... | ... | @@ -2485,7 +2453,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2485 | 2453 | const count_reg = regs[3]; |
| 2486 | 2454 | const tmp_reg = regs[4]; |
| 2487 | 2455 | |
| 2488 | | switch (mcv) { |
| 2456 | switch (src_val) { |
| 2489 | 2457 | .stack_offset => |offset| { |
| 2490 | 2458 | if (offset == stack_offset) return; |
| 2491 | 2459 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset }); |
| ... | ... | @@ -2511,7 +2479,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2511 | 2479 | }, |
| 2512 | 2480 | }); |
| 2513 | 2481 | }, |
| 2514 | | else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(mcv)}), |
| 2482 | else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(src_val)}), |
| 2515 | 2483 | } |
| 2516 | 2484 | |
| 2517 | 2485 | try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = stack_offset }); |
| ... | ... | @@ -2520,10 +2488,20 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2520 | 2488 | // memcpy(src, dst, len) |
| 2521 | 2489 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 2522 | 2490 | }, |
| 2523 | | else => return self.fail("TODO: genSetStack {s}", .{@tagName(mcv)}), |
| 2491 | else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)}), |
| 2524 | 2492 | } |
| 2525 | 2493 | } |
| 2526 | 2494 | |
| 2495 | fn genSetMem(self: *Self, ty: Type, addr: u64, src_val: MCValue) InnerError!void { |
| 2496 | const mod = self.bin_file.comp.module.?; |
| 2497 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 2498 | _ = abi_size; |
| 2499 | _ = addr; |
| 2500 | _ = src_val; |
| 2501 | |
| 2502 | return self.fail("TODO: genSetMem", .{}); |
| 2503 | } |
| 2504 | |
| 2527 | 2505 | fn genInlineMemcpy( |
| 2528 | 2506 | self: *Self, |
| 2529 | 2507 | src: Register, |
| ... | ... | @@ -2541,11 +2519,12 @@ fn genInlineMemcpy( |
| 2541 | 2519 | return self.fail("TODO: genInlineMemcpy", .{}); |
| 2542 | 2520 | } |
| 2543 | 2521 | |
| 2544 | | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 2522 | /// Sets the value of `src_val` into `reg`. Assumes you have a lock on it. |
| 2523 | fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!void { |
| 2545 | 2524 | const mod = self.bin_file.comp.module.?; |
| 2546 | 2525 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 2547 | 2526 | |
| 2548 | | switch (mcv) { |
| 2527 | switch (src_val) { |
| 2549 | 2528 | .dead => unreachable, |
| 2550 | 2529 | .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}), |
| 2551 | 2530 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -2634,8 +2613,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2634 | 2613 | .tag = tag, |
| 2635 | 2614 | .data = .{ .i_type = .{ |
| 2636 | 2615 | .rd = reg, |
| 2637 | | .rs1 = .sp, |
| 2638 | | .imm12 = @intCast(off), |
| 2616 | .rs1 = .s0, |
| 2617 | .imm12 = math.cast(i12, off) orelse { |
| 2618 | return self.fail("TODO: genSetReg support larger stack sizes", .{}); |
| 2619 | }, |
| 2639 | 2620 | } }, |
| 2640 | 2621 | }); |
| 2641 | 2622 | }, |
| ... | ... | @@ -2685,7 +2666,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2685 | 2666 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2686 | 2667 | |
| 2687 | 2668 | const dest = try self.allocRegOrMem(inst, true); |
| 2688 | | try self.setRegOrMem(self.typeOfIndex(inst), dest, operand); |
| 2669 | try self.setValue(self.typeOfIndex(inst), dest, operand); |
| 2689 | 2670 | break :result dest; |
| 2690 | 2671 | }; |
| 2691 | 2672 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -2912,7 +2893,6 @@ const CallMCValues = struct { |
| 2912 | 2893 | /// Caller must call `CallMCValues.deinit`. |
| 2913 | 2894 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2914 | 2895 | const mod = self.bin_file.comp.module.?; |
| 2915 | | const ip = &mod.intern_pool; |
| 2916 | 2896 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 2917 | 2897 | const cc = fn_info.cc; |
| 2918 | 2898 | var result: CallMCValues = .{ |
| ... | ... | @@ -2935,21 +2915,20 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2935 | 2915 | return result; |
| 2936 | 2916 | }, |
| 2937 | 2917 | .Unspecified, .C => { |
| 2938 | | // LP64D ABI |
| 2939 | | // |
| 2940 | | // TODO make this generic with other ABIs, in particular |
| 2941 | | // with different hardware floating-point calling |
| 2942 | | // conventions |
| 2943 | | var stack_offset: u32 = 0; |
| 2944 | | |
| 2945 | | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 2946 | | const param_type = Type.fromInterned(ty); |
| 2947 | | const param_size: u32 = @intCast(param_type.abiSize(mod)); |
| 2918 | if (result.args.len > 8) { |
| 2919 | return self.fail("TODO: support more than 8 function args", .{}); |
| 2920 | } |
| 2948 | 2921 | |
| 2949 | | result_arg.* = .{ .stack_offset = stack_offset }; |
| 2950 | | stack_offset += param_size; |
| 2922 | for (0..result.args.len) |i| { |
| 2923 | const arg_reg = try self.register_manager.allocReg(null, fa); |
| 2924 | result.args[i] = .{ .register = arg_reg }; |
| 2951 | 2925 | } |
| 2952 | 2926 | |
| 2927 | // stack_offset = num s registers spilled + local var space |
| 2928 | var stack_offset: u32 = 0; |
| 2929 | _ = &stack_offset; |
| 2930 | // TODO: spill used s registers here |
| 2931 | |
| 2953 | 2932 | result.stack_byte_count = stack_offset; |
| 2954 | 2933 | result.stack_align = .@"16"; |
| 2955 | 2934 | }, |