Skip to main content

luaur_code_gen/methods/
unwind_builder_win_prologue_x_64.rs

1use crate::enums::size_x_64::SizeX64;
2use crate::macros::codegen_assert::CODEGEN_ASSERT;
3use crate::records::register_x_64::RegisterX64;
4use crate::records::unwind_builder_win::UnwindBuilderWin;
5use crate::records::unwind_code_win::UnwindCodeWin;
6
7const UWOP_PUSH_NONVOL: u8 = 0;
8const UWOP_ALLOC_LARGE: u8 = 1;
9const UWOP_ALLOC_SMALL: u8 = 2;
10const UWOP_SET_FPREG: u8 = 3;
11const UWOP_SAVE_XMM128: u8 = 8;
12
13fn unwind_code(offset: u8, opcode: u8, opinfo: u8) -> UnwindCodeWin {
14    let mut result = UnwindCodeWin {
15        offset,
16        opcode_opinfo: 0,
17    };
18    result.set_opcode(opcode);
19    result.set_opinfo(opinfo);
20    result
21}
22
23impl UnwindBuilderWin {
24    pub fn prologue_x_64(
25        &mut self,
26        prologue_size: u32,
27        stack_size: u32,
28        setup_frame: bool,
29        gpr: &[RegisterX64],
30        simd: &[RegisterX64],
31    ) {
32        CODEGEN_ASSERT!(stack_size > 0 && stack_size < 4096 && stack_size % 8 == 0);
33        CODEGEN_ASSERT!(prologue_size < 256);
34
35        let mut stack_offset: u32 = 8;
36        let mut prologue_offset: u32 = 0;
37
38        if setup_frame {
39            stack_offset += 8;
40            prologue_offset += 2;
41            self.unwind_codes.push(unwind_code(
42                prologue_offset as u8,
43                UWOP_PUSH_NONVOL,
44                RegisterX64::rbp.index(),
45            ));
46
47            prologue_offset += 3;
48            self.frame_reg = RegisterX64::rbp;
49            self.frame_reg_offset = 0;
50            self.unwind_codes.push(unwind_code(
51                prologue_offset as u8,
52                UWOP_SET_FPREG,
53                self.frame_reg_offset,
54            ));
55        }
56
57        for reg in gpr {
58            CODEGEN_ASSERT!(reg.size() == SizeX64::qword);
59
60            stack_offset += 8;
61            prologue_offset += 2;
62            self.unwind_codes.push(unwind_code(
63                prologue_offset as u8,
64                UWOP_PUSH_NONVOL,
65                reg.index(),
66            ));
67        }
68
69        CODEGEN_ASSERT!(!setup_frame || simd.is_empty());
70
71        let mut simd_storage_size = simd.len() as u32 * 16;
72
73        if !simd.is_empty() && stack_offset % 16 == 8 {
74            simd_storage_size += 8;
75        }
76
77        if stack_size <= 128 {
78            stack_offset += stack_size;
79            prologue_offset += if stack_size == 128 { 7 } else { 4 };
80            self.unwind_codes.push(unwind_code(
81                prologue_offset as u8,
82                UWOP_ALLOC_SMALL,
83                ((stack_size - 8) / 8) as u8,
84            ));
85        } else {
86            CODEGEN_ASSERT!(stack_size < 4096);
87
88            stack_offset += stack_size;
89            prologue_offset += 7;
90
91            let encoded_offset = (stack_size / 8) as u16;
92            let bytes = encoded_offset.to_le_bytes();
93            self.unwind_codes.push(UnwindCodeWin {
94                offset: bytes[0],
95                opcode_opinfo: bytes[1],
96            });
97            self.unwind_codes
98                .push(unwind_code(prologue_offset as u8, UWOP_ALLOC_LARGE, 0));
99        }
100
101        let mut xmm_store_offset = stack_size - simd_storage_size;
102
103        for reg in simd {
104            CODEGEN_ASSERT!(reg.size() == SizeX64::xmmword);
105            CODEGEN_ASSERT!(
106                xmm_store_offset % 16 == 0,
107                "simd stores have to be performed to aligned locations"
108            );
109
110            prologue_offset += if xmm_store_offset >= 128 { 10 } else { 7 };
111            self.unwind_codes
112                .push(unwind_code((xmm_store_offset / 16) as u8, 0, 0));
113            self.unwind_codes.push(unwind_code(
114                prologue_offset as u8,
115                UWOP_SAVE_XMM128,
116                reg.index(),
117            ));
118            xmm_store_offset += 16;
119        }
120
121        CODEGEN_ASSERT!(stack_offset % 16 == 0);
122        CODEGEN_ASSERT!(prologue_offset == prologue_size);
123
124        self.prolog_size = prologue_size as u8;
125    }
126}