@@ -115,12 +115,10 @@ pub struct UnwindInfo {
115115impl UnwindInfo {
116116 pub ( crate ) fn build < ' b > (
117117 unwind : input:: UnwindInfo < RegUnit > ,
118- word_size : u8 ,
119- frame_register : Option < RegUnit > ,
120118 map_reg : & ' b dyn RegisterMapper ,
121119 ) -> CodegenResult < Self > {
122120 use input:: UnwindCode ;
123- let mut builder = InstructionBuilder :: new ( word_size, frame_register , map_reg) ;
121+ let mut builder = InstructionBuilder :: new ( unwind . word_size , map_reg) ;
124122
125123 for c in unwind. prologue_unwind_codes . iter ( ) . chain (
126124 unwind
@@ -130,9 +128,13 @@ impl UnwindInfo {
130128 . flatten ( ) ,
131129 ) {
132130 match c {
133- UnwindCode :: SaveRegister { offset, reg } => {
131+ UnwindCode :: SaveRegister {
132+ offset,
133+ reg,
134+ stack_offset : 0 ,
135+ } => {
134136 builder
135- . push_reg ( * offset, * reg)
137+ . save_reg ( * offset, * reg)
136138 . map_err ( CodegenError :: RegisterMappingError ) ?;
137139 }
138140 UnwindCode :: StackAlloc { offset, size } => {
@@ -143,7 +145,7 @@ impl UnwindInfo {
143145 }
144146 UnwindCode :: RestoreRegister { offset, reg } => {
145147 builder
146- . pop_reg ( * offset, * reg)
148+ . restore_reg ( * offset, * reg)
147149 . map_err ( CodegenError :: RegisterMappingError ) ?;
148150 }
149151 UnwindCode :: SetFramePointer { offset, reg } => {
@@ -180,46 +182,29 @@ impl UnwindInfo {
180182}
181183
182184struct InstructionBuilder < ' a > {
183- word_size : u8 ,
184- cfa_offset : i32 ,
185- saved_state : Option < i32 > ,
185+ sp_offset : i32 ,
186186 frame_register : Option < RegUnit > ,
187+ saved_state : Option < ( i32 , Option < RegUnit > ) > ,
187188 map_reg : & ' a dyn RegisterMapper ,
188189 instructions : Vec < ( u32 , CallFrameInstruction ) > ,
189190}
190191
191192impl < ' a > InstructionBuilder < ' a > {
192- fn new (
193- word_size : u8 ,
194- frame_register : Option < RegUnit > ,
195- map_reg : & ' a ( dyn RegisterMapper + ' a ) ,
196- ) -> Self {
193+ fn new ( word_size : u8 , map_reg : & ' a ( dyn RegisterMapper + ' a ) ) -> Self {
197194 Self {
198- word_size,
199- cfa_offset : word_size as i32 , // CFA offset starts at word size offset to account for the return address on stack
195+ sp_offset : word_size as i32 , // CFA offset starts at word size offset to account for the return address on stack
200196 saved_state : None ,
201- frame_register,
197+ frame_register : None ,
202198 map_reg,
203199 instructions : Vec :: new ( ) ,
204200 }
205201 }
206202
207- fn push_reg ( & mut self , offset : u32 , reg : RegUnit ) -> Result < ( ) , RegisterMappingError > {
208- self . cfa_offset += self . word_size as i32 ;
209- // Update the CFA if this is the save of the frame pointer register or if a frame pointer isn't being used
210- // When using a frame pointer, we only need to update the CFA to account for the push of the frame pointer itself
211- if match self . frame_register {
212- Some ( fp) => reg == fp,
213- None => true ,
214- } {
215- self . instructions
216- . push ( ( offset, CallFrameInstruction :: CfaOffset ( self . cfa_offset ) ) ) ;
217- }
218-
203+ fn save_reg ( & mut self , offset : u32 , reg : RegUnit ) -> Result < ( ) , RegisterMappingError > {
219204 // Pushes in the prologue are register saves, so record an offset of the save
220205 self . instructions . push ( (
221206 offset,
222- CallFrameInstruction :: Offset ( self . map_reg . map ( reg) ?, -self . cfa_offset ) ,
207+ CallFrameInstruction :: Offset ( self . map_reg . map ( reg) ?, -self . sp_offset ) ,
223208 ) ) ;
224209
225210 Ok ( ( ) )
@@ -228,76 +213,92 @@ impl<'a> InstructionBuilder<'a> {
228213 fn adjust_sp_down_imm ( & mut self , offset : u32 , imm : i64 ) {
229214 assert ! ( imm <= core:: u32 :: MAX as i64 ) ;
230215
216+ self . sp_offset += imm as i32 ;
217+
231218 // Don't adjust the CFA if we're using a frame pointer
232219 if self . frame_register . is_some ( ) {
233220 return ;
234221 }
235222
236- self . cfa_offset += imm as i32 ;
237223 self . instructions
238- . push ( ( offset, CallFrameInstruction :: CfaOffset ( self . cfa_offset ) ) ) ;
224+ . push ( ( offset, CallFrameInstruction :: CfaOffset ( self . sp_offset ) ) ) ;
239225 }
240226
241227 fn adjust_sp_up_imm ( & mut self , offset : u32 , imm : i64 ) {
242228 assert ! ( imm <= core:: u32 :: MAX as i64 ) ;
243229
230+ self . sp_offset -= imm as i32 ;
231+
244232 // Don't adjust the CFA if we're using a frame pointer
245233 if self . frame_register . is_some ( ) {
246234 return ;
247235 }
248236
249- self . cfa_offset -= imm as i32 ;
250- self . instructions
251- . push ( ( offset, CallFrameInstruction :: CfaOffset ( self . cfa_offset ) ) ) ;
237+ let cfa_inst_ofs = {
238+ // Scan to find and merge with CFA instruction with the same offset.
239+ let mut it = self . instructions . iter_mut ( ) ;
240+ loop {
241+ match it. next_back ( ) {
242+ Some ( ( i_offset, i) ) if * i_offset == offset => {
243+ if let CallFrameInstruction :: Cfa ( _, o) = i {
244+ break Some ( o) ;
245+ }
246+ }
247+ _ => {
248+ break None ;
249+ }
250+ }
251+ }
252+ } ;
253+
254+ if let Some ( o) = cfa_inst_ofs {
255+ // Update previous CFA instruction.
256+ * o = self . sp_offset ;
257+ } else {
258+ // Add just CFA offset instruction.
259+ self . instructions
260+ . push ( ( offset, CallFrameInstruction :: CfaOffset ( self . sp_offset ) ) ) ;
261+ }
252262 }
253263
254264 fn set_cfa_reg ( & mut self , offset : u32 , reg : RegUnit ) -> Result < ( ) , RegisterMappingError > {
255265 self . instructions . push ( (
256266 offset,
257267 CallFrameInstruction :: CfaRegister ( self . map_reg . map ( reg) ?) ,
258268 ) ) ;
269+ self . frame_register = Some ( reg) ;
259270 Ok ( ( ) )
260271 }
261272
262- fn pop_reg ( & mut self , offset : u32 , reg : RegUnit ) -> Result < ( ) , RegisterMappingError > {
263- self . cfa_offset -= self . word_size as i32 ;
264-
265- // Update the CFA if this is the restore of the frame pointer register or if a frame pointer isn't being used
266- match self . frame_register {
267- Some ( fp) => {
268- if reg == fp {
269- self . instructions . push ( (
270- offset,
271- CallFrameInstruction :: Cfa ( self . map_reg . rsp ( ) , self . cfa_offset ) ,
272- ) ) ;
273- }
274- }
275- None => {
276- self . instructions
277- . push ( ( offset, CallFrameInstruction :: CfaOffset ( self . cfa_offset ) ) ) ;
278-
279- // Pops in the epilogue are register restores, so record a "same value" for the register
280- // This isn't necessary when using a frame pointer as the CFA doesn't change for CSR restores
281- self . instructions . push ( (
282- offset,
283- CallFrameInstruction :: SameValue ( self . map_reg . map ( reg) ?) ,
284- ) ) ;
285- }
286- } ;
273+ fn restore_reg ( & mut self , offset : u32 , reg : RegUnit ) -> Result < ( ) , RegisterMappingError > {
274+ // Update the CFA if this is the restore of the frame pointer register.
275+ if Some ( reg) == self . frame_register {
276+ self . frame_register = None ;
277+ self . instructions . push ( (
278+ offset,
279+ CallFrameInstruction :: Cfa ( self . map_reg . rsp ( ) , self . sp_offset ) ,
280+ ) ) ;
281+ }
282+ // Pops in the epilogue are register restores, so record a "same value" for the register
283+ self . instructions . push ( (
284+ offset,
285+ CallFrameInstruction :: SameValue ( self . map_reg . map ( reg) ?) ,
286+ ) ) ;
287287
288288 Ok ( ( ) )
289289 }
290290
291291 fn remember_state ( & mut self , offset : u32 ) {
292- self . saved_state = Some ( self . cfa_offset ) ;
292+ self . saved_state = Some ( ( self . sp_offset , self . frame_register ) ) ;
293293
294294 self . instructions
295295 . push ( ( offset, CallFrameInstruction :: RememberState ) ) ;
296296 }
297297
298298 fn restore_state ( & mut self , offset : u32 ) {
299- let cfa_offset = self . saved_state . take ( ) . unwrap ( ) ;
300- self . cfa_offset = cfa_offset;
299+ let ( sp_offset, frame_register) = self . saved_state . take ( ) . unwrap ( ) ;
300+ self . sp_offset = sp_offset;
301+ self . frame_register = frame_register;
301302
302303 self . instructions
303304 . push ( ( offset, CallFrameInstruction :: RestoreState ) ) ;
0 commit comments