@@ -27,6 +27,8 @@ pub enum CompileError {
2727 /// We ran out of registers.
2828 /// In the long-run, when we have a proper register allocator, this won't be needed.
2929 OutOfRegisters ,
30+ /// We tried to retrieve the register for a local which doesn't have a register assigned to it.
31+ UnknownLocal ,
3032 /// Compiling this statement is not yet implemented.
3133 /// The string inside is a hint as to what kind of statement needs to be implemented.
3234 Unimplemented ( String ) ,
@@ -38,6 +40,7 @@ impl Display for CompileError {
3840 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
3941 match self {
4042 Self :: OutOfRegisters => write ! ( f, "Ran out of registers" ) ,
43+ Self :: UnknownLocal => write ! ( f, "Couldn't find assigned register for local." ) ,
4144 Self :: Unimplemented ( s) => write ! ( f, "Unimplemented compilation: {}" , s) ,
4245 Self :: UnknownSymbol ( s) => write ! ( f, "Unknown symbol: {}" , s) ,
4346 }
@@ -96,8 +99,9 @@ pub struct TraceCompiler {
9699 available_regs : Vec < u8 > ,
97100 /// Maps locals to their assigned registers.
98101 assigned_regs : HashMap < Local , u8 > ,
99- /// Stores the destination locals to which we copy RAX to after leaving an inlined call.
100- leaves : Vec < Option < Place > > ,
102+ /// Stores the destination local of the outer most function and moves its content into RAX at
103+ /// the end of the trace.
104+ rtn_var : Option < Place > ,
101105}
102106
103107impl TraceCompiler {
@@ -125,8 +129,26 @@ impl TraceCompiler {
125129 }
126130 }
127131
132+ /// Returns the currently assigned register for a given `Local`. Similar to `local_to_reg` but
133+ /// read-only, i.e. this function doesn't assign `Local`'s to registers.
134+ fn get_reg ( & self , local : & Local ) -> Result < u8 , CompileError > {
135+ match self . assigned_regs . get ( local) {
136+ Some ( u) => Ok ( * u) ,
137+ None => Err ( CompileError :: UnknownLocal ) ,
138+ }
139+ }
140+
128141 fn free_register ( & mut self , local : & Local ) {
129142 if let Some ( reg) = self . assigned_regs . remove ( local) {
143+ if local == & self . rtn_var . as_ref ( ) . unwrap ( ) . local {
144+ // We currently assume that we only trace a single function which leaves its return
145+ // value in RAX. Since we now inline a function's return variable this won't happen
146+ // automatically anymore. To keep things working, we thus copy the return value of
147+ // the most outer function into RAX at the end of the trace.
148+ dynasm ! ( self . asm
149+ ; mov rax, Rq ( reg)
150+ ) ;
151+ }
130152 self . available_regs . push ( reg) ;
131153 }
132154 }
@@ -217,19 +239,9 @@ impl TraceCompiler {
217239 } ,
218240 }
219241 }
220- // Remember the return destination.
221- self . leaves . push ( dest. as_ref ( ) . cloned ( ) ) ;
222- Ok ( ( ) )
223- }
224-
225- fn c_leave ( & mut self ) -> Result < ( ) , CompileError > {
226- let dest = self . leaves . pop ( ) ;
227- if let Some ( d) = dest {
228- if let Some ( d) = d {
229- // When we see a leave statement move whatever's left in RAX into the destination
230- // local.
231- self . mov_local_local ( d. local , Local ( 0 ) ) ?;
232- }
242+ if self . rtn_var . is_none ( ) {
243+ // Remember the return variable of the most outer function.
244+ self . rtn_var = dest. as_ref ( ) . cloned ( ) ;
233245 }
234246 Ok ( ( ) )
235247 }
@@ -313,7 +325,7 @@ impl TraceCompiler {
313325 } ;
314326 }
315327 Statement :: Enter ( op, args, dest, off) => self . c_enter ( op, args, dest, * off) ?,
316- Statement :: Leave => self . c_leave ( ) ? ,
328+ Statement :: Leave => { }
317329 Statement :: StorageLive ( _) => { }
318330 Statement :: StorageDead ( l) => self . free_register ( l) ,
319331 Statement :: Call ( target, args, dest) => self . c_call ( target, args, dest) ?,
@@ -388,7 +400,7 @@ impl TraceCompiler {
388400 // Use all the 64-bit registers we can (R15-R8, RDX, RCX).
389401 available_regs : vec ! [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 2 , 1 ] ,
390402 assigned_regs : HashMap :: new ( ) ,
391- leaves : Vec :: new ( ) ,
403+ rtn_var : None ,
392404 } ;
393405
394406 for i in 0 ..tt. len ( ) {
@@ -452,7 +464,7 @@ mod tests {
452464 asm : dynasmrt:: x64:: Assembler :: new ( ) . unwrap ( ) ,
453465 available_regs : vec ! [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 2 , 1 ] ,
454466 assigned_regs : HashMap :: new ( ) ,
455- leaves : Vec :: new ( ) ,
467+ rtn_var : None ,
456468 } ;
457469
458470 for _ in 0 ..32 {
@@ -470,7 +482,7 @@ mod tests {
470482 asm : dynasmrt:: x64:: Assembler :: new ( ) . unwrap ( ) ,
471483 available_regs : vec ! [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 2 , 1 ] ,
472484 assigned_regs : HashMap :: new ( ) ,
473- leaves : Vec :: new ( ) ,
485+ rtn_var : None ,
474486 } ;
475487
476488 let mut seen = HashSet :: new ( ) ;
0 commit comments