| 1 | const std = @import("std"); |
| 2 | const bits = @import("bits.zig"); |
| 3 | const Register = bits.Register; |
| 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | |
| 6 | // SPARCv9 SysV ABI stack constants. |
| 7 | // See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1. |
| 8 | |
| 9 | // The ABI specifies that %sp points to top of stack - stack bias, |
| 10 | // and %fp points to top of previous frame - stack bias. |
| 11 | pub const stack_bias = 2047; |
| 12 | |
| 13 | // The first 128 bytes of the stack is reserved for register saving purposes. |
| 14 | // The ABI also requires to reserve space in the stack for the first six |
| 15 | // outgoing arguments, even though they are usually passed in registers. |
| 16 | // TODO Don't allocate the argument space in leaf functions |
| 17 | // TODO Save an RO copy of outgoing arguments in reserved area when building in Debug |
| 18 | // TODO Should we also save it in ReleaseSafe? Solaris and OpenBSD binaries seem to ship |
| 19 | // with argument copying enabled and it doesn't seem to give them big slowdowns so |
| 20 | // I guess it would be okay to do in ReleaseSafe? |
| 21 | pub const stack_reserved_area = 128 + 48; |
| 22 | |
| 23 | // There are no callee-preserved registers since the windowing |
| 24 | // mechanism already takes care of them. |
| 25 | // We still need to preserve %o0-%o5, %g1, %g4, and %g5 before calling |
| 26 | // something, though, as those are shared with the callee and might be |
| 27 | // thrashed by it. |
| 28 | pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 }; |
| 29 | |
| 30 | // Try to allocate i, l, o, then g sets of registers, in order of priority. |
| 31 | const allocatable_regs = [_]Register{ |
| 32 | // zig fmt: off |
| 33 | .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5", |
| 34 | .l0, .l1, .l2, .l3, .l4, .l5, .l6, .l7, |
| 35 | .o0, .o1, .o2, .o3, .o4, .o5, |
| 36 | .g1, .g4, .g5, |
| 37 | // zig fmt: on |
| 38 | }; |
| 39 | |
| 40 | pub const c_abi_int_param_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 }; |
| 41 | pub const c_abi_int_param_regs_callee_view = [_]Register{ .i0, .i1, .i2, .i3, .i4, .i5 }; |
| 42 | |
| 43 | pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 }; |
| 44 | pub const c_abi_int_return_regs_callee_view = [_]Register{ .i0, .i1, .i2, .i3 }; |
| 45 | |
| 46 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs); |
| 47 | |
| 48 | // Register classes |
| 49 | const RegisterBitSet = RegisterManager.RegisterBitSet; |
| 50 | pub const RegisterClass = struct { |
| 51 | pub const gp: RegisterBitSet = blk: { |
| 52 | var set = RegisterBitSet.empty; |
| 53 | set.setRangeValue(.{ |
| 54 | .start = 0, |
| 55 | .end = allocatable_regs.len, |
| 56 | }, true); |
| 57 | break :blk set; |
| 58 | }; |
| 59 | }; |