@@ -27,6 +27,8 @@ pub enum CompileError {
27
27
/// We ran out of registers.
28
28
/// In the long-run, when we have a proper register allocator, this won't be needed.
29
29
OutOfRegisters ,
30
+ /// We tried to retrieve the register for a local which doesn't have a register assigned to it.
31
+ UnknownLocal ,
30
32
/// Compiling this statement is not yet implemented.
31
33
/// The string inside is a hint as to what kind of statement needs to be implemented.
32
34
Unimplemented ( String ) ,
@@ -38,6 +40,7 @@ impl Display for CompileError {
38
40
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
39
41
match self {
40
42
Self :: OutOfRegisters => write ! ( f, "Ran out of registers" ) ,
43
+ Self :: UnknownLocal => write ! ( f, "Couldn't find assigned register for local." ) ,
41
44
Self :: Unimplemented ( s) => write ! ( f, "Unimplemented compilation: {}" , s) ,
42
45
Self :: UnknownSymbol ( s) => write ! ( f, "Unknown symbol: {}" , s) ,
43
46
}
@@ -96,8 +99,9 @@ pub struct TraceCompiler {
96
99
available_regs : Vec < u8 > ,
97
100
/// Maps locals to their assigned registers.
98
101
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 > ,
101
105
}
102
106
103
107
impl TraceCompiler {
@@ -125,8 +129,26 @@ impl TraceCompiler {
125
129
}
126
130
}
127
131
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
+
128
141
fn free_register ( & mut self , local : & Local ) {
129
142
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
+ }
130
152
self . available_regs . push ( reg) ;
131
153
}
132
154
}
@@ -217,19 +239,9 @@ impl TraceCompiler {
217
239
} ,
218
240
}
219
241
}
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 ( ) ;
233
245
}
234
246
Ok ( ( ) )
235
247
}
@@ -313,7 +325,7 @@ impl TraceCompiler {
313
325
} ;
314
326
}
315
327
Statement :: Enter ( op, args, dest, off) => self . c_enter ( op, args, dest, * off) ?,
316
- Statement :: Leave => self . c_leave ( ) ? ,
328
+ Statement :: Leave => { }
317
329
Statement :: StorageLive ( _) => { }
318
330
Statement :: StorageDead ( l) => self . free_register ( l) ,
319
331
Statement :: Call ( target, args, dest) => self . c_call ( target, args, dest) ?,
@@ -388,7 +400,7 @@ impl TraceCompiler {
388
400
// Use all the 64-bit registers we can (R15-R8, RDX, RCX).
389
401
available_regs : vec ! [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 2 , 1 ] ,
390
402
assigned_regs : HashMap :: new ( ) ,
391
- leaves : Vec :: new ( ) ,
403
+ rtn_var : None ,
392
404
} ;
393
405
394
406
for i in 0 ..tt. len ( ) {
@@ -452,7 +464,7 @@ mod tests {
452
464
asm : dynasmrt:: x64:: Assembler :: new ( ) . unwrap ( ) ,
453
465
available_regs : vec ! [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 2 , 1 ] ,
454
466
assigned_regs : HashMap :: new ( ) ,
455
- leaves : Vec :: new ( ) ,
467
+ rtn_var : None ,
456
468
} ;
457
469
458
470
for _ in 0 ..32 {
@@ -470,7 +482,7 @@ mod tests {
470
482
asm : dynasmrt:: x64:: Assembler :: new ( ) . unwrap ( ) ,
471
483
available_regs : vec ! [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 2 , 1 ] ,
472
484
assigned_regs : HashMap :: new ( ) ,
473
- leaves : Vec :: new ( ) ,
485
+ rtn_var : None ,
474
486
} ;
475
487
476
488
let mut seen = HashSet :: new ( ) ;
0 commit comments