| 1 | // Copyright (c) 2026 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | |
| 5 | module x64 |
| 6 | |
| 7 | pub enum X64Abi { |
| 8 | sysv |
| 9 | windows |
| 10 | } |
| 11 | |
| 12 | const x64_no_arg_reg = -1 |
| 13 | |
| 14 | fn (abi X64Abi) int_arg_regs() []int { |
| 15 | return match abi { |
| 16 | .sysv { [int(rdi), int(rsi), int(rdx), int(rcx), int(r8), int(r9)] } |
| 17 | .windows { [int(rcx), int(rdx), int(r8), int(r9)] } |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | fn (abi X64Abi) sret_arg_regs() []int { |
| 22 | return match abi { |
| 23 | .sysv { [int(rsi), int(rdx), int(rcx), int(r8), int(r9)] } |
| 24 | .windows { [int(rdx), int(r8), int(r9)] } |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | fn (abi X64Abi) sret_reg() Reg { |
| 29 | return match abi { |
| 30 | .sysv { rdi } |
| 31 | .windows { rcx } |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | fn (abi X64Abi) float_arg_regs() []int { |
| 36 | return match abi { |
| 37 | .sysv { [0, 1, 2, 3, 4, 5, 6, 7] } |
| 38 | .windows { [0, 1, 2, 3] } |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | fn (abi X64Abi) uses_positional_arg_regs() bool { |
| 43 | return abi == .windows |
| 44 | } |
| 45 | |
| 46 | fn (abi X64Abi) int_arg_reg_at(index int) int { |
| 47 | regs := abi.int_arg_regs() |
| 48 | if index < 0 || index >= regs.len { |
| 49 | return x64_no_arg_reg |
| 50 | } |
| 51 | return regs[index] |
| 52 | } |
| 53 | |
| 54 | fn (abi X64Abi) float_arg_reg_at(index int) int { |
| 55 | regs := abi.float_arg_regs() |
| 56 | if index < 0 || index >= regs.len { |
| 57 | return x64_no_arg_reg |
| 58 | } |
| 59 | return regs[index] |
| 60 | } |
| 61 | |
| 62 | fn (abi X64Abi) int_arg_reg_for_position(arg_idx int) int { |
| 63 | return match abi { |
| 64 | .sysv { abi.int_arg_reg_at(arg_idx) } |
| 65 | .windows { abi.int_arg_reg_at(arg_idx) } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | fn (abi X64Abi) float_arg_reg_for_position(arg_idx int) int { |
| 70 | return match abi { |
| 71 | .sysv { abi.float_arg_reg_at(arg_idx) } |
| 72 | .windows { abi.float_arg_reg_at(arg_idx) } |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | fn (abi X64Abi) shadow_space_size() int { |
| 77 | return match abi { |
| 78 | .sysv { 0 } |
| 79 | .windows { 32 } |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | fn (abi X64Abi) stack_arg_offset(position int) int { |
| 84 | return match abi { |
| 85 | .sysv { 16 + position * 8 } |
| 86 | .windows { 48 + (position - 4) * 8 } |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | fn (abi X64Abi) call_stack_arg_offset(position int) int { |
| 91 | return match abi { |
| 92 | .sysv { position * 8 } |
| 93 | .windows { abi.shadow_space_size() + (position - 4) * 8 } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | fn (abi X64Abi) call_frame_size(stack_slots int) int { |
| 98 | base := abi.shadow_space_size() + stack_slots * 8 |
| 99 | if base % 16 == 0 { |
| 100 | return base |
| 101 | } |
| 102 | return base + (16 - (base % 16)) |
| 103 | } |
| 104 | |