╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Zcu.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2144 return tree.nodeToSpan(elem_node); 2145 } else if (tree.fullStructInit(&buf, init_node)) |full| { 2146 const field_node = full.ast.fields[init_elem.elem_index]; 2147 return tree.tokensToSpan( 2148 tree.firstToken(field_node) - 3, 2149 tree.lastToken(field_node), 2150 tree.nodeMainToken(field_node) - 2, 2151 ); 2152 } else unreachable; 2153 }, 2154 .init_field_name, 2155 .init_field_linkage, 2156 .init_field_section, 2157 .init_field_visibility, 2158 .init_field_rw, 2159 .init_field_locality, 2160 .init_field_cache, 2161 .init_field_library, 2162 .init_field_thread_local, 2163 .init_field_dll_import, 2164 .init_field_relocation, 2165 .init_field_decoration, 2166 => |builtin_call_node| { 2167 const wanted = switch (src_loc.lazy) { 2168 .init_field_name => "name", 2169 .init_field_linkage => "linkage", 2170 .init_field_section => "section", 2171 .init_field_visibility => "visibility", 2172 .init_field_rw => "rw", 2173 .init_field_locality => "locality", 2174 .init_field_cache => "cache", 2175 .init_field_library => "library", 2176 .init_field_thread_local => "thread_local", 2177 .init_field_dll_import => "dll_import", 2178 .init_field_relocation => "relocation", 2179 .init_field_decoration => "decoration", 2180 else => unreachable, 2181 }; 2182 const tree = try src_loc.file_scope.getTree(zcu); 2183 const node = builtin_call_node.toAbsolute(src_loc.base_node); 2184 var builtin_buf: [2]Ast.Node.Index = undefined; 2185 const args = tree.builtinCallParams(&builtin_buf, node).?; 2186 const arg_node = args[1]; 2187 var buf: [2]Ast.Node.Index = undefined; 2188 const full = tree.fullStructInit(&buf, arg_node) orelse 2189 return tree.nodeToSpan(arg_node); 2190 for (full.ast.fields) |field_node| { 2191 // . IDENTIFIER = field_node 2192 const name_token = tree.firstToken(field_node) - 2; 2193 const name = tree.tokenSlice(name_token); 2194 if (std.mem.eql(u8, name, wanted)) { 2195 return tree.tokensToSpan( 2196 name_token - 1, 2197 tree.lastToken(field_node), 2198 tree.nodeMainToken(field_node) - 2, 2199 ); 2200 } 2201 } 2202 return tree.nodeToSpan(arg_node); 2203 }, 2204 .switch_case_item, 2205 .switch_case_item_range_first, 2206 .switch_case_item_range_last, 2207 .switch_capture, 2208 .switch_tag_capture, 2209 => { 2210 const switch_node_offset, const want_case_idx = switch (src_loc.lazy) { 2211 .switch_case_item, 2212 .switch_case_item_range_first, 2213 .switch_case_item_range_last, 2214 => |x| .{ x.switch_node_offset, x.case_idx }, 2215 .switch_capture, 2216 .switch_tag_capture, 2217 => |x| .{ x.switch_node_offset, x.case_idx }, 2218 else => unreachable, 2219 }; 2220 2221 const tree = try src_loc.file_scope.getTree(zcu); 2222 const switch_node = switch_node_offset.toAbsolute(src_loc.base_node); 2223 _, const extra_index = tree.nodeData(switch_node).node_and_extra; 2224 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index); 2225 2226 var multi_i: u32 = 0; 2227 var scalar_i: u32 = 0; 2228 const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| { 2229 const case = tree.fullSwitchCase(case_node).?; 2230 if (case.ast.values.len == 0) { 2231 if (want_case_idx == Zir.UnwrappedSwitchBlock.Case.Index.@"else") { 2232 break :case case; 2233 } 2234 continue :case; 2235 } 2236 2237 const is_multi = case.ast.values.len != 1 or 2238 tree.nodeTag(case.ast.values[0]) == .switch_range; 2239 2240 switch (want_case_idx.kind) { 2241 .scalar => if (!is_multi and want_case_idx.value == scalar_i) 2242 break :case case, 2243 .multi => if (is_multi and want_case_idx.value == multi_i) 2244 break :case case, 2245 } 2246 2247 if (is_multi) { 2248 multi_i += 1; 2249 } else { 2250 scalar_i += 1; 2251 } 2252 } else unreachable; 2253 2254 const want_item_idx = switch (src_loc.lazy) { 2255 .switch_case_item, 2256 .switch_case_item_range_first, 2257 .switch_case_item_range_last, 2258 => |x| item_idx: { 2259 assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else"); 2260 break :item_idx x.item_idx; 2261 }, 2262 .switch_capture, .switch_tag_capture => { 2263 const start = switch (src_loc.lazy) { 2264 .switch_capture => case.payload_token.?, 2265 .switch_tag_capture => tok: { 2266 var tok = case.payload_token.?; 2267 if (tree.tokenTag(tok) == .asterisk) tok += 1; 2268 tok = tok + 2; // skip over comma 2269 break :tok tok; 2270 }, 2271 else => unreachable, 2272 }; 2273 const end = switch (tree.tokenTag(start)) { 2274 .asterisk => start + 1, 2275 else => start, 2276 }; 2277 return tree.tokensToSpan(start, end, start); 2278 }, 2279 else => unreachable, 2280 }; 2281 2282 switch (want_item_idx.kind) { 2283 .single => { 2284 var item_i: u32 = 0; 2285 for (case.ast.values) |item_node| { 2286 if (tree.nodeTag(item_node) == .switch_range) { 2287 continue; 2288 } 2289 if (item_i != want_item_idx.value) { 2290 item_i += 1; 2291 continue; 2292 } 2293 return tree.nodeToSpan(item_node); 2294 } else unreachable; 2295 }, 2296 .range => { 2297 var range_i: u32 = 0; 2298 for (case.ast.values) |item_node| { 2299 if (tree.nodeTag(item_node) != .switch_range) { 2300 continue; 2301 } 2302 if (range_i != want_item_idx.value) { 2303 range_i += 1; 2304 continue; 2305 } 2306 const first, const last = tree.nodeData(item_node).node_and_node; 2307 return switch (src_loc.lazy) { 2308 .switch_case_item => tree.nodeToSpan(item_node), 2309 .switch_case_item_range_first => tree.nodeToSpan(first), 2310 .switch_case_item_range_last => tree.nodeToSpan(last), 2311 else => unreachable, 2312 }; 2313 } else unreachable; 2314 }, 2315 } 2316 }, 2317 .func_decl_param_comptime => |param_idx| { 2318 const tree = try src_loc.file_scope.getTree(zcu); 2319 var buf: [1]Ast.Node.Index = undefined; 2320 const full = tree.fullFnProto(&buf, src_loc.base_node).?; 2321 var param_it = full.iterate(tree); 2322 for (0..param_idx) |_| assert(param_it.next() != null); 2323 const param = param_it.next().?; 2324 return tree.tokenToSpan(param.comptime_noalias.?); 2325 }, 2326 .func_decl_param_ty => |param_idx| { 2327 const tree = try src_loc.file_scope.getTree(zcu); 2328 var buf: [1]Ast.Node.Index = undefined; 2329 const full = tree.fullFnProto(&buf, src_loc.base_node).?; 2330 var param_it = full.iterate(tree); 2331 for (0..param_idx) |_| assert(param_it.next() != null); 2332 const param = param_it.next().?; 2333 if (param.anytype_ellipsis3) |tok| { 2334 return tree.tokenToSpan(tok); 2335 } else { 2336 return tree.nodeToSpan(param.type_expr.?); 2337 } 2338 }, 2339 } 2340 } 2341 }; 2342 2343 pub const LazySrcLoc = struct { 2344 /// This instruction provides the source node locations are resolved relative to. 2345 /// It is a `declaration`, `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl`. 2346 /// This must be valid even if `relative` is an absolute value, since it is required to 2347 /// determine the file which the `LazySrcLoc` refers to. 2348 base_node_inst: InternPool.TrackedInst.Index, 2349 /// This field determines the source location relative to `base_node_inst`. 2350 offset: Offset, 2351 2352 pub const Offset = union(enum) { 2353 /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting 2354 /// that all code paths which would need to resolve the source location are 2355 /// unreachable. If you are debugging this tag incorrectly being this value, 2356 /// look into using reverse-continue with a memory watchpoint to see where the 2357 /// value is being set to this tag. 2358 /// `base_node_inst` is unused. 2359 unneeded, 2360 /// The source location points to a byte offset within a source file, 2361 /// offset from 0. The source file is determined contextually. 2362 byte_abs: u32, 2363 /// The source location points to a token within a source file, 2364 /// offset from 0. The source file is determined contextually. 2365 token_abs: Ast.TokenIndex, 2366 /// The source location points to an AST node within a source file, 2367 /// offset from 0. The source file is determined contextually. 2368 node_abs: Ast.Node.Index, 2369 /// The source location points to a byte offset within a source file, 2370 /// offset from the byte offset of the base node within the file. 2371 byte_offset: u32, 2372 /// This data is the offset into the token list from the base node's first token. 2373 token_offset: Ast.TokenOffset, 2374 /// The source location points to an AST node, which is this value offset 2375 /// from its containing base node AST index. 2376 node_offset: TracedOffset, 2377 /// The source location points to the main token of an AST node, found 2378 /// by taking this AST node index offset from the containing base node. 2379 node_offset_main_token: Ast.Node.Offset, 2380 /// The source location points to the beginning of a struct initializer. 2381 node_offset_initializer: Ast.Node.Offset, 2382 /// The source location points to a variable declaration type expression, 2383 /// found by taking this AST node index offset from the containing 2384 /// base node, which points to a variable declaration AST node. Next, navigate 2385 /// to the type expression. 2386 node_offset_var_decl_ty: Ast.Node.Offset, 2387 /// The source location points to the alignment expression of a var decl. 2388 node_offset_var_decl_align: Ast.Node.Offset, 2389 /// The source location points to the linksection expression of a var decl. 2390 node_offset_var_decl_section: Ast.Node.Offset, 2391 /// The source location points to the addrspace expression of a var decl. 2392 node_offset_var_decl_addrspace: Ast.Node.Offset, 2393 /// The source location points to the initializer of a var decl. 2394 node_offset_var_decl_init: Ast.Node.Offset, 2395 /// The source location points to the given argument of a builtin function call. 2396 /// `builtin_call_node` points to the builtin call. 2397 /// `arg_index` is the index of the argument which hte source location refers to. 2398 node_offset_builtin_call_arg: struct { 2399 builtin_call_node: Ast.Node.Offset, 2400 arg_index: u32, 2401 }, 2402 /// Like `node_offset_builtin_call_arg` but recurses through arbitrarily many calls 2403 /// to pointer cast builtins (taking the first argument of the most nested). 2404 node_offset_ptrcast_operand: Ast.Node.Offset, 2405 /// The source location points to the index expression of an array access 2406 /// expression, found by taking this AST node index offset from the containing 2407 /// base node, which points to an array access AST node. Next, navigate 2408 /// to the index expression. 2409 node_offset_array_access_index: Ast.Node.Offset, 2410 /// The source location points to the LHS of a slice expression 2411 /// expression, found by taking this AST node index offset from the containing 2412 /// base node, which points to a slice AST node. Next, navigate 2413 /// to the sentinel expression. 2414 node_offset_slice_ptr: Ast.Node.Offset, 2415 /// The source location points to start expression of a slice expression 2416 /// expression, found by taking this AST node index offset from the containing 2417 /// base node, which points to a slice AST node. Next, navigate 2418 /// to the sentinel expression. 2419 node_offset_slice_start: Ast.Node.Offset, 2420 /// The source location points to the end expression of a slice 2421 /// expression, found by taking this AST node index offset from the containing 2422 /// base node, which points to a slice AST node. Next, navigate 2423 /// to the sentinel expression. 2424 node_offset_slice_end: Ast.Node.Offset, 2425 /// The source location points to the sentinel expression of a slice 2426 /// expression, found by taking this AST node index offset from the containing 2427 /// base node, which points to a slice AST node. Next, navigate 2428 /// to the sentinel expression. 2429 node_offset_slice_sentinel: Ast.Node.Offset, 2430 /// The source location points to the callee expression of a function 2431 /// call expression, found by taking this AST node index offset from the containing 2432 /// base node, which points to a function call AST node. Next, navigate 2433 /// to the callee expression. 2434 node_offset_call_func: Ast.Node.Offset, 2435 /// The payload is offset from the containing base node. 2436 /// The source location points to the field name of: 2437 /// * a field access expression (`a.b`), or 2438 /// * the callee of a method call (`a.b()`) 2439 node_offset_field_name: Ast.Node.Offset, 2440 /// The payload is offset from the containing base node. 2441 /// The source location points to the field name of the operand ("b" node) 2442 /// of a field initialization expression (`.a = b`) 2443 node_offset_field_name_init: Ast.Node.Offset, 2444 /// The source location points to the pointer of a pointer deref expression, 2445 /// found by taking this AST node index offset from the containing 2446 /// base node, which points to a pointer deref AST node. Next, navigate 2447 /// to the pointer expression. 2448 node_offset_deref_ptr: Ast.Node.Offset, 2449 /// The source location points to the assembly source code of an inline assembly 2450 /// expression, found by taking this AST node index offset from the containing 2451 /// base node, which points to inline assembly AST node. Next, navigate 2452 /// to the asm template source code. 2453 node_offset_asm_source: Ast.Node.Offset, 2454 /// The source location points to the return type of an inline assembly 2455 /// expression, found by taking this AST node index offset from the containing 2456 /// base node, which points to inline assembly AST node. Next, navigate 2457 /// to the return type expression. 2458 node_offset_asm_ret_ty: Ast.Node.Offset, 2459 /// The source location points to the condition expression of an if 2460 /// expression, found by taking this AST node index offset from the containing 2461 /// base node, which points to an if expression AST node. Next, navigate 2462 /// to the condition expression. 2463 node_offset_if_cond: Ast.Node.Offset, 2464 /// The source location points to a binary expression, such as `a + b`, found 2465 /// by taking this AST node index offset from the containing base node. 2466 node_offset_bin_op: Ast.Node.Offset, 2467 /// The source location points to the LHS of a binary expression, found 2468 /// by taking this AST node index offset from the containing base node, 2469 /// which points to a binary expression AST node. Next, navigate to the LHS. 2470 node_offset_bin_lhs: Ast.Node.Offset, 2471 /// The source location points to the RHS of a binary expression, found 2472 /// by taking this AST node index offset from the containing base node, 2473 /// which points to a binary expression AST node. Next, navigate to the RHS. 2474 node_offset_bin_rhs: Ast.Node.Offset, 2475 /// The source location points to the operand of a try expression, found 2476 /// by taking this AST node index offset from the containing base node, 2477 /// which points to a try expression AST node. Next, navigate to the 2478 /// operand expression. 2479 node_offset_try_operand: Ast.Node.Offset, 2480 /// The source location points to the operand of a switch expression, found 2481 /// by taking this AST node index offset from the containing base node, 2482 /// which points to a switch expression AST node. Next, navigate to the operand. 2483 node_offset_switch_operand: Ast.Node.Offset, 2484 /// The source location points to the else prong of a switch expression, found 2485 /// by taking this AST node index offset from the containing base node, 2486 /// which points to a switch expression AST node. Next, navigate to the else prong. 2487 node_offset_switch_else_prong: Ast.Node.Offset, 2488 /// The source location points to all the ranges of a switch expression, found 2489 /// by taking this AST node index offset from the containing base node, 2490 /// which points to a switch expression AST node. Next, navigate to any of the 2491 /// range nodes. The error applies to all of them. 2492 node_offset_switch_range: Ast.Node.Offset, 2493 /// The source location points to the align expr of a function type 2494 /// expression, found by taking this AST node index offset from the containing 2495 /// base node, which points to a function type AST node. Next, navigate to 2496 /// the calling convention node. 2497 node_offset_fn_type_align: Ast.Node.Offset, 2498 /// The source location points to the addrspace expr of a function type 2499 /// expression, found by taking this AST node index offset from the containing 2500 /// base node, which points to a function type AST node. Next, navigate to 2501 /// the calling convention node. 2502 node_offset_fn_type_addrspace: Ast.Node.Offset, 2503 /// The source location points to the linksection expr of a function type 2504 /// expression, found by taking this AST node index offset from the containing 2505 /// base node, which points to a function type AST node. Next, navigate to 2506 /// the calling convention node. 2507 node_offset_fn_type_section: Ast.Node.Offset, 2508 /// The source location points to the calling convention of a function type 2509 /// expression, found by taking this AST node index offset from the containing 2510 /// base node, which points to a function type AST node. Next, navigate to 2511 /// the calling convention node. 2512 node_offset_fn_type_cc: Ast.Node.Offset, 2513 /// The source location points to the return type of a function type 2514 /// expression, found by taking this AST node index offset from the containing 2515 /// base node, which points to a function type AST node. Next, navigate to 2516 /// the return type node. 2517 node_offset_fn_type_ret_ty: Ast.Node.Offset, 2518 node_offset_param: Ast.Node.Offset, 2519 token_offset_param: Ast.TokenOffset, 2520 /// The source location points to the type expression of an `anyframe->T` 2521 /// expression, found by taking this AST node index offset from the containing 2522 /// base node, which points to a `anyframe->T` expression AST node. Next, navigate 2523 /// to the type expression. 2524 node_offset_anyframe_type: Ast.Node.Offset, 2525 /// The source location points to the string literal of `extern "foo"`, found 2526 /// by taking this AST node index offset from the containing 2527 /// base node, which points to a function prototype or variable declaration 2528 /// expression AST node. Next, navigate to the string literal of the `extern "foo"`. 2529 node_offset_lib_name: Ast.Node.Offset, 2530 /// The source location points to the len expression of an `[N:S]T` 2531 /// expression, found by taking this AST node index offset from the containing 2532 /// base node, which points to an `[N:S]T` expression AST node. Next, navigate 2533 /// to the len expression. 2534 node_offset_array_type_len: Ast.Node.Offset, 2535 /// The source location points to the sentinel expression of an `[N:S]T` 2536 /// expression, found by taking this AST node index offset from the containing 2537 /// base node, which points to an `[N:S]T` expression AST node. Next, navigate 2538 /// to the sentinel expression. 2539 node_offset_array_type_sentinel: Ast.Node.Offset, 2540 /// The source location points to the elem expression of an `[N:S]T` 2541 /// expression, found by taking this AST node index offset from the containing 2542 /// base node, which points to an `[N:S]T` expression AST node. Next, navigate 2543 /// to the elem expression. 2544 node_offset_array_type_elem: Ast.Node.Offset, 2545 /// The source location points to the operand of an unary expression. 2546 node_offset_un_op: Ast.Node.Offset, 2547 /// The source location points to the elem type of a pointer. 2548 node_offset_ptr_elem: Ast.Node.Offset, 2549 /// The source location points to the sentinel of a pointer. 2550 node_offset_ptr_sentinel: Ast.Node.Offset, 2551 /// The source location points to the align expr of a pointer. 2552 node_offset_ptr_align: Ast.Node.Offset, 2553 /// The source location points to the addrspace expr of a pointer. 2554 node_offset_ptr_addrspace: Ast.Node.Offset, 2555 /// The source location points to the bit-offset of a pointer. 2556 node_offset_ptr_bitoffset: Ast.Node.Offset, 2557 /// The source location points to the host size of a pointer. 2558 node_offset_ptr_hostsize: Ast.Node.Offset, 2559 /// The source location points to the type of an array or struct initializer. 2560 node_offset_init_ty: Ast.Node.Offset, 2561 /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`). 2562 node_offset_store_ptr: Ast.Node.Offset, 2563 /// The source location points to the RHS of an assignment (or assign-op, e.g. `+=`). 2564 node_offset_store_operand: Ast.Node.Offset, 2565 /// The source location points to the operand of a `return` statement, or 2566 /// the `return` itself if there is no explicit operand. 2567 node_offset_return_operand: Ast.Node.Offset, 2568 /// The source location points to an assembly input 2569 asm_input: struct { 2570 /// Points to the assembly node 2571 offset: Ast.Node.Offset, 2572 input_index: u32, 2573 }, 2574 /// The source location points to an assembly output 2575 asm_output: struct { 2576 /// Points to the assembly node 2577 offset: Ast.Node.Offset, 2578 output_index: u32, 2579 }, 2580 /// Points to the assembly node 2581 asm_clobbers: Ast.Node.Offset, 2582 /// The source location points to a for loop input. 2583 for_input: struct { 2584 /// Points to the for loop AST node. 2585 for_node_offset: Ast.Node.Offset, 2586 /// Picks one of the inputs from the condition. 2587 input_index: u32, 2588 }, 2589 /// The source location points to one of the captures of a for loop, found 2590 /// by taking this AST node index offset from the containing 2591 /// base node, which points to one of the input nodes of a for loop. 2592 /// Next, navigate to the corresponding capture. 2593 for_capture_from_input: Ast.Node.Offset, 2594 /// The source location points to the argument node of a function call. 2595 call_arg: struct { 2596 /// Points to the function call AST node. 2597 call_node_offset: Ast.Node.Offset, 2598 /// The index of the argument the source location points to. 2599 arg_index: u32, 2600 }, 2601 fn_proto_param: FnProtoParam, 2602 fn_proto_param_type: FnProtoParam, 2603 array_cat_lhs: ArrayCat, 2604 array_cat_rhs: ArrayCat, 2605 /// The source location points to the backing or tag type expression of 2606 /// the container type declaration at the base node. 2607 /// 2608 /// For 'union(enum(T))', this points to 'T', not 'enum(T)'. 2609 container_arg, 2610 /// The source location points to the name of the field at the given index 2611 /// of the container type declaration at the base node. 2612 container_field_name: u32, 2613 /// Like `continer_field_name`, but points at the field's default value. 2614 container_field_value: u32, 2615 /// Like `continer_field_name`, but points at the field's type. 2616 container_field_type: u32, 2617 /// Like `continer_field_name`, but points at the field's alignment. 2618 container_field_align: u32, 2619 /// The source location points to the type of the field at the given index 2620 /// of the tuple type declaration at `tuple_decl_node_offset`. 2621 tuple_field_type: TupleField, 2622 /// The source location points to the default init of the field at the given index 2623 /// of the tuple type declaration at `tuple_decl_node_offset`. 2624 tuple_field_init: TupleField, 2625 /// The source location points to the given element/field of a struct or 2626 /// array initialization expression. 2627 init_elem: struct { 2628 /// Points to the AST node of the initialization expression. 2629 init_node_offset: Ast.Node.Offset, 2630 /// The index of the field/element the source location points to. 2631 elem_index: u32, 2632 }, 2633 // The following source locations are like `init_elem`, but refer to a 2634 // field with a specific name. If such a field is not given, the entire 2635 // initialization expression is used instead. 2636 // The `Ast.Node.Offset` points to the AST node of a builtin call, whose *second* 2637 // argument is the init expression. 2638 init_field_name: Ast.Node.Offset, 2639 init_field_linkage: Ast.Node.Offset, 2640 init_field_section: Ast.Node.Offset, 2641 init_field_visibility: Ast.Node.Offset, 2642 init_field_rw: Ast.Node.Offset, 2643 init_field_locality: Ast.Node.Offset, 2644 init_field_cache: Ast.Node.Offset, 2645 init_field_library: Ast.Node.Offset, 2646 init_field_thread_local: Ast.Node.Offset, 2647 init_field_dll_import: Ast.Node.Offset, 2648 init_field_relocation: Ast.Node.Offset, 2649 init_field_decoration: Ast.Node.Offset, 2650 /// The source location points to the value of an item in a specific 2651 /// case of a `switch`. 2652 switch_case_item: SwitchItem, 2653 /// The source location points to the "first" value of a range item in 2654 /// a specific case of a `switch`. 2655 switch_case_item_range_first: SwitchItem, 2656 /// The source location points to the "last" value of a range item in 2657 /// a specific case of a `switch`. 2658 switch_case_item_range_last: SwitchItem, 2659 /// The source location points to the main capture of a specific case of 2660 /// a `switch`. 2661 switch_capture: SwitchCapture, 2662 /// The source location points to the "tag" capture (second capture) of 2663 /// a specific case of a `switch`. 2664 switch_tag_capture: SwitchCapture, 2665 /// The source location points to the `comptime` token on the given comptime parameter, 2666 /// where the base node is a function declaration. The value is the parameter index. 2667 func_decl_param_comptime: u32, 2668 /// The source location points to the type annotation on the given function parameter, 2669 /// where the base node is a function declaration. The value is the parameter index. 2670 func_decl_param_ty: u32, 2671 2672 pub const FnProtoParam = struct { 2673 /// The offset of the function prototype AST node. 2674 fn_proto_node_offset: Ast.Node.Offset, 2675 /// The index of the parameter the source location points to. 2676 param_index: u32, 2677 }; 2678 2679 pub const SwitchItem = struct { 2680 /// The offset of the switch AST node. 2681 switch_node_offset: Ast.Node.Offset, 2682 /// The index of the case to point to within this switch. 2683 case_idx: Zir.UnwrappedSwitchBlock.Case.Index, 2684 /// The index of the item to point to within this case. 2685 item_idx: SwitchItem.Index, 2686 2687 pub const Index = packed struct(u32) { 2688 kind: enum(u1) { single, range }, 2689 value: u31, 2690 }; 2691 }; 2692 2693 pub const SwitchCapture = struct { 2694 /// The offset of the switch AST node. 2695 switch_node_offset: Ast.Node.Offset, 2696 /// The index of the case whose capture to point to. 2697 case_idx: Zir.UnwrappedSwitchBlock.Case.Index, 2698 }; 2699 2700 pub const ArrayCat = struct { 2701 /// Points to the array concat AST node. 2702 array_cat_offset: Ast.Node.Offset, 2703 /// The index of the element the source location points to. 2704 elem_index: u32, 2705 }; 2706 2707 pub const TupleField = struct { 2708 /// Points to the AST node of the tuple type decaration. 2709 tuple_decl_node_offset: Ast.Node.Offset, 2710 /// The index of the tuple field the source location points to. 2711 elem_index: u32, 2712 }; 2713 2714 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; 2715 2716 noinline fn nodeOffsetDebug(node_offset: Ast.Node.Offset) Offset { 2717 var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } }; 2718 result.node_offset.trace.addAddr(@returnAddress(), "init"); 2719 return result; 2720 } 2721 2722 fn nodeOffsetRelease(node_offset: Ast.Node.Offset) Offset { 2723 return .{ .node_offset = .{ .x = node_offset } }; 2724 } 2725 2726 /// This wraps a simple integer in debug builds so that later on we can find out 2727 /// where in semantic analysis the value got set. 2728 pub const TracedOffset = struct { 2729 x: Ast.Node.Offset, 2730 trace: std.debug.Trace = std.debug.Trace.init, 2731 2732 const want_tracing = false; 2733 }; 2734 }; 2735 2736 pub const unneeded: LazySrcLoc = .{ 2737 .base_node_inst = undefined, 2738 .offset = .unneeded, 2739 }; 2740 2741 /// Returns `null` if the ZIR instruction has been lost across incremental updates. 2742 pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) ?struct { *File, Ast.Node.Index } { 2743 comptime assert(Zir.inst_tracking_version == 0); 2744 2745 const ip = &zcu.intern_pool; 2746 const file_index, const zir_inst = inst: { 2747 const info = base_node_inst.resolveFull(ip) orelse return null; 2748 break :inst .{ info.file, info.inst }; 2749 }; 2750 const file = zcu.fileByIndex(file_index); 2751 2752 // If we're relative to .main_struct_inst, we know the ast node is the root and don't need to resolve the ZIR, 2753 // which may not exist e.g. in the case of errors in ZON files. 2754 if (zir_inst == .main_struct_inst) return .{ file, .root }; 2755 2756 // Otherwise, make sure ZIR is loaded. 2757 const zir = &file.zir.?; 2758 2759 const inst = zir.instructions.get(@backingInt(zir_inst)); 2760 const base_node: Ast.Node.Index = switch (inst.tag) { 2761 .declaration => inst.data.declaration.src_node, 2762 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node, 2763 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node, 2764 .extended => switch (inst.data.extended.opcode) { 2765 .struct_decl => zir.getStructDecl(zir_inst).src_node, 2766 .union_decl => zir.getUnionDecl(zir_inst).src_node, 2767 .enum_decl => zir.getEnumDecl(zir_inst).src_node, 2768 .opaque_decl => zir.getOpaqueDecl(zir_inst).src_node, 2769 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node, 2770 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node, 2771 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node, 2772 .reify_spirv_type => zir.extraData(Zir.Inst.ReifySpirvType, inst.data.extended.operand).data.node, 2773 else => unreachable, 2774 }, 2775 else => unreachable, 2776 }; 2777 return .{ file, base_node }; 2778 } 2779 2780 /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`. 2781 /// The resulting `SrcLoc` should only be used ephemerally, as it is not correct across incremental updates. 2782 pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc { 2783 return lazy.upgradeOrLost(zcu).?; 2784 } 2785 2786 /// Like `upgrade`, but returns `null` if the source location has been lost across incremental updates. 2787 pub fn upgradeOrLost(lazy: LazySrcLoc, zcu: *Zcu) ?SrcLoc { 2788 const file, const base_node: Ast.Node.Index = resolveBaseNode(lazy.base_node_inst, zcu) orelse return null; 2789 return .{ 2790 .file_scope = file, 2791 .base_node = base_node, 2792 .lazy = lazy.offset, 2793 }; 2794 } 2795 2796 pub fn order(lhs: LazySrcLoc, rhs: LazySrcLoc, zcu: *Zcu) std.math.Order { 2797 const lhs_resolved = lhs.upgradeOrLost(zcu) orelse { 2798 // LHS source location lost, so should never be referenced. Just sort it to the end. 2799 return .gt; 2800 }; 2801 const rhs_resolved = rhs.upgradeOrLost(zcu) orelse { 2802 // RHS source location lost, so should never be referenced. Just sort it to the end. 2803 return .lt; 2804 }; 2805 if (lhs_resolved.file_scope != rhs_resolved.file_scope) { 2806 const lhs_path = lhs_resolved.file_scope.path; 2807 const rhs_path = rhs_resolved.file_scope.path; 2808 return std.math.order(@backingInt(lhs_path.root), @backingInt(rhs_path.root)).differ() orelse 2809 std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).differ().?; 2810 } 2811 const prev_prot = zcu.comp.io.swapCancelProtection(.blocked); 2812 defer _ = zcu.comp.io.swapCancelProtection(prev_prot); 2813 const lhs_span = lhs_resolved.span(zcu) catch |err| { 2814 assert(err != error.Canceled); // we're protected 2815 // Failed to read LHS, so we'll get a transient error. Just sort it to the end. 2816 return .gt; 2817 }; 2818 const rhs_span = rhs_resolved.span(zcu) catch |err| { 2819 assert(err != error.Canceled); // we're protected 2820 // Failed to read RHS, so we'll get a transient error. Just sort it to the end. 2821 return .lt; 2822 }; 2823 return std.math.order(lhs_span.main, rhs_span.main); 2824 } 2825 }; 2826 2827 pub const SemaError = error{ OutOfMemory, Canceled, AlreadyReported }; 2828 pub const CompileError = error{ 2829 OutOfMemory, 2830 /// The compilation update is no longer desired. 2831 Canceled, 2832 /// When this is returned, the compile error for the failure has already been recorded. 2833 AlreadyReported, 2834 /// In a comptime scope, a return instruction was encountered. This error is only seen when 2835 /// doing a comptime function call. 2836 ComptimeReturn, 2837 /// In a comptime scope, a break instruction was encountered. This error is only seen when 2838 /// evaluating a comptime block. 2839 ComptimeBreak, 2840 }; 2841 2842 pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { 2843 try zcu.intern_pool.init(gpa, io, thread_count); 2844 } 2845 2846 /// It is valid to not call this function before `deinit` in error paths. 2847 /// Requires the fields on `zcu.comp` to already be initialized. 2848 pub fn initAfterCompilation(zcu: *Zcu) void { 2849 zcu.initTracyPlots(); 2850 } 2851 2852 pub fn deinit(zcu: *Zcu) void { 2853 const comp = zcu.comp; 2854 const io = comp.io; 2855 const gpa = zcu.gpa; 2856 { 2857 if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); 2858 2859 zcu.builtin_modules.deinit(gpa); 2860 zcu.module_roots.deinit(gpa); 2861 for (zcu.import_table.keys()) |file_index| { 2862 zcu.destroyFile(file_index); 2863 } 2864 zcu.import_table.deinit(gpa); 2865 zcu.alive_files.deinit(gpa); 2866 2867 for (zcu.embed_table.keys()) |embed_file| { 2868 embed_file.path.deinit(gpa); 2869 gpa.destroy(embed_file); 2870 } 2871 zcu.embed_table.deinit(gpa); 2872 2873 zcu.local_zir_cache.handle.close(io); 2874 zcu.global_zir_cache.handle.close(io); 2875 2876 for (zcu.failed_analysis.values()) |value| value.destroy(gpa); 2877 for (zcu.failed_codegen.values()) |value| value.destroy(gpa); 2878 for (zcu.failed_types.values()) |value| value.destroy(gpa); 2879 zcu.analysis_in_progress.deinit(gpa); 2880 zcu.failed_analysis.deinit(gpa); 2881 zcu.transitive_failed_analysis.deinit(gpa); 2882 zcu.dependency_loops.deinit(gpa); 2883 zcu.dependency_loop_nodes.deinit(gpa); 2884 zcu.failed_codegen.deinit(gpa); 2885 zcu.failed_types.deinit(gpa); 2886 2887 for (zcu.failed_files.values()) |value| { 2888 if (value) |msg| gpa.free(msg); 2889 } 2890 zcu.failed_files.deinit(gpa); 2891 zcu.failed_imports.deinit(gpa); 2892 2893 for (zcu.failed_exports.values()) |value| { 2894 value.destroy(gpa); 2895 } 2896 zcu.failed_exports.deinit(gpa); 2897 2898 for (zcu.cimport_errors.values()) |*errs| { 2899 errs.deinit(gpa); 2900 } 2901 zcu.cimport_errors.deinit(gpa); 2902 2903 zcu.compile_logs.deinit(gpa); 2904 zcu.compile_log_lines.deinit(gpa); 2905 zcu.free_compile_log_lines.deinit(gpa); 2906 2907 zcu.all_exports.deinit(gpa); 2908 zcu.free_exports.deinit(gpa); 2909 zcu.single_exports.deinit(gpa); 2910 zcu.multi_exports.deinit(gpa); 2911 2912 zcu.potentially_outdated.deinit(gpa); 2913 zcu.outdated.deinit(gpa); 2914 zcu.outdated_ready.funcs.deinit(gpa); 2915 zcu.outdated_ready.other.deinit(gpa); 2916 zcu.retryable_failures.deinit(gpa); 2917 2918 zcu.test_functions.deinit(gpa); 2919 2920 for (zcu.global_assembly.values()) |s| { 2921 gpa.free(s); 2922 } 2923 zcu.global_assembly.deinit(gpa); 2924 2925 zcu.reference_table.deinit(gpa); 2926 zcu.all_references.deinit(gpa); 2927 zcu.free_references.deinit(gpa); 2928 2929 zcu.inline_reference_frames.deinit(gpa); 2930 zcu.free_inline_reference_frames.deinit(gpa); 2931 2932 zcu.type_reference_table.deinit(gpa); 2933 zcu.all_type_references.deinit(gpa); 2934 zcu.free_type_references.deinit(gpa); 2935 2936 if (zcu.resolved_references) |*r| r.deinit(gpa); 2937 2938 if (comp.debugIncremental()) { 2939 zcu.incremental_debug_state.deinit(gpa); 2940 } 2941 } 2942 zcu.intern_pool.deinit(gpa, io); 2943 } 2944 2945 fn deinitFile(zcu: *Zcu, file_index: Zcu.File.Index) void { 2946 const gpa = zcu.gpa; 2947 const file = zcu.fileByIndex(file_index); 2948 log.debug("deinit File {f}", .{file.path.fmt(zcu.comp)}); 2949 file.path.deinit(gpa); 2950 file.unload(gpa); 2951 if (file.prev_zir) |prev_zir| { 2952 prev_zir.deinit(gpa); 2953 gpa.destroy(prev_zir); 2954 } 2955 file.* = undefined; 2956 } 2957 2958 fn destroyFile(zcu: *Zcu, file_index: Zcu.File.Index) void { 2959 const gpa = zcu.gpa; 2960 const file = zcu.fileByIndex(file_index); 2961 deinitFile(zcu, file_index); 2962 gpa.destroy(file); 2963 } 2964 2965 pub fn namespacePtr(zcu: *Zcu, index: Namespace.Index) *Namespace { 2966 return zcu.intern_pool.namespacePtr(index); 2967 } 2968 2969 pub fn namespacePtrUnwrap(zcu: *Zcu, index: Namespace.OptionalIndex) ?*Namespace { 2970 return zcu.namespacePtr(index.unwrap() orelse return null); 2971 } 2972 2973 // TODO https://github.com/ziglang/zig/issues/8643 2974 pub const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8; 2975 pub const HackDataLayout = extern struct { 2976 data: [8]u8 align(@alignOf(Zir.Inst.Data)), 2977 safety_tag: u8, 2978 }; 2979 comptime { 2980 if (data_has_safety_tag) { 2981 assert(@sizeOf(HackDataLayout) == @sizeOf(Zir.Inst.Data)); 2982 } 2983 } 2984 2985 pub fn loadZirCache(gpa: Allocator, io: Io, cache_file: Io.File) !Zir { 2986 var buffer: [2000]u8 = undefined; 2987 var file_reader = cache_file.reader(io, &buffer); 2988 return result: { 2989 const header = file_reader.interface.takeStructPointer(Zir.Header) catch |err| break :result err; 2990 break :result loadZirCacheBody(gpa, header.*, &file_reader.interface); 2991 } catch |err| switch (err) { 2992 error.ReadFailed => return file_reader.err.?, 2993 else => |e| return e, 2994 }; 2995 } 2996 2997 pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_br: *Io.Reader) !Zir { 2998 var instructions: std.MultiArrayList(Zir.Inst) = .{}; 2999 errdefer instructions.deinit(gpa); 3000 3001 try instructions.setCapacity(gpa, header.instructions_len); 3002 instructions.len = header.instructions_len; 3003 3004 var zir: Zir = .{ 3005 .instructions = instructions.toOwnedSlice(), 3006 .string_bytes = &.{}, 3007 .extra = &.{}, 3008 }; 3009 errdefer zir.deinit(gpa); 3010 3011 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); 3012 zir.extra = try gpa.alloc(u32, header.extra_len); 3013 3014 const safety_buffer = if (data_has_safety_tag) 3015 try gpa.alloc([8]u8, header.instructions_len) 3016 else 3017 undefined; 3018 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3019 3020 var vecs = [_][]u8{ 3021 @ptrCast(zir.instructions.items(.tag)), 3022 if (data_has_safety_tag) 3023 @ptrCast(safety_buffer) 3024 else 3025 @ptrCast(zir.instructions.items(.data)), 3026 zir.string_bytes, 3027 @ptrCast(zir.extra), 3028 }; 3029 try cache_br.readVecAll(&vecs); 3030 if (data_has_safety_tag) { 3031 const tags = zir.instructions.items(.tag); 3032 for (zir.instructions.items(.data), 0..) |*data, i| { 3033 const union_tag = Zir.Inst.Tag.data_tags[@backingInt(tags[i])]; 3034 const as_struct = @as(*HackDataLayout, @ptrCast(data)); 3035 as_struct.* = .{ 3036 .safety_tag = @backingInt(union_tag), 3037 .data = safety_buffer[i], 3038 }; 3039 } 3040 } 3041 return zir; 3042 } 3043 3044 pub fn saveZirCache( 3045 gpa: Allocator, 3046 cache_file_writer: *Io.File.Writer, 3047 stat: Io.File.Stat, 3048 zir: *const Zir, 3049 ) (Io.File.Writer.Error || Allocator.Error)!void { 3050 const safety_buffer = if (data_has_safety_tag) 3051 try gpa.alloc([8]u8, zir.instructions.len) 3052 else 3053 undefined; 3054 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3055 3056 if (data_has_safety_tag) { 3057 // The `Data` union has a safety tag but in the file format we store it without. 3058 for (zir.instructions.items(.data), 0..) |*data, i| { 3059 const as_struct: *const HackDataLayout = @ptrCast(data); 3060 safety_buffer[i] = as_struct.data; 3061 } 3062 } 3063 3064 const header: Zir.Header = .{ 3065 .instructions_len = @intCast(zir.instructions.len), 3066 .string_bytes_len = @intCast(zir.string_bytes.len), 3067 .extra_len = @intCast(zir.extra.len), 3068 3069 .stat_size = stat.size, 3070 .stat_inode = stat.inode, 3071 .stat_mtime = stat.mtime.toNanoseconds(), 3072 }; 3073 var vecs = [_][]const u8{ 3074 @ptrCast((&header)[0..1]), 3075 @ptrCast(zir.instructions.items(.tag)), 3076 if (data_has_safety_tag) 3077 @ptrCast(safety_buffer) 3078 else 3079 @ptrCast(zir.instructions.items(.data)), 3080 zir.string_bytes, 3081 @ptrCast(zir.extra), 3082 }; 3083 cache_file_writer.interface.writeVecAll(&vecs) catch |err| switch (err) { 3084 error.WriteFailed => return cache_file_writer.err.?, 3085 }; 3086 } 3087 3088 pub fn saveZoirCache(cache_file_writer: *Io.File.Writer, stat: Io.File.Stat, zoir: *const Zoir) Io.File.Writer.Error!void { 3089 const header: Zoir.Header = .{ 3090 .nodes_len = @intCast(zoir.nodes.len), 3091 .extra_len = @intCast(zoir.extra.len), 3092 .limbs_len = @intCast(zoir.limbs.len), 3093 .string_bytes_len = @intCast(zoir.string_bytes.len), 3094 .compile_errors_len = @intCast(zoir.compile_errors.len), 3095 .error_notes_len = @intCast(zoir.error_notes.len), 3096 3097 .stat_size = stat.size, 3098 .stat_inode = stat.inode, 3099 .stat_mtime = stat.mtime.toNanoseconds(), 3100 }; 3101 var vecs = [_][]const u8{ 3102 @ptrCast((&header)[0..1]), 3103 @ptrCast(zoir.nodes.items(.tag)), 3104 @ptrCast(zoir.nodes.items(.data)), 3105 @ptrCast(zoir.nodes.items(.ast_node)), 3106 @ptrCast(zoir.extra), 3107 @ptrCast(zoir.limbs), 3108 zoir.string_bytes, 3109 @ptrCast(zoir.compile_errors), 3110 @ptrCast(zoir.error_notes), 3111 }; 3112 cache_file_writer.interface.writeVecAll(&vecs) catch |err| switch (err) { 3113 error.WriteFailed => return cache_file_writer.err.?, 3114 }; 3115 } 3116 3117 pub fn loadZoirCacheBody(gpa: Allocator, header: Zoir.Header, cache_br: *Io.Reader) !Zoir { 3118 var zoir: Zoir = .{ 3119 .nodes = .empty, 3120 .extra = &.{}, 3121 .limbs = &.{}, 3122 .string_bytes = &.{}, 3123 .compile_errors = &.{}, 3124 .error_notes = &.{}, 3125 }; 3126 errdefer zoir.deinit(gpa); 3127 3128 zoir.nodes = nodes: { 3129 var nodes: std.MultiArrayList(Zoir.Node.Repr) = .empty; 3130 defer nodes.deinit(gpa); 3131 try nodes.setCapacity(gpa, header.nodes_len); 3132 nodes.len = header.nodes_len; 3133 break :nodes nodes.toOwnedSlice(); 3134 }; 3135 3136 zoir.extra = try gpa.alloc(u32, header.extra_len); 3137 zoir.limbs = try gpa.alloc(std.math.big.Limb, header.limbs_len); 3138 zoir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); 3139 3140 zoir.compile_errors = try gpa.alloc(Zoir.CompileError, header.compile_errors_len); 3141 zoir.error_notes = try gpa.alloc(Zoir.CompileError.Note, header.error_notes_len); 3142 3143 var vecs = [_][]u8{ 3144 @ptrCast(zoir.nodes.items(.tag)), 3145 @ptrCast(zoir.nodes.items(.data)), 3146 @ptrCast(zoir.nodes.items(.ast_node)), 3147 @ptrCast(zoir.extra), 3148 @ptrCast(zoir.limbs), 3149 zoir.string_bytes, 3150 @ptrCast(zoir.compile_errors), 3151 @ptrCast(zoir.error_notes), 3152 }; 3153 try cache_br.readVecAll(&vecs); 3154 return zoir; 3155 } 3156 3157 pub fn markDependeeOutdated( 3158 zcu: *Zcu, 3159 /// When we are diffing ZIR and marking things as outdated, we won't yet have marked the dependencies as PO. 3160 /// However, when we discover during analysis that something was outdated, the `Dependee` was already 3161 /// marked as PO, so we need to decrement the PO dep count for each depender. 3162 marked_po: enum { not_marked_po, marked_po }, 3163 dependee: InternPool.Dependee, 3164 ) !void { 3165 const gpa = zcu.comp.gpa; 3166 deps_log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); 3167 var it = zcu.intern_pool.dependencyIterator(dependee); 3168 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3169 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3170 while (it.next()) |depender| { 3171 if (zcu.outdated.getPtr(depender)) |po_dep_count| { 3172 switch (marked_po) { 3173 .not_marked_po => {}, 3174 .marked_po => { 3175 po_dep_count.* -= 1; 3176 deps_log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); 3177 if (po_dep_count.* == 0) { 3178 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); 3179 switch (depender.unwrap()) { 3180 .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}), 3181 else => try zcu.outdated_ready.other.put(gpa, depender, {}), 3182 } 3183 } 3184 }, 3185 } 3186 continue; 3187 } 3188 const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender); 3189 const new_po_dep_count = switch (marked_po) { 3190 .not_marked_po => if (opt_po_entry) |e| e.value else 0, 3191 .marked_po => if (opt_po_entry) |e| e.value - 1 else { 3192 // This `AnalUnit` has already been re-analyzed this update, and registered a dependency 3193 // on this thing, but already has sufficiently up-to-date information. Nothing to do. 3194 continue; 3195 }, 3196 }; 3197 try zcu.outdated.putNoClobber( 3198 gpa, 3199 depender, 3200 new_po_dep_count, 3201 ); 3202 deps_log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); 3203 if (new_po_dep_count == 0) { 3204 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); 3205 switch (depender.unwrap()) { 3206 .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}), 3207 else => try zcu.outdated_ready.other.put(gpa, depender, {}), 3208 } 3209 } 3210 // If this is a Decl and was not previously PO, we must recursively 3211 // mark dependencies on its tyval as PO. 3212 if (opt_po_entry == null) { 3213 assert(marked_po == .not_marked_po); 3214 try zcu.markTransitiveDependersPotentiallyOutdated(depender); 3215 } 3216 } 3217 3218 zcu.updateTracyOutdatedPlots(); 3219 } 3220 3221 pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { 3222 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3223 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3224 try markPoDependeeUpToDateInner(zcu, dependee); 3225 zcu.updateTracyOutdatedPlots(); 3226 } 3227 /// Assumes that `zcu.outdated_lock` is already held exclusively. 3228 fn markPoDependeeUpToDateInner(zcu: *Zcu, dependee: InternPool.Dependee) !void { 3229 const gpa = zcu.comp.gpa; 3230 deps_log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)}); 3231 var it = zcu.intern_pool.dependencyIterator(dependee); 3232 while (it.next()) |depender| { 3233 if (zcu.outdated.getPtr(depender)) |po_dep_count| { 3234 // This depender is already outdated, but it now has one 3235 // less PO dependency! 3236 po_dep_count.* -= 1; 3237 deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); 3238 if (po_dep_count.* == 0) { 3239 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); 3240 switch (depender.unwrap()) { 3241 .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}), 3242 else => try zcu.outdated_ready.other.put(gpa, depender, {}), 3243 } 3244 } 3245 continue; 3246 } 3247 // This depender is definitely at least PO, because this Decl was just analyzed 3248 // due to being outdated. 3249 const ptr = zcu.potentially_outdated.getPtr(depender) orelse { 3250 // This dependency has been registered during in-progress analysis, but the unit is 3251 // not in `potentially_outdated` because analysis is in-progress. Nothing to do. 3252 continue; 3253 }; 3254 if (ptr.* > 1) { 3255 ptr.* -= 1; 3256 deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); 3257 continue; 3258 } 3259 3260 deps_log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); 3261 3262 // This dependency is no longer PO, i.e. is known to be up-to-date. 3263 assert(zcu.potentially_outdated.swapRemove(depender)); 3264 // If this is a Decl, we must recursively mark dependencies on its tyval 3265 // as no longer PO. 3266 switch (depender.unwrap()) { 3267 .@"comptime" => {}, 3268 .nav_val => |nav| try zcu.markPoDependeeUpToDateInner(.{ .nav_val = nav }), 3269 .nav_ty => |nav| try zcu.markPoDependeeUpToDateInner(.{ .nav_ty = nav }), 3270 .type_layout => |ty| try zcu.markPoDependeeUpToDateInner(.{ .type_layout = ty }), 3271 .struct_defaults => |ty| try zcu.markPoDependeeUpToDateInner(.{ .struct_defaults = ty }), 3272 .func => |func| try zcu.markPoDependeeUpToDateInner(.{ .func_ies = func }), 3273 .memoized_state => |stage| try zcu.markPoDependeeUpToDateInner(.{ .memoized_state = stage }), 3274 } 3275 } 3276 } 3277 3278 /// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may 3279 /// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES. 3280 /// 3281 /// Assumes that `zcu.outdated_lock` is already held exclusively. 3282 fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) Allocator.Error!void { 3283 const gpa = zcu.comp.gpa; 3284 const ip = &zcu.intern_pool; 3285 const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) { 3286 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies 3287 .nav_val => |nav| .{ .nav_val = nav }, 3288 .nav_ty => |nav| .{ .nav_ty = nav }, 3289 .type_layout => |ty| .{ .type_layout = ty }, 3290 .struct_defaults => |ty| .{ .struct_defaults = ty }, 3291 .func => |func_index| .{ .func_ies = func_index }, 3292 .memoized_state => |stage| .{ .memoized_state = stage }, 3293 }; 3294 deps_log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); 3295 var it = ip.dependencyIterator(dependee); 3296 while (it.next()) |po| { 3297 if (zcu.outdated.getPtr(po)) |po_dep_count| { 3298 // This dependency is already outdated, but it now has one more PO dependency. 3299 if (po_dep_count.* == 0) { 3300 switch (po.unwrap()) { 3301 .func => |func| _ = zcu.outdated_ready.funcs.swapRemove(func), 3302 else => _ = zcu.outdated_ready.other.swapRemove(po), 3303 } 3304 } 3305 po_dep_count.* += 1; 3306 deps_log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); 3307 continue; 3308 } 3309 if (zcu.potentially_outdated.getPtr(po)) |n| { 3310 // There is now one more PO dependency. 3311 n.* += 1; 3312 deps_log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); 3313 continue; 3314 } 3315 try zcu.potentially_outdated.putNoClobber(gpa, po, 1); 3316 deps_log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); 3317 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. 3318 try zcu.markTransitiveDependersPotentiallyOutdated(po); 3319 } 3320 } 3321 3322 /// Selects an outdated `AnalUnit` to analyze next. Called from the main semantic analysis loop when 3323 /// there is no work immediately queued. The unit is chosen such that it is unlikely to require any 3324 /// recursive analysis (all of its previously-marked dependencies are already up-to-date), because 3325 /// recursive analysis can cause over-analysis on incremental updates. 3326 pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { 3327 // We prioritize functions, because the sooner they get analyzed, the sooner they can be send to 3328 // the codegen backend and linker, which are usually running in parallel (so this can increase 3329 // parallelism). 3330 // TODO: perhaps we should also experiment with *avoiding* functions if the codegen/link queue 3331 // is backed up (for instance due to a very large function). That could help minimize blocking 3332 // on the main thread in `CodegenTaskPool.start` waiting for the linker to catch up. 3333 if (zcu.outdated_ready.funcs.count() > 0) { 3334 const unit: AnalUnit = .wrap(.{ .func = zcu.outdated_ready.funcs.keys()[0] }); 3335 log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)}); 3336 return unit; 3337 } 3338 3339 if (zcu.outdated_ready.other.count() > 0) { 3340 const unit = zcu.outdated_ready.other.keys()[0]; 3341 log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)}); 3342 return unit; 3343 } 3344 3345 // Usually, getting here means that everything is up-to-date, so there is no more work to do. We 3346 // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty. 3347 // 3348 // However, if a previous update had a dependency loop compile error, there is a cycle in the 3349 // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears 3350 // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that 3351 // case, we usually have to just bite the bullet and analyze one of them. An exception is if 3352 // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only 3353 // possible situation is a cycle where everything is actually up-to-date, so we can clear out 3354 // `zcu.potentially_outdated` and we are done. 3355 3356 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3357 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3358 3359 if (zcu.outdated.count() == 0) { 3360 // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated` 3361 // from a dependency loop on a previous update. 3362 zcu.potentially_outdated.clearRetainingCapacity(); 3363 zcu.updateTracyOutdatedPlots(); 3364 log.debug("findOutdatedToAnalyze: all up-to-date", .{}); 3365 return null; 3366 } 3367 3368 const unit = zcu.outdated.keys()[0]; 3369 log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{ 3370 zcu.outdated.count(), 3371 zcu.fmtAnalUnit(unit), 3372 }); 3373 return unit; 3374 } 3375 3376 /// During an incremental update, before semantic analysis, call this to flush all values from 3377 /// `retryable_failures` and mark them as outdated so they get re-analyzed. 3378 pub fn flushRetryableFailures(zcu: *Zcu) !void { 3379 const comp = zcu.comp; 3380 const gpa = comp.gpa; 3381 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(comp.io); 3382 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(comp.io); 3383 for (zcu.retryable_failures.items) |depender| { 3384 if (zcu.outdated.contains(depender)) continue; 3385 if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| { 3386 // This AnalUnit was already PO, but we now consider it outdated. 3387 // Any transitive dependencies are already marked PO. 3388 try zcu.outdated.put(gpa, depender, kv.value); 3389 continue; 3390 } 3391 // This AnalUnit was not marked PO, but is now outdated. Mark it as 3392 // such, then recursively mark transitive dependencies as PO. 3393 try zcu.outdated.put(gpa, depender, 0); 3394 try zcu.markTransitiveDependersPotentiallyOutdated(depender); 3395 } 3396 zcu.retryable_failures.clearRetainingCapacity(); 3397 zcu.updateTracyOutdatedPlots(); 3398 } 3399 3400 pub fn mapOldZirToNew( 3401 gpa: Allocator, 3402 old_zir: *const Zir, 3403 new_zir: *const Zir, 3404 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), 3405 ) Allocator.Error!void { 3406 // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc. 3407 // Not `declaration`, as this does not create a namespace. 3408 const MatchedZirDecl = struct { 3409 old_inst: Zir.Inst.Index, 3410 new_inst: Zir.Inst.Index, 3411 }; 3412 var pending_matched_type_decls: std.ArrayList(MatchedZirDecl) = .empty; 3413 defer pending_matched_type_decls.deinit(gpa); 3414 3415 // Used as temporary buffers for namespace declaration instructions 3416 var old_contents: Zir.DeclContents = .init; 3417 defer old_contents.deinit(gpa); 3418 var new_contents: Zir.DeclContents = .init; 3419 defer new_contents.deinit(gpa); 3420 3421 // Map the main struct inst to start off with. 3422 try pending_matched_type_decls.append(gpa, .{ 3423 .old_inst = .main_struct_inst, 3424 .new_inst = .main_struct_inst, 3425 }); 3426 3427 while (pending_matched_type_decls.pop()) |match_item| { 3428 // There are some properties of type declarations which cannot change across incremental 3429 // updates. If they have, we need to ignore this mapping. These properties are essentially 3430 // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums, 3431 // and opaques). 3432 const old_tag = old_zir.instructions.items(.data)[@backingInt(match_item.old_inst)].extended.opcode; 3433 const new_tag = new_zir.instructions.items(.data)[@backingInt(match_item.new_inst)].extended.opcode; 3434 if (old_tag != new_tag) continue; 3435 switch (old_tag) { 3436 .struct_decl => { 3437 const old = old_zir.getStructDecl(match_item.old_inst); 3438 const new = new_zir.getStructDecl(match_item.new_inst); 3439 if (old.captures.len != new.captures.len) continue; 3440 if (old.field_names.len != new.field_names.len) continue; 3441 if (old.layout != new.layout) continue; 3442 const old_any_field_aligns = old.field_align_body_lens != null; 3443 const old_any_field_defaults = old.field_default_body_lens != null; 3444 const old_any_comptime_fields = old.field_comptime_bits != null; 3445 const old_explicit_backing_int = old.backing_int_type_body != null; 3446 const new_any_field_aligns = new.field_align_body_lens != null; 3447 const new_any_field_defaults = new.field_default_body_lens != null; 3448 const new_any_comptime_fields = new.field_comptime_bits != null; 3449 const new_explicit_backing_int = new.backing_int_type_body != null; 3450 if (old_any_field_aligns != new_any_field_aligns) continue; 3451 if (old_any_field_defaults != new_any_field_defaults) continue; 3452 if (old_any_comptime_fields != new_any_comptime_fields) continue; 3453 if (old_explicit_backing_int != new_explicit_backing_int) continue; 3454 }, 3455 .union_decl => { 3456 const old = old_zir.getUnionDecl(match_item.old_inst); 3457 const new = new_zir.getUnionDecl(match_item.new_inst); 3458 if (old.captures.len != new.captures.len) continue; 3459 if (old.field_names.len != new.field_names.len) continue; 3460 if (old.kind != new.kind) continue; 3461 const old_any_field_aligns = old.field_align_body_lens != null; 3462 const new_any_field_aligns = new.field_align_body_lens != null; 3463 if (old_any_field_aligns != new_any_field_aligns) continue; 3464 }, 3465 .enum_decl => { 3466 const old = old_zir.getEnumDecl(match_item.old_inst); 3467 const new = new_zir.getEnumDecl(match_item.new_inst); 3468 if (old.captures.len != new.captures.len) continue; 3469 if (old.field_names.len != new.field_names.len) continue; 3470 if (old.nonexhaustive != new.nonexhaustive) continue; 3471 const old_explicit_tag_type = old.tag_type_body != null; 3472 const new_explicit_tag_type = new.tag_type_body != null; 3473 if (old_explicit_tag_type != new_explicit_tag_type) continue; 3474 }, 3475 .opaque_decl => { 3476 const old = old_zir.getOpaqueDecl(match_item.old_inst); 3477 const new = new_zir.getOpaqueDecl(match_item.new_inst); 3478 if (old.captures.len != new.captures.len) continue; 3479 }, 3480 else => unreachable, 3481 } 3482 3483 // Match the container declaration itself 3484 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst); 3485 3486 { 3487 // First, map the fields... 3488 try old_zir.findTrackableFields(gpa, &old_contents, match_item.old_inst); 3489 try new_zir.findTrackableFields(gpa, &new_contents, match_item.new_inst); 3490 3491 // This isn't a `.declaration`, so we shouldn't see a function declaration. 3492 assert(old_contents.func_decl == null); 3493 assert(new_contents.func_decl == null); 3494 3495 // We don't have any smart way of matching up these instructions, so we correlate them based on source order 3496 // in their respective arrays. 3497 3498 const num_type_decls = @min(old_contents.type_decls.items.len, new_contents.type_decls.items.len); 3499 try pending_matched_type_decls.ensureUnusedCapacity(gpa, @intCast(num_type_decls)); 3500 for ( 3501 old_contents.type_decls.items[0..num_type_decls], 3502 new_contents.type_decls.items[0..num_type_decls], 3503 ) |old_inst, new_inst| { 3504 pending_matched_type_decls.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); 3505 } 3506 3507 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); 3508 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other)); 3509 for ( 3510 old_contents.other.items[0..num_other], 3511 new_contents.other.items[0..num_other], 3512 ) |old_inst, new_inst| { 3513 // These instructions don't have declarations, so we just modify `inst_map` directly. 3514 inst_map.putAssumeCapacity(old_inst, new_inst); 3515 } 3516 } 3517 3518 // Maps decl name to `declaration` instruction. 3519 var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; 3520 defer named_decls.deinit(gpa); 3521 // Maps test name to `declaration` instruction. 3522 var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; 3523 defer named_tests.deinit(gpa); 3524 // Maps test name to `declaration` instruction. 3525 var named_decltests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; 3526 defer named_decltests.deinit(gpa); 3527 // All unnamed tests, in order, for a best-effort match. 3528 var unnamed_tests: std.ArrayList(Zir.Inst.Index) = .empty; 3529 defer unnamed_tests.deinit(gpa); 3530 // All comptime declarations, in order, for a best-effort match. 3531 var comptime_decls: std.ArrayList(Zir.Inst.Index) = .empty; 3532 defer comptime_decls.deinit(gpa); 3533 3534 for (old_zir.typeDecls(match_item.old_inst)) |old_decl_inst| { 3535 const old_decl = old_zir.getDeclaration(old_decl_inst); 3536 switch (old_decl.kind) { 3537 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst), 3538 .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst), 3539 .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), 3540 .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), 3541 .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), 3542 } 3543 } 3544 3545 var unnamed_test_idx: u32 = 0; 3546 var comptime_decl_idx: u32 = 0; 3547 3548 for (new_zir.typeDecls(match_item.new_inst)) |new_decl_inst| { 3549 const new_decl = new_zir.getDeclaration(new_decl_inst); 3550 // Attempt to match this to a declaration in the old ZIR: 3551 // * For named declarations (`const`/`var`/`fn`), we match based on name. 3552 // * For named tests (`test "foo"`) and decltests (`test foo`), we also match based on name. 3553 // * For unnamed tests, we match based on order. 3554 // * For comptime blocks, we match based on order. 3555 // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`. 3556 const old_decl_inst = switch (new_decl.kind) { 3557 .@"comptime" => inst: { 3558 if (comptime_decl_idx == comptime_decls.items.len) continue; 3559 defer comptime_decl_idx += 1; 3560 break :inst comptime_decls.items[comptime_decl_idx]; 3561 }, 3562 .unnamed_test => inst: { 3563 if (unnamed_test_idx == unnamed_tests.items.len) continue; 3564 defer unnamed_test_idx += 1; 3565 break :inst unnamed_tests.items[unnamed_test_idx]; 3566 }, 3567 .@"test" => inst: { 3568 const name = new_zir.nullTerminatedString(new_decl.name); 3569 break :inst named_tests.get(name) orelse continue; 3570 }, 3571 .decltest => inst: { 3572 const name = new_zir.nullTerminatedString(new_decl.name); 3573 break :inst named_decltests.get(name) orelse continue; 3574 }, 3575 .@"const", .@"var" => inst: { 3576 const name = new_zir.nullTerminatedString(new_decl.name); 3577 break :inst named_decls.get(name) orelse continue; 3578 }, 3579 }; 3580 3581 // Match the `declaration` instruction 3582 try inst_map.put(gpa, old_decl_inst, new_decl_inst); 3583 3584 // Find trackable instructions within this declaration 3585 try old_zir.findTrackable(gpa, &old_contents, old_decl_inst); 3586 try new_zir.findTrackable(gpa, &new_contents, new_decl_inst); 3587 3588 // We don't have any smart way of matching up these instructions, so we correlate them based on source order 3589 // in their respective arrays. 3590 3591 const num_type_decls = @min(old_contents.type_decls.items.len, new_contents.type_decls.items.len); 3592 try pending_matched_type_decls.ensureUnusedCapacity(gpa, @intCast(num_type_decls)); 3593 for ( 3594 old_contents.type_decls.items[0..num_type_decls], 3595 new_contents.type_decls.items[0..num_type_decls], 3596 ) |old_inst, new_inst| { 3597 pending_matched_type_decls.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); 3598 } 3599 3600 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); 3601 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other)); 3602 for ( 3603 old_contents.other.items[0..num_other], 3604 new_contents.other.items[0..num_other], 3605 ) |old_inst, new_inst| { 3606 // These instructions don't have declarations, so we just modify `inst_map` directly. 3607 inst_map.putAssumeCapacity(old_inst, new_inst); 3608 } 3609 3610 if (old_contents.func_decl) |old_func_inst| { 3611 if (new_contents.func_decl) |new_func_inst| { 3612 // There are no declarations on a function either, so again, we just directly add it to `inst_map`. 3613 try inst_map.put(gpa, old_func_inst, new_func_inst); 3614 } 3615 } 3616 } 3617 } 3618 } 3619 3620 /// Ensure this function's body is or will be analyzed and emitted. This should 3621 /// be called whenever a potential runtime call of a function is seen. 3622 /// 3623 /// The caller is responsible for ensuring the function decl itself is already 3624 /// analyzed, and for ensuring it can exist at runtime (see 3625 /// `Type.fnHasRuntimeBitsSema`). This function does *not* guarantee that the body 3626 /// will be analyzed when it returns: for that, see `PerThread.ensureFuncBodyUpToDate`. 3627 pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func: InternPool.Index) !void { 3628 const comp = zcu.comp; 3629 const gpa = comp.gpa; 3630 const io = comp.io; 3631 const ip = &zcu.intern_pool; 3632 assert(func == ip.unwrapCoercedFunc(func)); // analyze the body of the original function, not a coerced one 3633 if (ip.setWantRuntimeFnAnalysis(io, func)) { 3634 // This is the first reference to this function, so we must ensure it will be analyzed. 3635 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3636 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3637 try zcu.outdated.ensureUnusedCapacity(gpa, 1); 3638 try zcu.outdated_ready.funcs.ensureUnusedCapacity(gpa, 1); 3639 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .func = func }), 0); 3640 zcu.outdated_ready.funcs.putAssumeCapacityNoClobber(func, {}); 3641 zcu.updateTracyOutdatedPlots(); 3642 } 3643 } 3644 3645 pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav: InternPool.Nav.Index) !void { 3646 const comp = zcu.comp; 3647 const gpa = comp.gpa; 3648 const io = comp.io; 3649 const ip = &zcu.intern_pool; 3650 if (ip.setWantNavAnalysis(io, nav)) { 3651 // This is the first reference to this function, so we must ensure it will be analyzed. 3652 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3653 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3654 try zcu.outdated.ensureUnusedCapacity(gpa, 2); 3655 try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 2); 3656 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), 0); 3657 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), 0); 3658 zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), {}); 3659 zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), {}); 3660 zcu.updateTracyOutdatedPlots(); 3661 } 3662 } 3663 3664 /// Called when an `InternPool.ComptimeUnit` is first created to mark it as outdated so that it will 3665 /// be semantically analyzed. 3666 pub fn queueComptimeUnitAnalysis(zcu: *Zcu, cu: InternPool.ComptimeUnit.Id) Allocator.Error!void { 3667 const comp = zcu.comp; 3668 const gpa = comp.gpa; 3669 const io = comp.io; 3670 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); 3671 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(io); 3672 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(io); 3673 try zcu.outdated.ensureUnusedCapacity(gpa, 1); 3674 try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 1); 3675 zcu.outdated.putAssumeCapacityNoClobber(unit, 0); 3676 zcu.outdated_ready.other.putAssumeCapacityNoClobber(unit, {}); 3677 zcu.updateTracyOutdatedPlots(); 3678 } 3679 3680 /// If `unit` was marked as outdated or porentially outdated, clears that status and returns `true`. 3681 /// Otherwise, returns `false`. 3682 pub fn clearOutdatedState(zcu: *Zcu, unit: AnalUnit) bool { 3683 const io = zcu.comp.io; 3684 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(io); 3685 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(io); 3686 if (zcu.outdated.fetchSwapRemove(unit)) |kv| { 3687 const was_ready = switch (unit.unwrap()) { 3688 .func => |func| zcu.outdated_ready.funcs.swapRemove(func), 3689 else => zcu.outdated_ready.other.swapRemove(unit), 3690 }; 3691 if (kv.value == 0) { 3692 assert(was_ready); 3693 } else { 3694 assert(!was_ready); 3695 } 3696 zcu.updateTracyOutdatedPlots(); 3697 return true; 3698 } else if (zcu.potentially_outdated.swapRemove(unit)) { 3699 zcu.updateTracyOutdatedPlots(); 3700 return true; 3701 } else { 3702 return false; 3703 } 3704 } 3705 3706 /// This function takes a `*const Zcu` and `@constCast`s it so that it can be called from functions 3707 /// in `Type` which otherwise do not modify the `Zcu`. 3708 pub fn assertUpToDate(zcu: *const Zcu, unit: AnalUnit) void { 3709 if (!std.debug.runtime_safety) return; 3710 3711 const io = zcu.comp.io; 3712 3713 @constCast(zcu).outdated_lock.lockSharedUncancelable(io); 3714 defer @constCast(zcu).outdated_lock.unlockShared(io); 3715 3716 assert(!zcu.outdated.contains(unit)); 3717 assert(!zcu.potentially_outdated.contains(unit)); 3718 } 3719 3720 pub const ImportResult = struct { 3721 /// Whether `file` has been newly created; in other words, whether this is the first import of 3722 /// this file. This should only be `true` when importing files during AstGen. After that, all 3723 /// files should have already been discovered. 3724 is_new: bool, 3725 3726 /// `file.mod` is not populated by this function, so if `is_new`, then it is `undefined`. 3727 file: *Zcu.File, 3728 file_index: File.Index, 3729 3730 /// If this import was a simple file path, this is `null`; the imported file should exist within 3731 /// the importer's module. Otherwise, it's the module which the import resolved to. This module 3732 /// could match the module of `cur_file`, since a module can depend on itself. 3733 module: ?*Module, 3734 }; 3735 3736 /// Prepares `unit` for re-analysis by clearing all of the following state: 3737 /// * Compile errors associated with `unit` 3738 /// * Compile logs associated with `unit` 3739 /// * Exports performed by `unit` 3740 /// * Dependencies from `unit` on other things 3741 /// * References from `unit` to other units 3742 /// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it 3743 /// has. Called in preparation for re-analysis, which will recreate references and dependencies. 3744 /// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated. 3745 pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void { 3746 const gpa = zcu.comp.gpa; 3747 3748 if (!dev.env.supports(.incremental)) { 3749 // This is the first time `unit` is being analyzed, so there is no stale data to clear. 3750 return; 3751 } 3752 3753 // Compile errors 3754 if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| { 3755 kv.value.destroy(gpa); 3756 } else if (zcu.dependency_loop_nodes.swapRemove(unit)) { 3757 _ = zcu.dependency_loops.swapRemove(unit); 3758 _ = zcu.transitive_failed_analysis.swapRemove(unit); 3759 } else { 3760 _ = zcu.transitive_failed_analysis.swapRemove(unit); 3761 } 3762 3763 // Compile logs 3764 if (zcu.compile_logs.fetchSwapRemove(unit)) |kv| { 3765 var opt_line_idx = kv.value.first_line.toOptional(); 3766 while (opt_line_idx.unwrap()) |line_idx| { 3767 zcu.free_compile_log_lines.append(gpa, line_idx) catch { 3768 // This space will be reused eventually, so we need not propagate this error. 3769 // Just leak it for now, and let GC reclaim it later on. 3770 break; 3771 }; 3772 opt_line_idx = line_idx.get(zcu).next; 3773 } 3774 } 3775 3776 // Exports 3777 exports: { 3778 const base: u32, const len: u32 = index: { 3779 if (zcu.single_exports.fetchSwapRemove(unit)) |kv| { 3780 break :index .{ @backingInt(kv.value), 1 }; 3781 } 3782 if (zcu.multi_exports.fetchSwapRemove(unit)) |kv| { 3783 break :index .{ kv.value.index, kv.value.len }; 3784 } 3785 break :exports; 3786 }; 3787 for (base..base + len) |exp_index_usize| { 3788 const exp_index: Export.Index = @fromBackingInt(@intCast(exp_index_usize)); 3789 if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| { 3790 failed_kv.value.destroy(gpa); 3791 } 3792 } 3793 zcu.free_exports.ensureUnusedCapacity(gpa, len) catch { 3794 // This space will be reused eventually, so we need not propagate this error. 3795 // Just leak it for now, and let GC reclaim it later on. 3796 break :exports; 3797 }; 3798 for (base..base + len) |exp_index| { 3799 zcu.free_exports.appendAssumeCapacity(@fromBackingInt(@intCast(exp_index))); 3800 } 3801 } 3802 3803 // Dependencies 3804 zcu.intern_pool.removeDependenciesForDepender(gpa, unit); 3805 3806 // References 3807 zcu.clearCachedResolvedReferences(); 3808 unit_refs: { 3809 const kv = zcu.reference_table.fetchSwapRemove(unit) orelse break :unit_refs; 3810 var idx = kv.value; 3811 3812 while (idx != std.math.maxInt(u32)) { 3813 const ref = zcu.all_references.items[idx]; 3814 zcu.free_references.append(gpa, idx) catch { 3815 // This space will be reused eventually, so we need not propagate this error. 3816 // Just leak it for now, and let GC reclaim it later on. 3817 break :unit_refs; 3818 }; 3819 idx = ref.next; 3820 3821 var opt_inline_frame = ref.inline_frame; 3822 while (opt_inline_frame.unwrap()) |inline_frame| { 3823 // The same inline frame could be used multiple times by one unit. We need to 3824 // detect this case to avoid adding it to `free_inline_reference_frames` more 3825 // than once. We do that by setting `parent` to itself as a marker. 3826 if (inline_frame.ptr(zcu).parent == inline_frame.toOptional()) break; 3827 zcu.free_inline_reference_frames.append(gpa, inline_frame) catch { 3828 // This space will be reused eventually, so we need not propagate this error. 3829 // Just leak it for now, and let GC reclaim it later on. 3830 break :unit_refs; 3831 }; 3832 opt_inline_frame = inline_frame.ptr(zcu).parent; 3833 inline_frame.ptr(zcu).parent = inline_frame.toOptional(); // signal to code above 3834 } 3835 } 3836 } 3837 type_refs: { 3838 const kv = zcu.type_reference_table.fetchSwapRemove(unit) orelse break :type_refs; 3839 var idx = kv.value; 3840 3841 while (idx != std.math.maxInt(u32)) { 3842 zcu.free_type_references.append(gpa, idx) catch { 3843 // This space will be reused eventually, so we need not propagate this error. 3844 // Just leak it for now, and let GC reclaim it later on. 3845 break :type_refs; 3846 }; 3847 idx = zcu.all_type_references.items[idx].next; 3848 } 3849 } 3850 } 3851 3852 pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index { 3853 const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: { 3854 _ = try zcu.inline_reference_frames.addOne(zcu.gpa); 3855 break :idx @fromBackingInt(@intCast(zcu.inline_reference_frames.items.len - 1)); 3856 }; 3857 frame_idx.ptr(zcu).* = frame; 3858 return frame_idx; 3859 } 3860 3861 pub fn addUnitReference( 3862 zcu: *Zcu, 3863 src_unit: AnalUnit, 3864 referenced_unit: AnalUnit, 3865 ref_src: LazySrcLoc, 3866 inline_frame: InlineReferenceFrame.Index.Optional, 3867 ) Allocator.Error!void { 3868 const gpa = zcu.gpa; 3869 3870 zcu.clearCachedResolvedReferences(); 3871 3872 try zcu.reference_table.ensureUnusedCapacity(gpa, 1); 3873 3874 const ref_idx = zcu.free_references.pop() orelse idx: { 3875 _ = try zcu.all_references.addOne(gpa); 3876 break :idx zcu.all_references.items.len - 1; 3877 }; 3878 3879 errdefer comptime unreachable; 3880 3881 const gop = zcu.reference_table.getOrPutAssumeCapacity(src_unit); 3882 3883 zcu.all_references.items[ref_idx] = .{ 3884 .referenced = referenced_unit, 3885 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), 3886 .src = ref_src, 3887 .inline_frame = inline_frame, 3888 }; 3889 3890 gop.value_ptr.* = @intCast(ref_idx); 3891 } 3892 3893 pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void { 3894 const gpa = zcu.gpa; 3895 3896 zcu.clearCachedResolvedReferences(); 3897 3898 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1); 3899 3900 const ref_idx = zcu.free_type_references.pop() orelse idx: { 3901 _ = try zcu.all_type_references.addOne(gpa); 3902 break :idx zcu.all_type_references.items.len - 1; 3903 }; 3904 3905 errdefer comptime unreachable; 3906 3907 const gop = zcu.type_reference_table.getOrPutAssumeCapacity(src_unit); 3908 3909 zcu.all_type_references.items[ref_idx] = .{ 3910 .referenced = referenced_type, 3911 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), 3912 .src = ref_src, 3913 }; 3914 3915 gop.value_ptr.* = @intCast(ref_idx); 3916 } 3917 3918 fn clearCachedResolvedReferences(zcu: *Zcu) void { 3919 if (zcu.resolved_references) |*r| r.deinit(zcu.gpa); 3920 zcu.resolved_references = null; 3921 } 3922 3923 pub fn errorSetBits(zcu: *const Zcu) u16 { 3924 const target = zcu.getTarget(); 3925 3926 if (zcu.error_limit == 0) return 0; 3927 if (target.cpu.arch.isSpirV()) { 3928 // As expected by https://github.com/Snektron/zig-spirv-test-executor 3929 if (zcu.comp.config.is_test) return 32; 3930 } 3931 3932 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1; 3933 } 3934 3935 pub fn errNote( 3936 zcu: *Zcu, 3937 src_loc: LazySrcLoc, 3938 parent: *ErrorMsg, 3939 comptime format: []const u8, 3940 args: anytype, 3941 ) error{OutOfMemory}!void { 3942 const msg = try std.fmt.allocPrint(zcu.gpa, format, args); 3943 errdefer zcu.gpa.free(msg); 3944 3945 parent.notes = try zcu.gpa.realloc(parent.notes, parent.notes.len + 1); 3946 parent.notes[parent.notes.len - 1] = .{ 3947 .src_loc = src_loc, 3948 .msg = msg, 3949 }; 3950 } 3951 3952 /// Deprecated. There is no global target for a Zig Compilation Unit. Instead, 3953 /// look up the target based on the Module that contains the source code being 3954 /// analyzed. 3955 pub fn getTarget(zcu: *const Zcu) *const Target { 3956 return &zcu.root_mod.resolved_target.result; 3957 } 3958 3959 pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void { 3960 const gpa = zcu.gpa; 3961 const gop = try zcu.global_assembly.getOrPut(gpa, unit); 3962 if (gop.found_existing) { 3963 const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source }); 3964 gpa.free(gop.value_ptr.*); 3965 gop.value_ptr.* = new_value; 3966 } else { 3967 gop.value_ptr.* = try gpa.dupe(u8, source); 3968 } 3969 } 3970 3971 pub const Feature = enum { 3972 /// When this feature is enabled, Sema will emit calls to 3973 /// `std.lang.panic` functions for things like safety checks and 3974 /// unreachables. Otherwise traps will be emitted. 3975 panic_fn, 3976 /// When this feature is enabled, Sema will insert tracer functions for gathering a stack 3977 /// trace for error returns. 3978 error_return_trace, 3979 /// When this feature is enabled, Sema will emit the `is_named_enum_value` AIR instructions 3980 /// and use it to check for corrupt switches. Backends currently need to implement their own 3981 /// logic to determine whether an enum value is in the set of named values. 3982 is_named_enum_value, 3983 error_set_has_value, 3984 field_reordering, 3985 /// In theory, backends are supposed to work like this: 3986 /// 3987 /// * The AIR emitted by `Sema` is converted into MIR by `codegen.generateFunction`. This pass 3988 /// is "pure", in that it does not depend on or modify any external mutable state. 3989 /// 3990 /// * That MIR is sent to the linker, which calls `codegen.emitFunction` to convert the MIR to 3991 /// finalized machine code. This process is permitted to query and modify linker state. 3992 /// 3993 /// * The linker stores the resulting machine code in the binary as needed. 3994 /// 3995 /// The first stage described above can run in parallel to the rest of the compiler, and even to 3996 /// other code generation work; we can run as many codegen threads as we want in parallel because 3997 /// of the fact that this pass is pure. Emit and link must be single-threaded, but are generally 3998 /// very fast, so that isn't a problem. 3999 /// 4000 /// Unfortunately, some code generation implementations currently query and/or mutate linker state 4001 /// or even (in the case of the LLVM backend) semantic analysis state. Such backends cannot be run 4002 /// in parallel with each other, with linking, or (potentially) with semantic analysis. 4003 /// 4004 /// Additionally, some backends continue to need the AIR in the "emit" stage, despite this pass 4005 /// operating on MIR. This complicates memory management under the threading model above. 4006 /// 4007 /// These are both **bugs** in backend implementations, left over from legacy code. However, they 4008 /// are difficult to fix. So, this `Feature` currently guards correct threading of code generation: 4009 /// 4010 /// * With this feature enabled, the backend is threaded as described above. The "emit" stage does 4011 /// not have access to AIR (it will be `undefined`; see `codegen.emitFunction`). 4012 /// 4013 /// * With this feature disabled, semantic analysis, code generation, and linking all occur on the 4014 /// same thread, and the "emit" stage has access to AIR. 4015 separate_thread, 4016 }; 4017 4018 pub fn backendSupportsFeature(zcu: *const Zcu, comptime feature: Feature) bool { 4019 const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); 4020 return target_util.backendSupportsFeature(backend, feature); 4021 } 4022 4023 pub const AtomicPtrAlignmentError = error{ 4024 FloatTooBig, 4025 IntTooBig, 4026 BadType, 4027 OutOfMemory, 4028 }; 4029 4030 pub const AtomicPtrAlignmentDiagnostics = struct { 4031 bits: u16 = undefined, 4032 max_bits: u16 = undefined, 4033 }; 4034 4035 /// Returns the alignment required for the target to perform atomic operations on type `ty` (that 4036 /// is, the required align attribute on the pointer). If the ABI alignment of `ty` is sufficient, 4037 /// returns `.none`. 4038 // TODO this function does not take into account CPU features, which can affect 4039 // this value. Audit this! 4040 pub fn atomicPtrAlignment( 4041 zcu: *Zcu, 4042 ty: Type, 4043 diags: *AtomicPtrAlignmentDiagnostics, 4044 ) AtomicPtrAlignmentError!Alignment { 4045 const target = zcu.getTarget(); 4046 const max_atomic_bits: u16 = switch (target.cpu.arch) { 4047 .ez80, 4048 .spork8, 4049 => 8, 4050 4051 .aarch64, 4052 .aarch64_be, 4053 => 128, 4054 4055 .mips64, 4056 .mips64el, 4057 => 64, // N32 should be 64, not 32. 4058 4059 .x86_64 => if (target.cpu.has(.x86, .cx16)) 128 else 64, // x32 should be 64 or 128, not 32. 4060 4061 else => target.ptrBitWidth(), 4062 }; 4063 4064 if (ty.toIntern() == .bool_type) return .none; 4065 if (ty.isRuntimeFloat()) { 4066 const bit_count = ty.floatBits(target); 4067 if (bit_count > max_atomic_bits) { 4068 diags.* = .{ 4069 .bits = bit_count, 4070 .max_bits = max_atomic_bits, 4071 }; 4072 return error.FloatTooBig; 4073 } 4074 return .none; 4075 } 4076 if (switch (ty.zigTypeTag(zcu)) { 4077 .int, .@"enum" => true, 4078 .@"struct" => ty.containerLayout(zcu) == .@"packed", 4079 else => false, 4080 }) { 4081 assert(ty.isAbiInt(zcu)); 4082 const bit_count = ty.intInfo(zcu).bits; 4083 if (bit_count > max_atomic_bits) { 4084 diags.* = .{ 4085 .bits = bit_count, 4086 .max_bits = max_atomic_bits, 4087 }; 4088 return error.IntTooBig; 4089 } 4090 return .none; 4091 } 4092 if (ty.isPtrAtRuntime(zcu)) return .none; 4093 return error.BadType; 4094 } 4095 4096 /// Returns null if `ty` is not a struct. 4097 pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType { 4098 if (ty.ip_index == .none) return null; 4099 const ip = &zcu.intern_pool; 4100 return switch (ip.indexToKey(ty.ip_index)) { 4101 .struct_type => ip.loadStructType(ty.ip_index), 4102 else => null, 4103 }; 4104 } 4105 4106 pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType { 4107 const s = zcu.typeToStruct(ty) orelse return null; 4108 if (s.layout != .@"packed") return null; 4109 return s; 4110 } 4111 4112 /// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets 4113 /// into the packed struct InternPool data rather than computing this on the 4114 /// fly, however it was found to perform worse when measured on real world 4115 /// projects. 4116 pub fn structPackedFieldBitOffset( 4117 zcu: *Zcu, 4118 struct_type: InternPool.LoadedStructType, 4119 field_index: u32, 4120 ) u16 { 4121 const ip = &zcu.intern_pool; 4122 assert(struct_type.layout == .@"packed"); 4123 var bit_sum: u64 = 0; 4124 for (0..struct_type.field_types.len) |i| { 4125 if (i == field_index) { 4126 return @intCast(bit_sum); 4127 } 4128 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); 4129 bit_sum += field_ty.bitSize(zcu); 4130 } 4131 unreachable; // index out of bounds 4132 } 4133 4134 pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType { 4135 if (ty.ip_index == .none) return null; 4136 const ip = &zcu.intern_pool; 4137 return switch (ip.indexToKey(ty.ip_index)) { 4138 .union_type => ip.loadUnionType(ty.ip_index), 4139 else => null, 4140 }; 4141 } 4142 4143 pub fn typeToFunc(zcu: *const Zcu, ty: Type) ?InternPool.Key.FuncType { 4144 if (ty.ip_index == .none) return null; 4145 return zcu.intern_pool.indexToFuncType(ty.toIntern()); 4146 } 4147 4148 pub fn iesFuncIndex(zcu: *const Zcu, ies_index: InternPool.Index) InternPool.Index { 4149 return zcu.intern_pool.iesFuncIndex(ies_index); 4150 } 4151 4152 pub fn funcInfo(zcu: *const Zcu, func_index: InternPool.Index) InternPool.Key.Func { 4153 return zcu.intern_pool.toFunc(func_index); 4154 } 4155 4156 pub const UnionLayout = struct { 4157 abi_size: u64, 4158 abi_align: Alignment, 4159 most_aligned_field: u32, 4160 most_aligned_field_size: u64, 4161 biggest_field: u32, 4162 payload_size: u64, 4163 payload_align: Alignment, 4164 tag_align: Alignment, 4165 tag_size: u64, 4166 padding: u32, 4167 4168 pub fn tagOffset(layout: UnionLayout) u64 { 4169 return if (layout.tag_align.compare(.lt, layout.payload_align)) layout.payload_size else 0; 4170 } 4171 4172 pub fn payloadOffset(layout: UnionLayout) u64 { 4173 return if (layout.tag_align.compare(.lt, layout.payload_align)) 0 else layout.tag_size; 4174 } 4175 }; 4176 4177 /// Returns the index of the active field, given the current tag value 4178 pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 { 4179 const ip = &zcu.intern_pool; 4180 if (enum_tag.toIntern() == .none) return null; 4181 const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag; 4182 assert(enum_tag_key.ty == loaded_union.enum_tag_type); 4183 const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type); 4184 return loaded_enum.tagValueIndex(ip, enum_tag_key.int); 4185 } 4186 4187 pub const ResolvedReference = struct { 4188 referencer: AnalUnit, 4189 /// If `inline_frame` is not `.none`, this is the *deepest* source location in the chain of 4190 /// inline calls. For source locations further up the inline call stack, consult `inline_frame`. 4191 src: LazySrcLoc, 4192 inline_frame: InlineReferenceFrame.Index.Optional, 4193 }; 4194 4195 /// Returns a mapping from an `AnalUnit` to where it is referenced. 4196 /// If the value is `null`, the `AnalUnit` is a root of analysis. 4197 /// If an `AnalUnit` is not in the returned map, it is unreferenced. 4198 /// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller. 4199 /// This hashmap is cached, so repeated calls to this function are cheap. 4200 pub fn resolveReferences(zcu: *Zcu) Allocator.Error!*const std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) { 4201 if (zcu.resolved_references == null) { 4202 zcu.resolved_references = try zcu.resolveReferencesInner(); 4203 } 4204 return &zcu.resolved_references.?; 4205 } 4206 fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) { 4207 const trace = tracy.trace(@src()); 4208 defer trace.end(); 4209 4210 const gpa = zcu.gpa; 4211 const comp = zcu.comp; 4212 const ip = &zcu.intern_pool; 4213 4214 var units: std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = .empty; 4215 var types: std.array_hash_map.Auto(InternPool.Index, ?ResolvedReference) = .empty; 4216 defer { 4217 units.deinit(gpa); 4218 types.deinit(gpa); 4219 } 4220 4221 // This is not a sufficient size, but an approximate lower bound. 4222 try units.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); 4223 4224 try types.ensureTotalCapacity(gpa, zcu.analysis_roots_len); 4225 for (zcu.analysisRoots()) |mod| { 4226 const file = zcu.module_roots.get(mod).?.unwrap() orelse continue; 4227 const root_ty = zcu.fileRootType(file); 4228 if (root_ty == .none) continue; 4229 types.putAssumeCapacityNoClobber(root_ty, null); 4230 } 4231 4232 var unit_idx: usize = 0; 4233 var type_idx: usize = 0; 4234 while (true) { 4235 if (type_idx < types.count()) { 4236 const ty = types.keys()[type_idx]; 4237 const referencer = types.values()[type_idx]; 4238 type_idx += 1; 4239 4240 refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip)}); 4241 4242 // Queue any decls within this type which would be automatically analyzed. 4243 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`. 4244 const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?; 4245 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| { 4246 // `comptime` decls are always analyzed. 4247 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); 4248 const gop = try units.getOrPut(gpa, unit); 4249 if (!gop.found_existing) { 4250 refs_log.debug("type '{f}': ref comptime %{}", .{ 4251 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4252 @backingInt(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue), 4253 }); 4254 gop.value_ptr.* = referencer; 4255 } 4256 } 4257 for (zcu.namespacePtr(ns).test_decls.items) |nav_id| { 4258 const nav = ip.getNav(nav_id); 4259 // `test` declarations are analyzed depending on the test filter. 4260 const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue; 4261 const file = zcu.fileByIndex(inst_info.file); 4262 const decl = file.zir.?.getDeclaration(inst_info.inst); 4263 4264 if (!comp.config.is_test or file.mod != zcu.main_mod) continue; 4265 4266 const want_analysis = switch (decl.kind) { 4267 .@"const", .@"var" => unreachable, 4268 .@"comptime" => unreachable, 4269 .unnamed_test => true, 4270 .@"test", .decltest => a: { 4271 const fqn_slice = nav.fqn.toSlice(ip); 4272 if (comp.test_filters.len > 0) { 4273 for (comp.test_filters) |test_filter| { 4274 if (std.mem.find(u8, fqn_slice, test_filter) != null) break; 4275 } else break :a false; 4276 } 4277 break :a true; 4278 }, 4279 }; 4280 if (want_analysis) { 4281 { 4282 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id })); 4283 if (!gop.found_existing) { 4284 refs_log.debug("type '{f}': ref test %{}", .{ 4285 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4286 @backingInt(inst_info.inst), 4287 }); 4288 gop.value_ptr.* = referencer; 4289 } 4290 } 4291 // Non-fatal AstGen errors could mean this test decl failed 4292 if (nav.resolved != null and nav.resolved.?.value != .none) { 4293 const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.resolved.?.value })); 4294 if (!gop.found_existing) gop.value_ptr.* = referencer; 4295 } 4296 } 4297 } 4298 for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| { 4299 // These are named declarations. They are analyzed only if marked `export`. 4300 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue; 4301 const file = zcu.fileByIndex(inst_info.file); 4302 const decl = file.zir.?.getDeclaration(inst_info.inst); 4303 if (decl.linkage == .@"export") { 4304 const unit: AnalUnit = .wrap(.{ .nav_val = nav }); 4305 const gop = try units.getOrPut(gpa, unit); 4306 if (!gop.found_existing) { 4307 refs_log.debug("type '{f}': ref named %{}", .{ 4308 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4309 @backingInt(inst_info.inst), 4310 }); 4311 gop.value_ptr.* = referencer; 4312 } 4313 } 4314 } 4315 for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| { 4316 // These are named declarations. They are analyzed only if marked `export`. 4317 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue; 4318 const file = zcu.fileByIndex(inst_info.file); 4319 const decl = file.zir.?.getDeclaration(inst_info.inst); 4320 if (decl.linkage == .@"export") { 4321 const unit: AnalUnit = .wrap(.{ .nav_val = nav }); 4322 const gop = try units.getOrPut(gpa, unit); 4323 if (!gop.found_existing) { 4324 refs_log.debug("type '{f}': ref named %{}", .{ 4325 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4326 @backingInt(inst_info.inst), 4327 }); 4328 gop.value_ptr.* = referencer; 4329 } 4330 } 4331 } 4332 continue; 4333 } 4334 if (unit_idx < units.count()) { 4335 const unit = units.keys()[unit_idx]; 4336 unit_idx += 1; 4337 4338 // `nav_val` and `nav_ty` reference each other *implicitly* to save memory. 4339 // Likewise for `type_layout` and `struct_defaults` of a struct type. 4340 queue_paired: { 4341 const other: AnalUnit = .wrap(switch (unit.unwrap()) { 4342 .nav_val => |n| .{ .nav_ty = n }, 4343 .nav_ty => |n| .{ .nav_val = n }, 4344 .struct_defaults => |ty| .{ .type_layout = ty }, 4345 .type_layout => |ty| switch (ip.indexToKey(ty)) { 4346 .struct_type => .{ .struct_defaults = ty }, 4347 .union_type, .enum_type, .opaque_type => break :queue_paired, 4348 else => unreachable, 4349 }, 4350 .@"comptime", .func, .memoized_state => break :queue_paired, 4351 }); 4352 const gop = try units.getOrPut(gpa, other); 4353 if (gop.found_existing) break :queue_paired; 4354 gop.value_ptr.* = units.values()[unit_idx - 1]; // same reference location 4355 } 4356 4357 refs_log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); 4358 4359 if (zcu.reference_table.get(unit)) |first_ref_idx| { 4360 assert(first_ref_idx != std.math.maxInt(u32)); 4361 var ref_idx = first_ref_idx; 4362 while (ref_idx != std.math.maxInt(u32)) { 4363 const ref = zcu.all_references.items[ref_idx]; 4364 const gop = try units.getOrPut(gpa, ref.referenced); 4365 if (!gop.found_existing) { 4366 refs_log.debug("unit '{f}': ref unit '{f}'", .{ 4367 zcu.fmtAnalUnit(unit), 4368 zcu.fmtAnalUnit(ref.referenced), 4369 }); 4370 gop.value_ptr.* = .{ 4371 .referencer = unit, 4372 .src = ref.src, 4373 .inline_frame = ref.inline_frame, 4374 }; 4375 } 4376 ref_idx = ref.next; 4377 } 4378 } 4379 if (zcu.type_reference_table.get(unit)) |first_ref_idx| { 4380 assert(first_ref_idx != std.math.maxInt(u32)); 4381 var ref_idx = first_ref_idx; 4382 while (ref_idx != std.math.maxInt(u32)) { 4383 const ref = zcu.all_type_references.items[ref_idx]; 4384 const gop = try types.getOrPut(gpa, ref.referenced); 4385 if (!gop.found_existing) { 4386 refs_log.debug("unit '{f}': ref type '{f}'", .{ 4387 zcu.fmtAnalUnit(unit), 4388 Type.fromInterned(ref.referenced).containerTypeName(ip).fqn.fmt(ip), 4389 }); 4390 gop.value_ptr.* = .{ 4391 .referencer = unit, 4392 .src = ref.src, 4393 .inline_frame = .none, 4394 }; 4395 } 4396 ref_idx = ref.next; 4397 } 4398 } 4399 continue; 4400 } 4401 break; 4402 } 4403 4404 return units.move(); 4405 } 4406 4407 pub fn analysisRoots(zcu: *Zcu) []*Module { 4408 return zcu.analysis_roots_buffer[0..zcu.analysis_roots_len]; 4409 } 4410 4411 pub fn fileByIndex(zcu: *const Zcu, file_index: File.Index) *File { 4412 return zcu.intern_pool.filePtr(file_index); 4413 } 4414 4415 /// Returns the struct that represents this `File`. 4416 /// If the struct has not been created, returns `.none`. 4417 pub fn fileRootType(zcu: *const Zcu, file_index: File.Index) InternPool.Index { 4418 const ip = &zcu.intern_pool; 4419 const file_index_unwrapped = file_index.unwrap(ip); 4420 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire(); 4421 return files.view().items(.root_type)[file_index_unwrapped.index]; 4422 } 4423 4424 pub fn setFileRootType(zcu: *Zcu, file_index: File.Index, root_type: InternPool.Index) void { 4425 const ip = &zcu.intern_pool; 4426 const file_index_unwrapped = file_index.unwrap(ip); 4427 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire(); 4428 files.view().items(.root_type)[file_index_unwrapped.index] = root_type; 4429 } 4430 4431 pub fn navSrcLoc(zcu: *const Zcu, nav_index: InternPool.Nav.Index) LazySrcLoc { 4432 const ip = &zcu.intern_pool; 4433 return .{ 4434 .base_node_inst = ip.getNav(nav_index).srcInst(ip), 4435 .offset = LazySrcLoc.Offset.nodeOffset(.zero), 4436 }; 4437 } 4438 4439 pub fn typeSrcLoc(zcu: *const Zcu, ty_index: InternPool.Index) LazySrcLoc { 4440 _ = zcu; 4441 _ = ty_index; 4442 @panic("TODO"); 4443 } 4444 4445 pub fn typeFileScope(zcu: *Zcu, ty_index: InternPool.Index) *File { 4446 _ = zcu; 4447 _ = ty_index; 4448 @panic("TODO"); 4449 } 4450 4451 pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 { 4452 const ip = &zcu.intern_pool; 4453 const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?; 4454 const zir = zcu.fileByIndex(inst_info.file).zir; 4455 return zir.?.getDeclaration(inst_info.inst).src_line; 4456 } 4457 4458 pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value { 4459 return .fromInterned(zcu.intern_pool.getNav(nav_index).resolved.?.value); 4460 } 4461 4462 pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index { 4463 const ip = &zcu.intern_pool; 4464 return ip.getNav(nav).srcInst(ip).resolveFile(ip); 4465 } 4466 4467 pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { 4468 return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); 4469 } 4470 4471 pub fn navAlignment(zcu: *Zcu, nav_id: InternPool.Nav.Index) InternPool.Alignment { 4472 const resolved = zcu.intern_pool.getNav(nav_id).resolved.?; 4473 return switch (resolved.@"align") { 4474 else => |a| a, 4475 .none => Type.fromInterned(resolved.type).abiAlignment(zcu), 4476 }; 4477 } 4478 4479 pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) { 4480 return .{ .data = .{ .unit = unit, .zcu = zcu } }; 4481 } 4482 pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Alt(FormatDependee, formatDependee) { 4483 return .{ .data = .{ .dependee = d, .zcu = zcu } }; 4484 } 4485 4486 const FormatAnalUnit = struct { unit: AnalUnit, zcu: *const Zcu }; 4487 fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void { 4488 const zcu = data.zcu; 4489 const ip = &zcu.intern_pool; 4490 switch (data.unit.unwrap()) { 4491 .@"comptime" => |cu_id| { 4492 const cu = ip.getComptimeUnit(cu_id); 4493 if (cu.zir_index.resolveFull(ip)) |resolved| { 4494 const file_path = zcu.fileByIndex(resolved.file).path; 4495 return writer.print("comptime(inst=('{f}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @backingInt(resolved.inst), @backingInt(cu_id) }); 4496 } else { 4497 return writer.print("comptime(inst=<lost> [{}])", .{@backingInt(cu_id)}); 4498 } 4499 }, 4500 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @backingInt(nav) }), 4501 .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), @backingInt(ty) }), 4502 .func => |func| { 4503 const nav = zcu.funcInfo(func).owner_nav; 4504 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @backingInt(func) }); 4505 }, 4506 .memoized_state => return writer.writeAll("memoized_state"), 4507 } 4508 } 4509 4510 const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *const Zcu }; 4511 fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void { 4512 const zcu = data.zcu; 4513 const ip = &zcu.intern_pool; 4514 switch (data.dependee) { 4515 .src_hash => |ti| { 4516 const info = ti.resolveFull(ip) orelse { 4517 return writer.writeAll("inst(<lost>)"); 4518 }; 4519 const file_path = zcu.fileByIndex(info.file).path; 4520 return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @backingInt(info.inst) }); 4521 }, 4522 .nav_val, .nav_ty => |nav, tag| { 4523 const fqn = ip.getNav(nav).fqn; 4524 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); 4525 }, 4526 .type_layout, .struct_defaults => |ip_index, tag| { 4527 const fqn = Type.fromInterned(ip_index).containerTypeName(ip).fqn; 4528 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); 4529 }, 4530 .func_ies => |ip_index| { 4531 const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn; 4532 return writer.print("func_ies('{f}')", .{fqn.fmt(ip)}); 4533 }, 4534 .source_file => |file| { 4535 const file_path = zcu.fileByIndex(file).path; 4536 return writer.print("source_file('{f}')", .{file_path.fmt(zcu.comp)}); 4537 }, 4538 .embed_file => |ef_idx| { 4539 const ef = ef_idx.get(zcu); 4540 return writer.print("embed_file('{f}')", .{ef.path.fmt(zcu.comp)}); 4541 }, 4542 .namespace => |ti| { 4543 const info = ti.resolveFull(ip) orelse { 4544 return writer.writeAll("namespace(<lost>)"); 4545 }; 4546 const file_path = zcu.fileByIndex(info.file).path; 4547 return writer.print("namespace('{f}', %{d})", .{ file_path.fmt(zcu.comp), @backingInt(info.inst) }); 4548 }, 4549 .namespace_name => |k| { 4550 const info = k.namespace.resolveFull(ip) orelse { 4551 return writer.print("namespace(<lost>, '{f}')", .{k.name.fmt(ip)}); 4552 }; 4553 const file_path = zcu.fileByIndex(info.file).path; 4554 return writer.print("namespace('{f}', %{d}, '{f}')", .{ file_path.fmt(zcu.comp), @backingInt(info.inst), k.name.fmt(ip) }); 4555 }, 4556 .memoized_state => return writer.writeAll("memoized_state"), 4557 } 4558 } 4559 4560 pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) { 4561 ok, 4562 bad_arch: []const std.Target.Cpu.Arch, // value is allowed archs for cc 4563 bad_backend: std.lang.CompilerBackend, // value is current backend 4564 } { 4565 const target = zcu.getTarget(); 4566 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm); 4567 switch (cc) { 4568 .auto, .@"inline" => return .ok, 4569 .async => return .{ .bad_backend = backend }, // nothing supports async currently 4570 .naked => {}, // depends only on backend 4571 else => for (cc.archs()) |allowed_arch| { 4572 if (allowed_arch == target.cpu.arch) break; 4573 } else return .{ .bad_arch = cc.archs() }, 4574 } 4575 const backend_ok = ok: switch (backend) { 4576 .stage1 => unreachable, 4577 .other => unreachable, 4578 _ => unreachable, 4579 4580 .stage2_llvm => { 4581 dev.check(.llvm_backend); 4582 break :ok @import("codegen/llvm.zig").toLlvmCallConv(cc, target) != null; 4583 }, 4584 .stage2_c => { 4585 dev.check(.c_backend); 4586 if (target.cCallingConvention()) |default_c| { 4587 if (cc.eql(default_c)) { 4588 break :ok true; 4589 } 4590 } 4591 break :ok switch (cc) { 4592 .x86_16_cdecl, 4593 .x86_16_stdcall, 4594 .x86_16_regparmcall, 4595 .x86_16_interrupt, 4596 .x86_64_sysv, 4597 .x86_64_win, 4598 .x86_64_vectorcall, 4599 .x86_64_regcall_v3_sysv, 4600 .x86_64_regcall_v4_win, 4601 .x86_64_interrupt, 4602 .x86_64_preserve_none, 4603 .x86_fastcall, 4604 .x86_thiscall, 4605 .x86_vectorcall, 4606 .x86_regcall_v3, 4607 .x86_regcall_v4_win, 4608 .x86_interrupt, 4609 .aarch64_vfabi, 4610 .aarch64_vfabi_sve, 4611 .aarch64_preserve_none, 4612 .arm_aapcs, 4613 .csky_interrupt, 4614 .riscv64_lp64_v, 4615 .riscv32_ilp32_v, 4616 .m68k_rtd, 4617 .m68k_interrupt, 4618 .msp430_interrupt, 4619 .arm_aapcs_vfp, 4620 .arc_interrupt, 4621 .arm_interrupt, 4622 .microblaze_interrupt, 4623 .mips_interrupt, 4624 .mips64_interrupt, 4625 .riscv32_interrupt, 4626 .riscv64_interrupt, 4627 .sh_interrupt, 4628 .avr_interrupt, 4629 .avr_signal, 4630 .ez80_tiflags, 4631 .naked, 4632 => true, // incoming stack alignment supported 4633 4634 .x86_sysv, 4635 .x86_win, 4636 .x86_mingw, 4637 .x86_stdcall, 4638 => |opts| opts.register_params == 0, // incoming stack alignment supported 4639 4640 else => false, 4641 }; 4642 }, 4643 .stage2_wasm => { 4644 dev.check(.wasm_backend); 4645 break :ok switch (cc) { 4646 .wasm_mvp => |opts| opts.incoming_stack_alignment == null, 4647 else => false, 4648 }; 4649 }, 4650 .stage2_arm => { 4651 dev.check(.arm_backend); 4652 break :ok switch (cc) { 4653 .arm_aapcs => |opts| opts.incoming_stack_alignment == null, 4654 .naked => true, 4655 else => false, 4656 }; 4657 }, 4658 .stage2_x86_64 => { 4659 dev.check(.x86_64_backend); 4660 break :ok switch (cc) { 4661 .x86_64_sysv, .x86_64_win, .naked => true, // incoming stack alignment supported 4662 else => false, 4663 }; 4664 }, 4665 .stage2_aarch64 => { 4666 dev.check(.aarch64_backend); 4667 break :ok switch (cc) { 4668 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true, 4669 else => false, 4670 }; 4671 }, 4672 .stage2_x86 => { 4673 dev.check(.x86_backend); 4674 break :ok switch (cc) { 4675 .x86_sysv, 4676 .x86_win, 4677 .x86_mingw, 4678 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, 4679 .naked => true, 4680 else => false, 4681 }; 4682 }, 4683 .stage2_powerpc => { 4684 dev.check(.powerpc_backend); 4685 break :ok switch (target.cpu.arch) { 4686 .powerpc, .powerpcle => switch (cc) { 4687 .powerpc_sysv, 4688 .powerpc_sysv_altivec, 4689 .powerpc_aix, 4690 .powerpc_aix_altivec, 4691 .naked, 4692 => true, 4693 else => false, 4694 }, 4695 .powerpc64, .powerpc64le => switch (cc) { 4696 .powerpc64_elf, 4697 .powerpc64_elf_altivec, 4698 .powerpc64_elf_v2, 4699 .naked, 4700 => true, 4701 else => false, 4702 }, 4703 else => unreachable, 4704 }; 4705 }, 4706 .stage2_riscv64 => { 4707 dev.check(.riscv64_backend); 4708 break :ok switch (cc) { 4709 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null, 4710 .naked => true, 4711 else => false, 4712 }; 4713 }, 4714 .stage2_sparc64 => { 4715 dev.check(.sparc64_backend); 4716 break :ok switch (cc) { 4717 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null, 4718 .naked => true, 4719 else => false, 4720 }; 4721 }, 4722 .stage2_spirv => { 4723 dev.check(.spirv_backend); 4724 break :ok switch (cc) { 4725 .spirv_device, .spirv_kernel => true, 4726 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan or target.os.tag == .opengl, 4727 .spirv_task, .spirv_mesh => target.os.tag == .vulkan, 4728 else => false, 4729 }; 4730 }, 4731 .stage2_loongarch => { 4732 dev.check(.loongarch_backend); 4733 break :ok switch (cc) { 4734 .loongarch64_lp64, .loongarch32_ilp32, .naked => true, 4735 else => false, 4736 }; 4737 }, 4738 .zsf_spork8 => { 4739 dev.check(.spork8_backend); 4740 break :ok switch (cc) { 4741 .spork8, .naked => true, 4742 else => false, 4743 }; 4744 }, 4745 }; 4746 if (!backend_ok) return .{ .bad_backend = backend }; 4747 return .ok; 4748 } 4749 4750 pub const CodegenFailError = Io.Cancelable || error{ 4751 /// Indicates the error message has been already stored at `Zcu.failed_codegen`. 4752 AlreadyReported, 4753 OutOfMemory, 4754 }; 4755 4756 pub fn codegenFail( 4757 zcu: *Zcu, 4758 nav_index: InternPool.Nav.Index, 4759 comptime format: []const u8, 4760 args: anytype, 4761 ) CodegenFailError { 4762 const msg = try Zcu.ErrorMsg.create(zcu.gpa, zcu.navSrcLoc(nav_index), format, args); 4763 return zcu.codegenFailMsg(nav_index, msg); 4764 } 4765 4766 /// Takes ownership of `msg`, even on OOM. 4767 pub fn codegenFailMsg(zcu: *Zcu, nav_index: InternPool.Nav.Index, msg: *ErrorMsg) CodegenFailError { 4768 const comp = zcu.comp; 4769 const gpa = comp.gpa; 4770 const io = comp.io; 4771 { 4772 comp.mutex.lockUncancelable(io); 4773 defer comp.mutex.unlock(io); 4774 errdefer msg.deinit(gpa); 4775 try zcu.failed_codegen.putNoClobber(gpa, nav_index, msg); 4776 } 4777 return error.AlreadyReported; 4778 } 4779 4780 pub fn codegenFailType( 4781 zcu: *Zcu, 4782 ty_index: InternPool.Index, 4783 comptime format: []const u8, 4784 args: anytype, 4785 ) CodegenFailError { 4786 const gpa = zcu.gpa; 4787 try zcu.failed_types.ensureUnusedCapacity(gpa, 1); 4788 const msg = try Zcu.ErrorMsg.create(gpa, zcu.typeSrcLoc(ty_index), format, args); 4789 zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg); 4790 return error.AlreadyReported; 4791 } 4792 4793 pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg) CodegenFailError { 4794 const gpa = zcu.gpa; 4795 { 4796 errdefer msg.deinit(gpa); 4797 try zcu.failed_types.ensureUnusedCapacity(gpa, 1); 4798 } 4799 zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg); 4800 return error.AlreadyReported; 4801 } 4802 4803 /// Asserts that `zcu.multi_module_err != null`. 4804 pub fn addFileInMultipleModulesError( 4805 zcu: *Zcu, 4806 eb: *std.zig.ErrorBundle.Wip, 4807 ) Allocator.Error!void { 4808 const gpa = zcu.gpa; 4809 4810 const info = zcu.multi_module_err.?; 4811 const file = info.file; 4812 4813 // error: file exists in modules 'root.foo' and 'root.bar' 4814 // note: files must belong to only one module 4815 // note: file is imported here 4816 // note: which is imported here 4817 // note: which is the root of module 'root.foo' imported here 4818 // note: file is the root of module 'root.bar' imported here 4819 4820 const file_src = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb); 4821 const root_msg = try eb.printString("file exists in modules '{s}' and '{s}'", .{ 4822 info.modules[0].fully_qualified_name, 4823 info.modules[1].fully_qualified_name, 4824 }); 4825 4826 var notes: std.ArrayList(std.zig.ErrorBundle.MessageIndex) = .empty; 4827 defer notes.deinit(gpa); 4828 4829 try notes.append(gpa, try eb.addErrorMessage(.{ 4830 .msg = try eb.addString("files must belong to only one module"), 4831 .src_loc = file_src, 4832 })); 4833 4834 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[0], info.refs[0]); 4835 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[1], info.refs[1]); 4836 4837 try eb.addRootErrorMessage(.{ 4838 .msg = root_msg, 4839 .src_loc = file_src, 4840 .notes_len = @intCast(notes.items.len), 4841 }); 4842 const notes_start = try eb.reserveNotes(@intCast(notes.items.len)); 4843 const notes_slice: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]); 4844 @memcpy(notes_slice, notes.items); 4845 } 4846 4847 fn explainWhyFileIsInModule( 4848 zcu: *Zcu, 4849 eb: *std.zig.ErrorBundle.Wip, 4850 notes_out: *std.ArrayList(std.zig.ErrorBundle.MessageIndex), 4851 file: File.Index, 4852 in_module: *Module, 4853 ref: File.Reference, 4854 ) Allocator.Error!void { 4855 const gpa = zcu.gpa; 4856 4857 // error: file is the root of module 'foo' 4858 // 4859 // error: file is imported here by the root of module 'foo' 4860 // 4861 // error: file is imported here 4862 // note: which is imported here 4863 // note: which is imported here by the root of module 'foo' 4864 4865 var import = switch (ref) { 4866 .analysis_root => |mod| { 4867 assert(mod == in_module); 4868 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4869 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}), 4870 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb), 4871 })); 4872 return; 4873 }, 4874 .import => |import| if (import.module) |mod| { 4875 assert(mod == in_module); 4876 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4877 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}), 4878 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb), 4879 })); 4880 return; 4881 } else import, 4882 }; 4883 4884 var is_first = true; 4885 while (true) { 4886 const thing: []const u8 = if (is_first) "file" else "which"; 4887 is_first = false; 4888 4889 const importer_file = zcu.fileByIndex(import.importer); 4890 // `errorBundleTokenSrc` expects the tree to be loaded 4891 _ = importer_file.getTree(zcu) catch |err| { 4892 try Compilation.unableToLoadZcuFile(zcu, eb, importer_file, err); 4893 return; // stop the explanation early 4894 }; 4895 const import_src = try importer_file.errorBundleTokenSrc(import.tok, zcu, eb); 4896 4897 const importer_ref = zcu.alive_files.get(import.importer).?; 4898 const importer_root: ?*Module = switch (importer_ref) { 4899 .analysis_root => |mod| mod, 4900 .import => |i| i.module, 4901 }; 4902 4903 if (importer_root) |m| { 4904 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4905 .msg = try eb.printString("{s} is imported here by the root of module '{s}'", .{ thing, m.fully_qualified_name }), 4906 .src_loc = import_src, 4907 })); 4908 return; 4909 } 4910 4911 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4912 .msg = try eb.printString("{s} is imported here", .{thing}), 4913 .src_loc = import_src, 4914 })); 4915 4916 import = importer_ref.import; 4917 } 4918 } 4919 4920 pub fn addDependencyLoopErrors(zcu: *Zcu, eb: *std.zig.ErrorBundle.Wip) Allocator.Error!void { 4921 const gpa = zcu.comp.gpa; 4922 4923 const all_references = try zcu.resolveReferences(); 4924 4925 var units: std.ArrayList(AnalUnit) = .empty; 4926 defer units.deinit(gpa); 4927 4928 // TODO: sort the dependency loops somehow to make the error bundle reproducible 4929 for (zcu.dependency_loops.keys()) |arbitrary_unit| { 4930 units.clearRetainingCapacity(); 4931 4932 var cur = arbitrary_unit; 4933 while (true) { 4934 try units.append(gpa, cur); 4935 cur = zcu.dependency_loop_nodes.get(cur).?.unit; 4936 if (cur == arbitrary_unit) break; 4937 } 4938 4939 // `units` now contains all units in the loop. We need to pick a starting point somewhere 4940 // along that loop to begin. We will pick whichever node has the shortest reference trace, 4941 // because the other units may well just be referenced *by* that one! This is also likely 4942 // to match the user's intuition for where the loop "starts". 4943 var start_index: usize = 0; 4944 var start_depth: u32 = depth: { 4945 var depth: u32 = 0; 4946 var opt_ref = all_references.get(units.items[0]) orelse { 4947 // This dependency loop is actually unreferenced, so we don't need to emit a compile 4948 // error at all! Move onto the next dependency loop. 4949 continue; 4950 }; 4951 while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1; 4952 break :depth depth; 4953 }; 4954 for (units.items[1..], 1..) |unit, index| { 4955 var depth: u32 = 0; 4956 var opt_ref = all_references.get(unit).?; 4957 while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1; 4958 if (depth < start_depth) { 4959 start_index = index; 4960 start_depth = depth; 4961 } 4962 } 4963 4964 // Collect a reference trace for the start of the loop. 4965 var ref_trace: std.ArrayList(std.zig.ErrorBundle.ReferenceTrace) = .empty; 4966 defer ref_trace.deinit(gpa); 4967 const frame_limit = zcu.comp.reference_trace orelse 0; 4968 try zcu.populateReferenceTrace(units.items[start_index], frame_limit, eb, &ref_trace); 4969 4970 if (units.items.len == 1) { 4971 // Don't do a complicated message with multiple notes, just do a single error message. 4972 assert(start_index == 0); 4973 const root_msg = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) { 4974 error.AlreadyReported => return, // give up on the dep loop error 4975 error.OutOfMemory => |e| return e, 4976 }; 4977 try eb.root_list.append(eb.gpa, root_msg); 4978 continue; 4979 } 4980 4981 // Collect all notes first so we don't leave an incomplete root error message on `error.AlreadyReported`. 4982 const note_buf = try gpa.alloc(std.zig.ErrorBundle.MessageIndex, units.items.len + 1); 4983 defer gpa.free(note_buf); 4984 note_buf[0] = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) { 4985 error.AlreadyReported => return, // give up on the dep loop error 4986 error.OutOfMemory => |e| return e, 4987 }; 4988 for (units.items[start_index + 1 ..], note_buf[1 .. units.items.len - start_index]) |unit, *note| { 4989 note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) { 4990 error.AlreadyReported => return, // give up on the dep loop error 4991 error.OutOfMemory => |e| return e, 4992 }; 4993 } 4994 for (units.items[0..start_index], note_buf[units.items.len - start_index .. units.items.len]) |unit, *note| { 4995 note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) { 4996 error.AlreadyReported => return, // give up on the dep loop error 4997 error.OutOfMemory => |e| return e, 4998 }; 4999 } 5000 note_buf[units.items.len] = try eb.addErrorMessage(.{ 5001 .msg = try eb.addString("eliminate any one of these dependencies to break the loop"), 5002 .src_loc = .none, 5003 }); 5004 5005 try eb.addRootErrorMessage(.{ 5006 .msg = try eb.printString("dependency loop with length {d}", .{units.items.len}), 5007 .src_loc = .none, 5008 .notes_len = @intCast(units.items.len + 1), 5009 }); 5010 const notes_start = try eb.reserveNotes(@intCast(units.items.len + 1)); 5011 const notes: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]); 5012 @memcpy(notes, note_buf); 5013 } 5014 } 5015 fn addDependencyLoopErrorLine( 5016 zcu: *Zcu, 5017 eb: *std.zig.ErrorBundle.Wip, 5018 source_unit: AnalUnit, 5019 ref_trace: []const std.zig.ErrorBundle.ReferenceTrace, 5020 ) (Allocator.Error || error{AlreadyReported})!std.zig.ErrorBundle.MessageIndex { 5021 const ip = &zcu.intern_pool; 5022 const comp = zcu.comp; 5023 5024 const fmt_source: std.fmt.Alt(FormatAnalUnit, formatDependencyLoopSourceUnit) = .{ .data = .{ 5025 .unit = source_unit, 5026 .zcu = zcu, 5027 } }; 5028 5029 const dep_node = zcu.dependency_loop_nodes.get(source_unit).?; 5030 5031 const msg: std.zig.ErrorBundle.String = if (dep_node.unit == source_unit) switch (source_unit.unwrap()) { 5032 .@"comptime" => unreachable, // cannot be involved in a dependency loop 5033 .nav_ty, .nav_val => try eb.printString("{f} depends on itself here", .{fmt_source}), 5034 .memoized_state => unreachable, // memoized_state definitely does not *directly* depend on itself 5035 .func => try eb.printString("{f} uses its own inferred error set here", .{fmt_source}), 5036 .type_layout => try eb.printString("{f} depends on itself {s}", .{ 5037 fmt_source, 5038 dep_node.reason.type_layout_reason.msg(), 5039 }), 5040 .struct_defaults => |ty| try eb.printString( 5041 "default field values of '{f}' depend on themselves for initialization here", 5042 .{Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip)}, 5043 ), 5044 } else switch (dep_node.unit.unwrap()) { 5045 .@"comptime" => unreachable, // cannot be involved in a dependency loop 5046 .nav_val => |nav| try eb.printString("{f} uses value of declaration '{f}' here", .{ 5047 fmt_source, ip.getNav(nav).fqn.fmt(ip), 5048 }), 5049 .nav_ty => |nav| try eb.printString("{f} uses type of declaration '{f}' here", .{ 5050 fmt_source, ip.getNav(nav).fqn.fmt(ip), 5051 }), 5052 .memoized_state => |stage| switch (stage) { 5053 .panic => try eb.printString("{f} requires panic handler for call here", .{fmt_source}), 5054 else => try eb.printString("{f} requires 'std.lang' declarations here", .{fmt_source}), 5055 }, 5056 .func => |func| try eb.printString("{f} uses inferred error set of function '{f}' here", .{ 5057 fmt_source, ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip), 5058 }), 5059 .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{ 5060 fmt_source, 5061 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 5062 dep_node.reason.type_layout_reason.msg(), 5063 }), 5064 .struct_defaults => |ty| try eb.printString( 5065 "{f} uses default field values of '{f}' here", 5066 .{ fmt_source, Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip) }, 5067 ), 5068 }; 5069 5070 const src_loc = dep_node.reason.src.upgrade(zcu); 5071 const source = src_loc.file_scope.getSource(zcu) catch |err| { 5072 try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err); 5073 return error.AlreadyReported; 5074 }; 5075 const span = src_loc.span(zcu) catch |err| { 5076 try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err); 5077 return error.AlreadyReported; 5078 }; 5079 const loc = std.zig.findLineColumn(source, span.main); 5080 const eb_src = try eb.addSourceLocation(.{ 5081 .src_path = try eb.printString("{f}", .{src_loc.file_scope.path.fmt(comp)}), 5082 .span_start = span.start, 5083 .span_main = span.main, 5084 .span_end = span.end, 5085 .line = @intCast(loc.line), 5086 .column = @intCast(loc.column), 5087 .source_line = try eb.addString(loc.source_line), 5088 .reference_trace_len = @intCast(ref_trace.len), 5089 }); 5090 for (ref_trace) |rt| try eb.addReferenceTrace(rt); 5091 return eb.addErrorMessage(.{ 5092 .msg = msg, 5093 .src_loc = eb_src, 5094 }); 5095 } 5096 fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer.Error!void { 5097 const zcu = data.zcu; 5098 const ip = &zcu.intern_pool; 5099 switch (data.unit.unwrap()) { 5100 .@"comptime" => unreachable, // cannot be involved in a dependency loop 5101 .nav_val => |nav| try w.print("value of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}), 5102 .nav_ty => |nav| try w.print("type of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}), 5103 .memoized_state => |stage| switch (stage) { 5104 .panic => try w.writeAll("panic handler"), 5105 else => try w.writeAll("'std.lang' declarations"), 5106 }, 5107 .type_layout => |ty| try w.print("type '{f}'", .{ 5108 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 5109 }), 5110 .struct_defaults => |ty| try w.print("default field value of '{f}'", .{ 5111 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 5112 }), 5113 .func => |func| try w.print("function '{f}'", .{ 5114 ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip), 5115 }), 5116 } 5117 } 5118 5119 pub fn populateReferenceTrace( 5120 zcu: *Zcu, 5121 root: AnalUnit, 5122 frame_limit: u32, 5123 eb: *std.zig.ErrorBundle.Wip, 5124 ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace), 5125 ) Allocator.Error!void { 5126 const ip = &zcu.intern_pool; 5127 const gpa = zcu.comp.gpa; 5128 5129 if (frame_limit == 0) return; 5130 5131 const all_references = try zcu.resolveReferences(); 5132 5133 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty; 5134 defer seen.deinit(gpa); 5135 5136 var referenced_by = root; 5137 while (all_references.get(referenced_by)) |maybe_ref| { 5138 const ref = maybe_ref orelse break; 5139 const gop = try seen.getOrPut(gpa, ref.referencer); 5140 if (gop.found_existing) break; 5141 if (ref_trace.items.len < frame_limit) { 5142 var last_call_src = ref.src; 5143 var opt_inline_frame = ref.inline_frame; 5144 while (opt_inline_frame.unwrap()) |inline_frame| { 5145 const f = inline_frame.ptr(zcu).*; 5146 const func_nav = ip.indexToKey(f.callee).func.owner_nav; 5147 const func_name = ip.getNav(func_nav).name.toSlice(ip); 5148 addReferenceTraceFrame(zcu, eb, ref_trace, func_name, last_call_src, true) catch |err| switch (err) { 5149 error.OutOfMemory => |e| return e, 5150 error.AlreadyReported => { 5151 // An incomplete reference trace isn't the end of the world; just cut it off. 5152 return; 5153 }, 5154 }; 5155 last_call_src = f.call_src; 5156 opt_inline_frame = f.parent; 5157 } 5158 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { 5159 .@"comptime" => "comptime", 5160 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip), 5161 .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).fqn.toSlice(ip), 5162 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), 5163 .memoized_state => null, 5164 }; 5165 if (root_name) |n| { 5166 addReferenceTraceFrame(zcu, eb, ref_trace, n, last_call_src, false) catch |err| switch (err) { 5167 error.OutOfMemory => |e| return e, 5168 error.AlreadyReported => { 5169 // An incomplete reference trace isn't the end of the world; just cut it off. 5170 return; 5171 }, 5172 }; 5173 } 5174 } 5175 referenced_by = ref.referencer; 5176 } 5177 5178 if (seen.count() > ref_trace.items.len) { 5179 try ref_trace.append(gpa, .{ 5180 .decl_name = @intCast(seen.count() - ref_trace.items.len), 5181 .src_loc = .none, 5182 }); 5183 } 5184 } 5185 fn addReferenceTraceFrame( 5186 zcu: *Zcu, 5187 eb: *std.zig.ErrorBundle.Wip, 5188 ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace), 5189 name: []const u8, 5190 lazy_src: Zcu.LazySrcLoc, 5191 inlined: bool, 5192 ) error{ OutOfMemory, AlreadyReported }!void { 5193 const gpa = zcu.gpa; 5194 const src = lazy_src.upgrade(zcu); 5195 const source = src.file_scope.getSource(zcu) catch |err| { 5196 try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err); 5197 return error.AlreadyReported; 5198 }; 5199 const span = src.span(zcu) catch |err| { 5200 try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err); 5201 return error.AlreadyReported; 5202 }; 5203 const loc = std.zig.findLineColumn(source, span.main); 5204 try ref_trace.append(gpa, .{ 5205 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }), 5206 .src_loc = try eb.addSourceLocation(.{ 5207 .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}), 5208 .span_start = span.start, 5209 .span_main = span.main, 5210 .span_end = span.end, 5211 .line = @intCast(loc.line), 5212 .column = @intCast(loc.column), 5213 .source_line = 0, 5214 }), 5215 }); 5216 } 5217 5218 const TrackedUnitSema = struct { 5219 /// `null` means we created the node, so should end it. 5220 old_name: ?[std.Progress.Node.max_name_len]u8, 5221 old_analysis_timer: ?Compilation.Timer, 5222 analysis_timer_decl: ?InternPool.TrackedInst.Index, 5223 pub fn end(tus: TrackedUnitSema, zcu: *Zcu) void { 5224 const comp = zcu.comp; 5225 const io = comp.io; 5226 if (tus.old_name) |old_name| { 5227 zcu.sema_prog_node.completeOne(); // we're just renaming, but it's effectively completion 5228 zcu.cur_sema_prog_node.setName(&old_name); 5229 } else { 5230 zcu.cur_sema_prog_node.end(); 5231 zcu.cur_sema_prog_node = .none; 5232 } 5233 report_time: { 5234 const sema_ns = zcu.cur_analysis_timer.?.finish(io) orelse break :report_time; 5235 const zir_decl = tus.analysis_timer_decl orelse break :report_time; 5236 comp.mutex.lockUncancelable(io); 5237 defer comp.mutex.unlock(io); 5238 comp.time_report.?.stats.cpu_ns_sema += sema_ns; 5239 const gop = comp.time_report.?.decl_sema_info.getOrPut(comp.gpa, zir_decl) catch |err| switch (err) { 5240 error.OutOfMemory => { 5241 comp.setAllocFailure(); 5242 break :report_time; 5243 }, 5244 }; 5245 if (!gop.found_existing) gop.value_ptr.* = .{ .ns = 0, .count = 0 }; 5246 gop.value_ptr.ns += sema_ns; 5247 gop.value_ptr.count += 1; 5248 } 5249 zcu.cur_analysis_timer = tus.old_analysis_timer; 5250 if (zcu.cur_analysis_timer) |*t| t.@"resume"(io); 5251 } 5252 }; 5253 pub fn trackUnitSema(zcu: *Zcu, name: []const u8, zir_inst: ?InternPool.TrackedInst.Index) TrackedUnitSema { 5254 const comp = zcu.comp; 5255 const io = comp.io; 5256 if (zcu.cur_analysis_timer) |*t| t.pause(io); 5257 const old_analysis_timer = zcu.cur_analysis_timer; 5258 zcu.cur_analysis_timer = zcu.comp.startTimer(); 5259 const old_name: ?[std.Progress.Node.max_name_len]u8 = old_name: { 5260 if (zcu.cur_sema_prog_node.index == .none) { 5261 zcu.cur_sema_prog_node = zcu.sema_prog_node.start(name, 0); 5262 break :old_name null; 5263 } 5264 const old_name = zcu.cur_sema_prog_node.getName(); 5265 zcu.cur_sema_prog_node.setName(name); 5266 break :old_name old_name; 5267 }; 5268 return .{ 5269 .old_name = old_name, 5270 .old_analysis_timer = old_analysis_timer, 5271 .analysis_timer_decl = zir_inst, 5272 }; 5273 } 5274 5275 pub const CodegenTaskPool = struct { 5276 const CodegenResult = PerThread.RunCodegenError!codegen.AnyMir; 5277 5278 /// In the worst observed case, MIR is around 50 times as large as AIR. More typically, the ratio is 5279 /// around 20. Going by that 50x multiplier, and assuming we want to consume no more than 500 MiB of 5280 /// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight. 5281 const max_air_bytes_in_flight = 10 * 1024 * 1024; 5282 5283 const max_funcs_in_flight = link.Queue.buffer_size; 5284 5285 available_air_bytes: u32, 5286 5287 /// Locks the freelist and `available_air_bytes`. 5288 mutex: Io.Mutex, 5289 5290 /// Signaled when an item is added to the freelist. 5291 free_cond: Io.Condition, 5292 /// Pre-allocated with enough capacity for all indices. 5293 free: std.ArrayList(Index), 5294 5295 /// `.none` means this task is in the freelist. The `task_air_bytes` and 5296 /// `task_futures` entries are `undefined`. 5297 task_funcs: []InternPool.Index, 5298 task_air_bytes: []u32, 5299 task_futures: []Io.Future(CodegenResult), 5300 5301 pub fn init(arena: Allocator) Allocator.Error!CodegenTaskPool { 5302 const task_funcs = try arena.alloc(InternPool.Index, max_funcs_in_flight); 5303 const task_air_bytes = try arena.alloc(u32, max_funcs_in_flight); 5304 const task_futures = try arena.alloc(Io.Future(CodegenResult), max_funcs_in_flight); 5305 @memset(task_funcs, .none); 5306 5307 var free: std.ArrayList(Index) = try .initCapacity(arena, max_funcs_in_flight); 5308 for (0..max_funcs_in_flight) |index| free.appendAssumeCapacity(@fromBackingInt(@intCast(index))); 5309 5310 return .{ 5311 .available_air_bytes = max_air_bytes_in_flight, 5312 .mutex = .init, 5313 .free_cond = .init, 5314 .free = free, 5315 .task_funcs = task_funcs, 5316 .task_air_bytes = task_air_bytes, 5317 .task_futures = task_futures, 5318 }; 5319 } 5320 5321 pub fn cancel(pool: *CodegenTaskPool, zcu: *const Zcu) void { 5322 const io = zcu.comp.io; 5323 for ( 5324 pool.task_funcs, 5325 pool.task_air_bytes, 5326 pool.task_futures, 5327 ) |func, effective_air_bytes, *future| { 5328 if (func == .none) continue; 5329 pool.available_air_bytes += effective_air_bytes; 5330 var mir = future.cancel(io) catch continue; 5331 mir.deinit(zcu); 5332 } 5333 assert(pool.available_air_bytes == max_air_bytes_in_flight); 5334 zcu.updateTracyPlot("air_bytes_in_flight", 0); 5335 } 5336 5337 pub fn start( 5338 pool: *CodegenTaskPool, 5339 zcu: *Zcu, 5340 func_index: InternPool.Index, 5341 air: *Air, 5342 /// If `true`, this function will take ownership of `air`, freeing it after codegen 5343 /// completes; it is not assumed that `air` will outlive this function. If `false`, 5344 /// codegen will operate on `air` via the given pointer, which it is assumed will 5345 /// outline the codegen task. 5346 move_air: bool, 5347 ) Io.Cancelable!Index { 5348 const io = zcu.comp.io; 5349 5350 // To avoid consuming an excessive amount of memory, there is a limit on the total number of AIR 5351 // bytes which can be in the codegen/link pipeline at one time. If we exceed this limit, we must 5352 // wait for codegen/link to finish some WIP functions so they catch up with us. 5353 const actual_air_bytes: u32 = @intCast(air.instructions.len * 5 + air.extra.items.len * 4); 5354 // We need to let all AIR through eventually, even if one function exceeds `max_air_bytes_in_flight`. 5355 const effective_air_bytes: u32 = @min(actual_air_bytes, max_air_bytes_in_flight); 5356 assert(effective_air_bytes > 0); 5357 5358 const index: Index = index: { 5359 try pool.mutex.lock(io); 5360 defer pool.mutex.unlock(io); 5361 5362 while (pool.free.items.len == 0 or pool.available_air_bytes < effective_air_bytes) { 5363 // The linker thread needs to catch up! 5364 try pool.free_cond.wait(io, &pool.mutex); 5365 } 5366 5367 pool.available_air_bytes -= effective_air_bytes; 5368 5369 zcu.updateTracyPlot("air_bytes_in_flight", @max( 5370 max_air_bytes_in_flight - pool.available_air_bytes, 5371 actual_air_bytes, 5372 )); 5373 5374 break :index pool.free.pop().?; 5375 }; 5376 5377 // No turning back now: we're incrementing `pending_codegen_jobs` and starting the worker. 5378 errdefer comptime unreachable; 5379 5380 assert(zcu.pending_codegen_jobs.fetchAdd(1, .monotonic) > 0); // the "Code Generation" node is still active 5381 assert(pool.task_funcs[@backingInt(index)] == .none); 5382 pool.task_funcs[@backingInt(index)] = func_index; 5383 pool.task_air_bytes[@backingInt(index)] = actual_air_bytes; 5384 pool.task_futures[@backingInt(index)] = if (move_air) io.async( 5385 workerCodegenOwnedAir, 5386 .{ zcu, func_index, air.* }, 5387 ) else io.async( 5388 workerCodegenExternalAir, 5389 .{ zcu, func_index, air }, 5390 ); 5391 5392 return index; 5393 } 5394 pub const Index = enum(u32) { 5395 _, 5396 5397 /// Blocks until codegen has completed, successfully or otherwise. 5398 /// The returned MIR is owned by the caller. 5399 pub fn wait( 5400 index: Index, 5401 pool: *CodegenTaskPool, 5402 zcu: *const Zcu, 5403 ) PerThread.RunCodegenError!struct { InternPool.Index, codegen.AnyMir } { 5404 const io = zcu.comp.io; 5405 const func = pool.task_funcs[@backingInt(index)]; 5406 assert(func != .none); 5407 const effective_air_bytes = pool.task_air_bytes[@backingInt(index)]; 5408 const result = pool.task_futures[@backingInt(index)].await(io); 5409 5410 pool.task_funcs[@backingInt(index)] = .none; 5411 pool.task_air_bytes[@backingInt(index)] = undefined; 5412 pool.task_futures[@backingInt(index)] = undefined; 5413 5414 { 5415 pool.mutex.lockUncancelable(io); 5416 defer pool.mutex.unlock(io); 5417 pool.available_air_bytes += effective_air_bytes; 5418 pool.free.appendAssumeCapacity(index); 5419 pool.free_cond.signal(io); 5420 zcu.updateTracyPlot("air_bytes_in_flight", max_air_bytes_in_flight - pool.available_air_bytes); 5421 } 5422 5423 return .{ func, try result }; 5424 } 5425 }; 5426 fn workerCodegenOwnedAir( 5427 zcu: *Zcu, 5428 func_index: InternPool.Index, 5429 orig_air: Air, 5430 ) CodegenResult { 5431 // We own `air` now, so we are responsbile for freeing it. 5432 var air = orig_air; 5433 defer air.deinit(zcu.comp.gpa); 5434 const io = zcu.comp.io; 5435 const tid: Zcu.PerThread.Id = .acquire(io); 5436 defer tid.release(io); 5437 const active = zcu.activate(tid); 5438 defer active.deactivate(); 5439 return active.pt.runCodegen(func_index, &air); 5440 } 5441 fn workerCodegenExternalAir( 5442 zcu: *Zcu, 5443 func_index: InternPool.Index, 5444 air: *Air, 5445 ) CodegenResult { 5446 const io = zcu.comp.io; 5447 const tid: Zcu.PerThread.Id = .acquire(io); 5448 defer tid.release(io); 5449 const active = zcu.activate(tid); 5450 defer active.deactivate(); 5451 return active.pt.runCodegen(func_index, air); 5452 } 5453 }; 5454 5455 fn initTracyPlots(zcu: *const Zcu) void { 5456 if (zcu.comp.skip_linker_dependencies) return; 5457 5458 tracy.plotConfig("air_bytes_in_flight", .{ .format = .memory, .mode = .step }); 5459 5460 tracy.plotConfig("outdated + potentially_outdated", .{ .format = .number, .mode = .step, .color = 0xFFFF00 }); 5461 tracy.plotConfig("outdated", .{ .format = .number, .mode = .step, .color = 0xFF0000 }); 5462 tracy.plotConfig("potentially_outdated", .{ .format = .number, .mode = .step, .color = 0xFF7700 }); 5463 tracy.plotConfig("outdated_ready", .{ .format = .number, .mode = .step, .color = 0x00FF00 }); 5464 } 5465 5466 /// Marked `inline` to prevent binary bloat from trivial generic instances, and to ensure there is 5467 /// minimal overhead to this call when Tracy is disabled, even in Debug builds. 5468 inline fn updateTracyPlot(zcu: *const Zcu, comptime name: [*:0]const u8, val: u64) void { 5469 if (zcu.comp.skip_linker_dependencies) return; 5470 tracy.plotInt(name, @intCast(val)); 5471 } 5472 5473 /// Assumes that `zcu.outdated_lock` is already held. 5474 fn updateTracyOutdatedPlots(zcu: *const Zcu) void { 5475 zcu.updateTracyPlot("outdated + potentially_outdated", zcu.outdated.count() + zcu.potentially_outdated.count()); 5476 zcu.updateTracyPlot("outdated", zcu.outdated.count()); 5477 zcu.updateTracyPlot("potentially_outdated", zcu.potentially_outdated.count()); 5478 zcu.updateTracyPlot("outdated_ready", zcu.outdated_ready.funcs.count() + zcu.outdated_ready.other.count()); 5479 } 5480 5481 pub const Active = struct { 5482 pt: Zcu.PerThread, 5483 ip: InternPool.Active, 5484 pub fn deactivate(active: Active) void { 5485 active.ip.deactivate(); 5486 } 5487 pub fn release(active: Active) void { 5488 active.deactivate(); 5489 active.pt.tid.release(active.pt.zcu.comp.io); 5490 } 5491 }; 5492 pub fn activate(zcu: *Zcu, tid: PerThread.Id) Active { 5493 return .{ 5494 .pt = .{ .zcu = zcu, .tid = tid }, 5495 .ip = zcu.intern_pool.activate(), 5496 }; 5497 } 5498 pub fn acquire(zcu: *Zcu) Active { 5499 return zcu.activate(.acquire(zcu.comp.io)); 5500 } 5501