luaur_code_gen/methods/
unwind_builder_win_prologue_x_64.rs1use 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}